1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us> 2# 3# Permission is hereby granted, free of charge, to any person 4# obtaining a copy of this software and associated documentation files 5# (the "Software"), to deal in the Software without restriction, 6# including without limitation the rights to use, copy, modify, merge, 7# publish, distribute, sublicense, and/or sell copies of the Software, 8# and to permit persons to whom the Software is furnished to do so, 9# subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be 12# included in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22init -1600 python: 23 24 config.keymap = dict( 25 26 # Bindings present almost everywhere, unless explicitly 27 # disabled. 28 rollback = [ 'K_PAGEUP', 'repeat_K_PAGEUP', 'K_AC_BACK', 'mousedown_4' ], 29 screenshot = [ 's', 'alt_K_s', 'alt_shift_K_s', 'noshift_K_s' ], 30 toggle_afm = [ ], 31 toggle_fullscreen = [ 'f', 'alt_K_RETURN', 'alt_K_KP_ENTER', 'K_F11', 'noshift_K_f' ], 32 game_menu = [ 'K_ESCAPE', 'K_MENU', 'K_PAUSE', 'mouseup_3' ], 33 hide_windows = [ 'mouseup_2', 'h', 'noshift_K_h' ], 34 launch_editor = [ 'E', 'shift_K_e' ], 35 dump_styles = [ ], 36 reload_game = [ 'R', 'alt_shift_K_r', 'shift_K_r' ], 37 inspector = [ 'I', 'shift_K_i' ], 38 full_inspector = [ 'alt_shift_K_i' ], 39 developer = [ 'shift_K_d', 'alt_shift_K_d' ], 40 quit = [ ], 41 iconify = [ ], 42 help = [ 'K_F1', 'meta_shift_/' ], 43 choose_renderer = [ 'G', 'alt_shift_K_g', 'shift_K_g' ], 44 progress_screen = [ 'alt_shift_K_p', 'meta_shift_K_p', 'K_F2' ], 45 accessibility = [ "K_a" ], 46 47 # Accessibility. 48 self_voicing = [ 'v', 'V', 'alt_K_v', 'K_v' ], 49 clipboard_voicing = [ 'C', 'alt_shift_K_c', 'shift_K_c' ], 50 debug_voicing = [ 'alt_shift_K_v', 'meta_shift_K_v' ], 51 52 # Say. 53 rollforward = [ 'mousedown_5', 'K_PAGEDOWN', 'repeat_K_PAGEDOWN' ], 54 dismiss = [ 'mouseup_1', 'K_RETURN', 'K_SPACE', 'K_KP_ENTER', 'K_SELECT' ], 55 dismiss_unfocused = [ ], 56 57 # Pause. 58 dismiss_hard_pause = [ ], 59 60 # Focus. 61 focus_left = [ 'K_LEFT', 'repeat_K_LEFT' ], 62 focus_right = [ 'K_RIGHT', 'repeat_K_RIGHT' ], 63 focus_up = [ 'K_UP', 'repeat_K_UP' ], 64 focus_down = [ 'K_DOWN', 'repeat_K_DOWN' ], 65 66 # Button. 67 button_ignore = [ 'mousedown_1' ], 68 button_select = [ 'mouseup_1', 'K_RETURN', 'K_KP_ENTER', 'K_SELECT' ], 69 button_alternate = [ 'mouseup_3' ], 70 button_alternate_ignore = [ 'mousedown_3' ], 71 72 # Input. 73 input_backspace = [ 'K_BACKSPACE', 'repeat_K_BACKSPACE' ], 74 input_enter = [ 'K_RETURN', 'K_KP_ENTER' ], 75 input_left = [ 'K_LEFT', 'repeat_K_LEFT' ], 76 input_right = [ 'K_RIGHT', 'repeat_K_RIGHT' ], 77 input_up = [ 'K_UP', 'repeat_K_UP' ], 78 input_down = [ 'K_DOWN', 'repeat_K_DOWN' ], 79 input_delete = [ 'K_DELETE', 'repeat_K_DELETE' ], 80 input_home = [ 'K_HOME', 'meta_K_LEFT' ], 81 input_end = [ 'K_END', 'meta_K_RIGHT' ], 82 input_copy = [ 'ctrl_noshift_K_INSERT', 'ctrl_noshift_K_c' ], 83 input_paste = [ 'shift_K_INSERT', 'ctrl_noshift_K_v' ], 84 input_jump_word_left = [ 'osctrl_K_LEFT' ], 85 input_jump_word_right = [ 'osctrl_K_RIGHT' ], 86 input_delete_word = [ 'osctrl_K_BACKSPACE' ], 87 input_delete_full = [ 'meta_K_BACKSPACE' ], 88 89 # Viewport. 90 viewport_leftarrow = [ 'K_LEFT', 'repeat_K_LEFT' ], 91 viewport_rightarrow = [ 'K_RIGHT', 'repeat_K_RIGHT' ], 92 viewport_uparrow = [ 'K_UP', 'repeat_K_UP' ], 93 viewport_downarrow = [ 'K_DOWN', 'repeat_K_DOWN' ], 94 viewport_wheelup = [ 'mousedown_4' ], 95 viewport_wheeldown = [ 'mousedown_5' ], 96 viewport_drag_start = [ 'mousedown_1' ], 97 viewport_drag_end = [ 'mouseup_1' ], 98 viewport_pageup = [ 'K_PAGEUP', 'repeat_K_PAGEUP' ], 99 viewport_pagedown = [ 'K_PAGEDOWN', 'repeat_K_PAGEDOWN' ], 100 101 # These keys control skipping. 102 skip = [ 'K_LCTRL', 'K_RCTRL' ], 103 stop_skipping = [ ], 104 toggle_skip = [ 'K_TAB' ], 105 fast_skip = [ '>', 'shift_K_PERIOD' ], 106 107 # Bar. 108 bar_activate = [ 'mousedown_1', 'K_RETURN', 'K_KP_ENTER', 'K_SELECT' ], 109 bar_deactivate = [ 'mouseup_1', 'K_RETURN', 'K_KP_ENTER', 'K_SELECT' ], 110 bar_left = [ 'K_LEFT', 'repeat_K_LEFT' ], 111 bar_right = [ 'K_RIGHT', 'repeat_K_RIGHT' ], 112 bar_up = [ 'K_UP', 'repeat_K_UP' ], 113 bar_down = [ 'K_DOWN', 'repeat_K_DOWN' ], 114 115 # Delete a save. 116 save_delete = [ 'K_DELETE' ], 117 118 # Draggable. 119 drag_activate = [ 'mousedown_1' ], 120 drag_deactivate = [ 'mouseup_1' ], 121 122 # Debug console. 123 console = [ 'shift_K_o', 'alt_shift_K_o' ], 124 console_older = [ 'K_UP', 'repeat_K_UP' ], 125 console_newer = [ 'K_DOWN', 'repeat_K_DOWN'], 126 127 # Director 128 director = [ 'noshift_K_d' ], 129 130 # Ignored (kept for backwards compatibility). 131 toggle_music = [ 'm' ], 132 viewport_up = [ 'mousedown_4' ], 133 viewport_down = [ 'mousedown_5' ], 134 135 # Profile commands. 136 performance = [ 'K_F3' ], 137 image_load_log = [ 'K_F4' ], 138 profile_once = [ 'K_F8' ], 139 memory_profile = [ 'K_F7' ], 140 141 ) 142 143 config.default_keymap = { k : list(v) for k, v in config.keymap.items() } 144 145 config.pad_bindings = { 146 "pad_leftshoulder_press" : [ "rollback", ], 147 "pad_lefttrigger_pos" : [ "rollback", ], 148 "pad_back_press" : [ "rollback", ], 149 150 "repeat_pad_leftshoulder_press" : [ "rollback", ], 151 "repeat_pad_lefttrigger_pos" : [ "rollback", ], 152 "repeat_pad_back_press" : [ "rollback", ], 153 154 "pad_guide_press" : [ "game_menu", ], 155 "pad_start_press" : [ "game_menu", ], 156 157 "pad_y_press" : [ "hide_windows", ], 158 159 "pad_rightshoulder_press" : [ "rollforward", ], 160 "repeat_pad_rightshoulder_press" : [ "rollforward", ], 161 162 "pad_righttrigger_pos" : [ "dismiss", "button_select", "bar_activate", "bar_deactivate" ], 163 "pad_a_press" : [ "dismiss", "button_select", "bar_activate", "bar_deactivate"], 164 "pad_b_press" : [ "button_alternate" ], 165 166 "pad_dpleft_press" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 167 "pad_leftx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 168 "pad_rightx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 169 170 "pad_dpright_press" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 171 "pad_leftx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 172 "pad_rightx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 173 174 "pad_dpup_press" : [ "focus_up", "bar_up", "viewport_uparrow" ], 175 "pad_lefty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ], 176 "pad_righty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ], 177 178 "pad_dpdown_press" : [ "focus_down", "bar_down", "viewport_downarrow" ], 179 "pad_lefty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ], 180 "pad_righty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ], 181 182 "repeat_pad_dpleft_press" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 183 "repeat_pad_leftx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 184 "repeat_pad_rightx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ], 185 186 "repeat_pad_dpright_press" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 187 "repeat_pad_leftx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 188 "repeat_pad_rightx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ], 189 190 "repeat_pad_dpup_press" : [ "focus_up", "bar_up", "viewport_uparrow" ], 191 "repeat_pad_lefty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ], 192 "repeat_pad_righty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ], 193 194 "repeat_pad_dpdown_press" : [ "focus_down", "bar_down", "viewport_downarrow" ], 195 "repeat_pad_lefty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ], 196 "repeat_pad_righty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ], 197 } 198 199 # Should we use the autoreload system? 200 config.autoreload = True 201 202init -1600 python: 203 204 # Are the windows currently hidden? 205 _windows_hidden = False 206 207 def _keymap_toggle_afm(): 208 if renpy.context()._menu: 209 return 210 211 renpy.run(Preference("auto-forward", "toggle")) 212 213 def _toggle_skipping(): 214 215 if not renpy.config.allow_skipping: 216 return 217 218 if not renpy.store._skipping: 219 return 220 221 if not config.skipping: 222 config.skipping = "slow" 223 else: 224 config.skipping = None 225 226 if renpy.context()._menu: 227 renpy.jump("_noisy_return") 228 else: 229 renpy.restart_interaction() 230 231 toggle_skipping = _toggle_skipping 232 233 def _keymap_toggle_skipping(): 234 if renpy.context()._menu: 235 return 236 237 _toggle_skipping() 238 239 config.help = None 240 241 config.help_screen = "help" 242 243 def _help(help=None): 244 245 if help is None: 246 help = config.help 247 248 if help is None: 249 if config.help_screen and renpy.has_screen(config.help_screen): 250 renpy.run(ShowMenu(config.help_screen)) 251 252 return 253 254 if renpy.has_label(help): 255 renpy.call_in_new_context(help) 256 return 257 258 _preferences.fullscreen = False 259 260 try: 261 import webbrowser 262 import os 263 264 file_path = os.path.join(config.basedir, help) 265 if not os.path.isfile(file_path): 266 return 267 268 webbrowser.open_new("file:///" + file_path) 269 except: 270 pass 271 272 import os 273 config.screenshot_pattern = os.environ.get("RENPY_SCREENSHOT_PATTERN", "screenshot%04d.png") 274 del os 275 276 # Called to make a screenshot happen. 277 def _screenshot(): 278 import os.path 279 import os 280 import __main__ 281 282 dest = config.renpy_base 283 284 if renpy.macapp: 285 dest = os.path.expanduser(b"~/Desktop") 286 287 pattern = renpy.store._screenshot_pattern or config.screenshot_pattern 288 289 # Try to pick a filename. 290 i = 1 291 while True: 292 fn = os.path.join(dest, pattern % i) 293 if not os.path.exists(fn): 294 break 295 i += 1 296 297 try: 298 dn = os.path.dirname(fn) 299 if not os.path.exists(dn): 300 os.makedirs(dn) 301 except: 302 pass 303 304 try: 305 if not renpy.screenshot(fn): 306 renpy.notify(__("Failed to save screenshot as %s.") % fn) 307 return 308 except: 309 import traceback 310 traceback.print_exc() 311 renpy.notify(__("Failed to save screenshot as %s.") % fn) 312 return 313 314 if config.screenshot_callback is not None: 315 config.screenshot_callback(fn) 316 317 def _screenshot_callback(fn): 318 renpy.notify(__("Saved screenshot as %s.") % fn) 319 320 config.screenshot_callback = _screenshot_callback 321 322 def _fast_skip(): 323 if not config.fast_skipping and not config.developer: 324 return 325 326 Skip(fast=True, confirm=not config.developer)() 327 328 def _reload_game(): 329 if not config.developer: 330 return 331 332 if not config.autoreload: 333 renpy.exports.reload_script() 334 return 335 336 if renpy.get_autoreload(): 337 renpy.set_autoreload(False) 338 renpy.restart_interaction() 339 else: 340 renpy.set_autoreload(True) 341 renpy.exports.reload_script() 342 343 def _launch_editor(): 344 if not config.developer: 345 return 346 347 filename, line = renpy.get_filename_line() 348 renpy.launch_editor([ filename ], line) 349 350 def _developer(): 351 352 if not config.developer: 353 return 354 355 renpy.show_screen("_developer") 356 renpy.restart_interaction() 357 358 def _profile_once(): 359 360 if not config.profile: 361 config.profile_time = 10.0 362 config.profile = True 363 364 renpy.display.interface.profile_once = True 365 366 def _memory_profile(): 367 import os 368 369 if not renpy.experimental: 370 return 371 372 renpy.memory.diff_memory() 373 374 def _progress_screen(): 375 if renpy.context_nesting_level(): 376 return 377 378 if renpy.get_screen("_progress"): 379 renpy.hide_screen("_progress") 380 else: 381 renpy.show_screen("_progress") 382 383 renpy.restart_interaction() 384 385screen _progress: 386 $ new = renpy.count_newly_seen_dialogue_blocks() 387 $ seen = renpy.count_seen_dialogue_blocks() 388 $ total = renpy.count_dialogue_blocks() 389 390 drag: 391 draggable True 392 focus_mask None 393 xpos 0 394 ypos 0 395 396 text "[new] [seen]/[total]": 397 size 14 398 color "#fff" 399 outlines [ (1, "#000", 0, 0) ] 400 alt "" 401 402init -1100 python: 403 404 # The default keymap. We might also want to put some of this into 405 # the launcher. 406 _default_keymap = renpy.Keymap( 407 rollback = renpy.rollback, 408 screenshot = _screenshot, 409 toggle_fullscreen = renpy.toggle_fullscreen, 410 toggle_afm = _keymap_toggle_afm, 411 toggle_skip = _keymap_toggle_skipping, 412 fast_skip = _fast_skip, 413 game_menu = _invoke_game_menu, 414 hide_windows = renpy.curried_call_in_new_context("_hide_windows"), 415 launch_editor = _launch_editor, 416 reload_game = _reload_game, 417 developer = _developer, 418 quit = renpy.quit_event, 419 iconify = renpy.iconify, 420 help = _help, 421 choose_renderer = renpy.curried_call_in_new_context("_choose_renderer"), 422 console = _console.enter, 423 profile_once = _profile_once, 424 memory_profile = _memory_profile, 425 self_voicing = Preference("self voicing", "toggle"), 426 clipboard_voicing = Preference("clipboard voicing", "toggle"), 427 debug_voicing = Preference("debug voicing", "toggle"), 428 progress_screen = _progress_screen, 429 director = director.Start(), 430 performance = ToggleScreen("_performance"), 431 accessibility = ToggleScreen("_accessibility"), 432 ) 433 434 config.underlay = [ _default_keymap ] 435 436init 1100 python hide: 437 438 import os 439 440 if "RENPY_DEFAULT_KEYMAP" in os.environ: 441 renpy.config.keymap = renpy.config.default_keymap 442 config.underlay.insert(0, _default_keymap) 443 444 445label _hide_windows: 446 447 if renpy.context()._menu: 448 return 449 450 if _windows_hidden: 451 return 452 453 if renpy.has_label("hide_windows"): 454 call hide_windows 455 if _return: 456 return 457 458 python: 459 _windows_hidden = True 460 voice_sustain() 461 ui.saybehavior(dismiss=['dismiss', 'hide_windows']) 462 ui.interact(suppress_overlay=True, suppress_window=True) 463 _windows_hidden = False 464 465 return 466 467 468label _save_reload_game: 469 python hide: 470 471 renpy.music.stop() 472 473 if renpy.can_load("_reload-1"): 474 renpy.utter_restart() 475 476 import time 477 renpy.session["_reload_time"] = time.time() 478 479 renpy.take_screenshot((config.thumbnail_width, config.thumbnail_height)) 480 481 ui.add(Solid((0, 0, 0, 255))) 482 ui.text("Saving game...", 483 size=32, xalign=0.5, yalign=0.5, color="#fff", style="_text") 484 485 ui.pausebehavior(0) 486 ui.interact(suppress_overlay=True, suppress_underlay=True) 487 488 renpy.save("_reload-1", "reload save game") 489 490 ui.add(Solid((0, 0, 0, 255))) 491 ui.text("Reloading script...", 492 size=32, xalign=0.5, yalign=0.5, color="#fff", style="_text") 493 494 ui.pausebehavior(0) 495 ui.interact(suppress_overlay=True, suppress_underlay=True) 496 497 renpy.utter_restart() 498 499label _load_reload_game: 500 501 if not renpy.can_load("_reload-1"): 502 return 503 504 python hide: 505 renpy.rename_save("_reload-1", "_reload-2") 506 507 ui.add(Solid((0, 0, 0, 255))) 508 ui.text("Reloading game...", 509 size=32, xalign=0.5, yalign=0.5, color="#fff", style="_text") 510 511 ui.pausebehavior(0) 512 ui.interact(suppress_underlay=True, suppress_overlay=True) 513 514 renpy.load("_reload-2") 515 516 return 517