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 22# This file contains functions that are exported to the script namespace as 23# the renpy namespace. (So renpy.say, renpy.pause, and so on.) 24 25from __future__ import division, absolute_import, with_statement, print_function, unicode_literals 26from renpy.compat import * 27 28import re 29import gc 30 31import renpy.display 32import renpy.audio 33 34from renpy.pyanalysis import const, pure, not_const 35 36 37def renpy_pure(fn): 38 """ 39 Marks renpy.`fn` as a pure function. 40 """ 41 42 name = fn 43 44 if not isinstance(name, basestring): 45 name = fn.__name__ 46 47 pure("renpy." + name) 48 49 return fn 50 51 52import pygame_sdl2 53 54from renpy.text.extras import ParameterizedText, filter_text_tags 55from renpy.text.font import register_sfont, register_mudgefont, register_bmfont 56from renpy.text.text import language_tailor, BASELINE 57from renpy.display.behavior import Keymap 58from renpy.display.behavior import run, run as run_action, run_unhovered, run_periodic 59from renpy.display.behavior import map_event, queue_event, clear_keymap_cache 60from renpy.display.behavior import is_selected, is_sensitive 61 62from renpy.display.minigame import Minigame 63from renpy.display.screen import define_screen, show_screen, hide_screen, use_screen, current_screen 64from renpy.display.screen import has_screen, get_screen, get_displayable, get_widget, ScreenProfile as profile_screen 65from renpy.display.screen import get_displayable_properties, get_widget_properties 66 67from renpy.display.focus import focus_coordinates 68from renpy.display.predict import screen as predict_screen 69 70from renpy.display.image import image_exists, image_exists as has_image, list_images 71from renpy.display.image import get_available_image_tags, get_available_image_attributes, check_image_attributes, get_ordered_image_attributes 72from renpy.display.image import get_registered_image 73 74from renpy.display.im import load_surface, load_image 75 76from renpy.curry import curry, partial 77from renpy.display.video import movie_start_fullscreen, movie_start_displayable, movie_stop 78 79from renpy.loadsave import load, save, list_saved_games, can_load, rename_save, copy_save, unlink_save, scan_saved_game 80from renpy.loadsave import list_slots, newest_slot, slot_mtime, slot_json, slot_screenshot, force_autosave 81 82from renpy.python import py_eval as eval 83from renpy.python import rng as random 84from renpy.atl import atl_warper 85from renpy.easy import predict, displayable, split_properties 86from renpy.parser import unelide_filename, get_parse_errors 87 88from renpy.translation import change_language, known_languages, translate_string 89from renpy.translation.generation import generic_filter as transform_text 90 91from renpy.persistent import register_persistent 92 93from renpy.character import show_display_say, predict_show_display_say, display_say 94 95import renpy.audio.sound as sound 96import renpy.audio.music as music 97 98from renpy.statements import register as register_statement 99from renpy.text.extras import check_text_tags 100 101from renpy.memory import profile_memory, diff_memory, profile_rollback 102 103from renpy.text.textsupport import TAG as TEXT_TAG, TEXT as TEXT_TEXT, PARAGRAPH as TEXT_PARAGRAPH, DISPLAYABLE as TEXT_DISPLAYABLE 104 105from renpy.execution import not_infinite_loop 106 107from renpy.sl2.slparser import CustomParser as register_sl_statement, register_sl_displayable 108 109from renpy.ast import eval_who 110 111from renpy.loader import add_python_directory 112 113from renpy.lint import try_compile, try_eval 114 115from renpy.gl2.gl2shadercache import register_shader 116from renpy.gl2.live2d import has_live2d 117 118renpy_pure("ParameterizedText") 119renpy_pure("Keymap") 120renpy_pure("has_screen") 121renpy_pure("image_exists") 122renpy_pure("curry") 123renpy_pure("partial") 124renpy_pure("unelide_filename") 125renpy_pure("known_languages") 126renpy_pure("check_text_tags") 127renpy_pure("filter_text_tags") 128 129import time 130import sys 131import threading 132import fnmatch 133 134 135def public_api(): 136 """ 137 :undocumented: 138 139 This does nothing, except to make warnings about unused imports go away. 140 """ 141 ParameterizedText, filter_text_tags 142 register_sfont, register_mudgefont, register_bmfont 143 Keymap 144 run, run_action, run_unhovered, run_periodic, map_event 145 Minigame 146 curry, partial 147 play 148 movie_start_fullscreen, movie_start_displayable, movie_stop 149 load, save, list_saved_games, can_load, rename_save, copy_save, unlink_save, scan_saved_game 150 list_slots, newest_slot, slot_mtime, slot_json, slot_screenshot, force_autosave 151 eval 152 random 153 atl_warper 154 show_display_say, predict_show_display_say, display_say 155 sound 156 music 157 time 158 define_screen, show_screen, hide_screen, use_screen, has_screen 159 current_screen, get_screen, get_widget, profile_screen, get_widget_properties 160 focus_coordinates 161 predict, predict_screen 162 displayable, split_properties 163 unelide_filename, get_parse_errors 164 change_language, known_languages, translate_string 165 transform_text 166 language_tailor 167 register_persistent 168 register_statement 169 check_text_tags 170 map_event, queue_event, clear_keymap_cache 171 const, pure, not_const 172 image_exists, has_image, list_images 173 get_available_image_tags, get_available_image_attributes, check_image_attributes, get_ordered_image_attributes 174 get_registered_image 175 load_image, load_surface 176 profile_memory, diff_memory, profile_rollback 177 TEXT_TAG 178 TEXT_TEXT 179 TEXT_PARAGRAPH 180 TEXT_DISPLAYABLE 181 not_infinite_loop 182 register_sl_statement, register_sl_displayable 183 eval_who 184 is_selected, is_sensitive 185 add_python_directory 186 try_compile, try_eval 187 register_shader, has_live2d 188 189 190del public_api 191 192# The number of bits in the architecture. 193if sys.maxsize > (2 << 32): 194 bits = 64 195else: 196 bits = 32 197 198 199def roll_forward_info(): 200 """ 201 :doc: rollback 202 203 When in rollback, returns the data that was supplied to :func:`renpy.checkpoint` 204 the last time this statement executed. Outside of rollback, returns None. 205 """ 206 207 if not renpy.game.context().rollback: 208 return None 209 210 return renpy.game.log.forward_info() 211 212 213def roll_forward_core(value=None): 214 """ 215 :undocumented: 216 217 To cause a roll_forward to occur, return the value of this function 218 from an event handler. 219 """ 220 221 if value is None: 222 value = roll_forward_info() 223 if value is None: 224 return 225 226 renpy.game.interface.suppress_transition = True 227 renpy.game.after_rollback = True 228 renpy.game.log.rolled_forward = True 229 230 return value 231 232 233def in_rollback(): 234 """ 235 :doc: rollback 236 237 Returns true if the game has been rolled back. 238 """ 239 240 return renpy.game.log.in_rollback() or renpy.game.after_rollback 241 242 243def can_rollback(): 244 """ 245 :doc: rollback 246 247 Returns true if we can rollback. 248 """ 249 250 if not renpy.config.rollback_enabled: 251 return False 252 253 return renpy.game.log.can_rollback() 254 255 256def in_fixed_rollback(): 257 """ 258 :doc: blockrollback 259 260 Returns true if rollback is currently occurring and the current 261 context is before an executed renpy.fix_rollback() statement. 262 """ 263 264 return renpy.game.log.in_fixed_rollback() 265 266 267def checkpoint(data=None, keep_rollback=None, hard=True): 268 """ 269 :doc: rollback 270 :args: (data=None) 271 272 Makes the current statement a checkpoint that the user can rollback to. Once 273 this function has been called, there should be no more interaction with the 274 user in the current statement. 275 276 This will also clear the current screenshot used by saved games. 277 278 `data` 279 This data is returned by :func:`renpy.roll_forward_info` when the 280 game is being rolled back. 281 282 `hard` 283 If true, this is a hard checkpoint that rollback will stop at. If false, 284 this is a soft checkpoint that will not stop rollback. 285 """ 286 287 if keep_rollback is None: 288 keep_rollback = renpy.config.keep_rollback_data 289 290 renpy.game.log.checkpoint(data, keep_rollback=keep_rollback, hard=renpy.store._rollback and hard) 291 292 if renpy.store._rollback and renpy.config.auto_clear_screenshot: 293 renpy.game.interface.clear_screenshot = True 294 295 296def block_rollback(purge=False): 297 """ 298 :doc: blockrollback 299 :args: () 300 301 Prevents the game from rolling back to before the current 302 statement. 303 """ 304 305 renpy.game.log.block(purge=purge) 306 307 308def suspend_rollback(flag): 309 """ 310 :doc: rollback 311 :args: (flag) 312 313 Rollback will skip sections of the game where rollback has been 314 suspended. 315 316 `flag`: 317 When `flag` is true, rollback is suspended. When false, 318 rollback is resumed. 319 """ 320 321 renpy.game.log.suspend_checkpointing(flag) 322 323 324def fix_rollback(): 325 """ 326 :doc: blockrollback 327 328 Prevents the user from changing decisions made before the current 329 statement. 330 """ 331 renpy.game.log.fix_rollback() 332 333 334def retain_after_load(): 335 """ 336 :doc: retain_after_load 337 338 Causes data modified between the current statement and the statement 339 containing the next checkpoint to be retained when a load occurs. 340 """ 341 342 renpy.game.log.retain_after_load() 343 344 345scene_lists = renpy.display.core.scene_lists 346 347 348def count_displayables_in_layer(layer): 349 """ 350 Returns how many displayables are in the supplied layer. 351 """ 352 353 sls = scene_lists() 354 355 return len(sls.layers[layer]) 356 357 358def image(name, d): 359 """ 360 :doc: se_images 361 362 Defines an image. This function is the Python equivalent of the 363 image statement. 364 365 `name` 366 The name of the image to display, a string. 367 368 `d` 369 The displayable to associate with that image name. 370 371 This function may only be run from inside an init block. It is an 372 error to run this function once the game has started. 373 """ 374 375 if d is None: 376 raise Exception("Images may not be declared to be None.") 377 378 if not renpy.game.context().init_phase: 379 raise Exception("Images may only be declared inside init blocks.") 380 381 if not isinstance(name, tuple): 382 name = tuple(name.split()) 383 384 d = renpy.easy.displayable(d) 385 renpy.display.image.register_image(name, d) 386 387 388def copy_images(old, new): 389 """ 390 :doc: image_func 391 392 Copies images beginning with one prefix to images beginning with 393 another. For example:: 394 395 renpy.copy_images("eileen", "eileen2") 396 397 will create an image beginning with "eileen2" for every image beginning 398 with "eileen". If "eileen happy" exists, "eileen2 happy" will be 399 created. 400 401 `old` 402 A space-separated string giving the components of the old image 403 name. 404 405 `new` 406 A space-separated string giving the components of the new image 407 name. 408 409 """ 410 411 if not isinstance(old, tuple): 412 old = tuple(old.split()) 413 414 if not isinstance(new, tuple): 415 new = tuple(new.split()) 416 417 lenold = len(old) 418 419 for k, v in renpy.display.image.images.items(): 420 if len(k) < lenold: 421 continue 422 423 if k[:lenold] == old: 424 renpy.display.image.register_image(new + k[lenold:], v) 425 426 427def default_layer(layer, tag, expression=False): 428 """ 429 :undocumented: 430 431 If layer is not None, returns it. Otherwise, interprets `tag` as a name 432 or tag, then looks up what the default layer for that tag is, and returns 433 the result. 434 """ 435 436 if layer is not None: 437 return layer 438 439 if expression: 440 return 'master' 441 442 if isinstance(tag, tuple): 443 tag = tag[0] 444 elif " " in tag: 445 tag = tag.split()[0] 446 447 return renpy.config.tag_layer.get(tag, renpy.config.default_tag_layer) 448 449 450def can_show(name, layer=None, tag=None): 451 """ 452 :doc: image_func 453 454 Determines if `name` can be used to show an image. This interprets `name` 455 as a tag and attributes. This is combined with the attributes of the 456 currently-showing image with `tag` on `layer` to try to determine a unique image 457 to show. If a unique image can be show, returns the name of that image as 458 a tuple. Otherwise, returns None. 459 460 `tag` 461 The image tag to get attributes from. If not given, defaults to the first 462 component of `name`. 463 464 `layer` 465 The layer to check. If None, uses the default layer for `tag`. 466 """ 467 468 if not isinstance(name, tuple): 469 name = tuple(name.split()) 470 471 if tag is None: 472 tag = name[0] 473 474 layer = default_layer(layer, None) 475 476 try: 477 return renpy.game.context().images.apply_attributes(layer, tag, name) 478 except: 479 return None 480 481 482def showing(name, layer=None): 483 """ 484 :doc: image_func 485 486 Returns true if an image with the same tag as `name` is showing on 487 `layer`. 488 489 `image` 490 May be a string giving the image name or a tuple giving each 491 component of the image name. It may also be a string giving 492 only the image tag. 493 494 `layer` 495 The layer to check. If None, uses the default layer for `tag`. 496 """ 497 498 if not isinstance(name, tuple): 499 name = tuple(name.split()) 500 501 layer = default_layer(layer, name) 502 503 return renpy.game.context().images.showing(layer, name) 504 505 506def get_showing_tags(layer='master', sort=False): 507 """ 508 :doc: image_func 509 510 Returns the set of image tags that are currently being shown on `layer`. If 511 sort is true, returns a list of the tags from back to front. 512 """ 513 514 if sort: 515 return scene_lists().get_sorted_tags(layer) 516 517 return renpy.game.context().images.get_showing_tags(layer) 518 519 520def get_hidden_tags(layer='master'): 521 """ 522 :doc: image_func 523 524 Returns the set of image tags on `layer` that are currently hidden, but 525 still have attribute information associated with them. 526 """ 527 528 return renpy.game.context().images.get_hidden_tags(layer) 529 530 531def get_attributes(tag, layer=None, if_hidden=None): 532 """ 533 :doc: image_func 534 535 Return a tuple giving the image attributes for the image `tag`. If 536 the image tag has not had any attributes associated since the last 537 time it was hidden, returns `if_hidden`. 538 539 `layer` 540 The layer to check. If None, uses the default layer for `tag`. 541 """ 542 543 layer = default_layer(layer, tag) 544 return renpy.game.context().images.get_attributes(layer, tag, if_hidden) 545 546 547def _find_image(layer, key, name, what): 548 """ 549 :undocumented: 550 551 Finds an image to show. 552 """ 553 554 if renpy.config.image_attributes: 555 556 new_what = renpy.game.context().images.apply_attributes(layer, key, name) 557 if new_what is not None: 558 what = new_what 559 name = (key,) + new_what[1:] 560 return name, what 561 562 f = renpy.config.adjust_attributes.get(what[0], None) or renpy.config.adjust_attributes.get(None, None) 563 if f is not None: 564 new_what = f(what) 565 name = (key,) + new_what[1:] 566 return name, new_what 567 568 return name, what 569 570 571def predict_show(name, layer=None, what=None, tag=None, at_list=[ ]): 572 """ 573 :undocumented: 574 575 Predicts a scene or show statement. 576 577 `name` 578 The name of the image to show, a string. 579 580 `layer` 581 The layer the image is being shown on. 582 583 `what` 584 What is being show - if given, overrides `name`. 585 586 `tag` 587 The tag of the thing being shown. 588 589 `at_list` 590 A list of transforms to apply to the displayable. 591 """ 592 593 key = tag or name[0] 594 595 layer = default_layer(layer, key) 596 597 if what is None: 598 what = name 599 elif isinstance(what, basestring): 600 what = tuple(what.split()) 601 602 if isinstance(what, renpy.display.core.Displayable): 603 base = img = what 604 605 else: 606 607 name, what = _find_image(layer, key, name, what) 608 base = img = renpy.display.image.ImageReference(what, style='image_placement') 609 610 if not base.find_target(): 611 return 612 613 for i in at_list: 614 if isinstance(i, renpy.display.motion.Transform): 615 img = i(child=img) 616 else: 617 img = i(img) 618 619 img._unique() 620 621 renpy.game.context().images.predict_show(layer, name, True) 622 renpy.display.predict.displayable(img) 623 624 625def set_tag_attributes(name, layer=None): 626 """ 627 :doc: side 628 629 This sets the attributes associated with an image tag when that image 630 tag is not showing. The main use of this would be to directly set the 631 attributes used by a side image. 632 633 For example:: 634 635 $ renpy.set_tag_attributes("lucy mad") 636 $ renpy.say(l, "I'm rather cross.") 637 638 and:: 639 640 l mad "I'm rather cross." 641 642 are equivalent. 643 """ 644 645 if not isinstance(name, tuple): 646 name = tuple(name.split()) 647 648 tag = name[0] 649 name = renpy.game.context().images.apply_attributes(layer, tag, name) 650 651 renpy.game.context().images.predict_show(layer, name, False) 652 653 654def show(name, at_list=[ ], layer=None, what=None, zorder=None, tag=None, behind=[ ], atl=None, transient=False, munge_name=True): 655 """ 656 :doc: se_images 657 :args: (name, at_list=[], layer='master', what=None, zorder=0, tag=None, behind=[]) 658 659 Shows an image on a layer. This is the programmatic equivalent of the show 660 statement. 661 662 `name` 663 The name of the image to show, a string. 664 665 `at_list` 666 A list of transforms that are applied to the image. 667 The equivalent of the ``at`` property. 668 669 `layer` 670 A string, giving the name of the layer on which the image will be shown. 671 The equivalent of the ``onlayer`` property. If None, uses the default 672 layer associated with the tag. 673 674 `what` 675 If not None, this is a displayable that will be shown in lieu of 676 looking on the image. (This is the equivalent of the show expression 677 statement.) When a `what` parameter is given, `name` can be used to 678 associate a tag with the image. 679 680 `zorder` 681 An integer, the equivalent of the ``zorder`` property. If None, the 682 zorder is preserved if it exists, and is otherwise set to 0. 683 684 `tag` 685 A string, used to specify the image tag of the shown image. The 686 equivalent of the ``as`` property. 687 688 `behind` 689 A list of strings, giving image tags that this image is shown behind. 690 The equivalent of the ``behind`` property. 691 """ 692 693 default_transform = renpy.config.default_transform 694 695 if renpy.game.context().init_phase: 696 raise Exception("Show may not run while in init phase.") 697 698 if not isinstance(name, tuple): 699 name = tuple(name.split()) 700 701 if zorder is None and not renpy.config.preserve_zorder: 702 zorder = 0 703 704 sls = scene_lists() 705 key = tag or name[0] 706 707 layer = default_layer(layer, key) 708 709 if renpy.config.sticky_positions: 710 if not at_list and key in sls.at_list[layer]: 711 at_list = sls.at_list[layer][key] 712 713 if not at_list: 714 tt = renpy.config.tag_transform.get(key, None) 715 if tt is not None: 716 if not isinstance(tt, list): 717 at_list = [ tt ] 718 else: 719 at_list = list(tt) 720 721 if what is None: 722 what = name 723 elif isinstance(what, basestring): 724 what = tuple(what.split()) 725 726 if isinstance(what, renpy.display.core.Displayable): 727 728 if renpy.config.wrap_shown_transforms and isinstance(what, renpy.display.motion.Transform): 729 base = img = renpy.display.image.ImageReference(what, style='image_placement') 730 731 # Semi-principled, but mimics pre-6.99.6 behavior - if `what` is 732 # already a transform, do not apply the default transform to it. 733 default_transform = None 734 735 else: 736 base = img = what 737 738 else: 739 name, what = _find_image(layer, key, name, what) 740 base = img = renpy.display.image.ImageReference(what, style='image_placement') 741 742 if not base.find_target() and renpy.config.missing_show: 743 result = renpy.config.missing_show(name, what, layer) 744 745 if isinstance(result, renpy.display.core.Displayable): 746 base = img = result 747 elif result: 748 return 749 750 for i in at_list: 751 if isinstance(i, renpy.display.motion.Transform): 752 img = i(child=img) 753 else: 754 img = i(img) 755 756 # Mark the newly created images unique. 757 img._unique() 758 759 # Update the list of images we have ever seen. 760 renpy.game.persistent._seen_images[name] = True # @UndefinedVariable 761 762 if tag and munge_name: 763 name = (tag,) + name[1:] 764 765 if renpy.config.missing_hide: 766 renpy.config.missing_hide(name, layer) 767 768 sls.add(layer, img, key, zorder, behind, at_list=at_list, name=name, atl=atl, default_transform=default_transform, transient=transient) 769 770 771def hide(name, layer=None): 772 """ 773 :doc: se_images 774 775 Hides an image from a layer. The Python equivalent of the hide statement. 776 777 `name` 778 The name of the image to hide. Only the image tag is used, and 779 any image with the tag is hidden (the precise name does not matter). 780 781 `layer` 782 The layer on which this function operates. If None, uses the default 783 layer associated with the tag. 784 """ 785 786 if renpy.game.context().init_phase: 787 raise Exception("Hide may not run while in init phase.") 788 789 if not isinstance(name, tuple): 790 name = tuple(name.split()) 791 792 sls = scene_lists() 793 key = name[0] 794 795 layer = default_layer(layer, key) 796 797 sls.remove(layer, key) 798 799 if renpy.config.missing_hide: 800 renpy.config.missing_hide(name, layer) 801 802 803def scene(layer='master'): 804 """ 805 :doc: se_images 806 807 Removes all displayables from `layer`. This is equivalent to the scene 808 statement, when the scene statement is not given an image to show. 809 810 A full scene statement is equivalent to a call to renpy.scene followed by a 811 call to :func:`renpy.show`. For example:: 812 813 scene bg beach 814 815 is equivalent to:: 816 817 $ renpy.scene() 818 $ renpy.show("bg beach") 819 """ 820 821 if layer is None: 822 layer = 'master' 823 824 if renpy.game.context().init_phase: 825 raise Exception("Scene may not run while in init phase.") 826 827 sls = scene_lists() 828 sls.clear(layer) 829 830 if renpy.config.missing_scene: 831 renpy.config.missing_scene(layer) 832 833 # End a transition that's affecting layer. 834 renpy.display.interface.ongoing_transition.pop(layer, None) 835 836 837def input(prompt, default='', allow=None, exclude='{}', length=None, with_none=None, pixel_width=None, screen="input", mask=None, **kwargs): # @ReservedAssignment 838 """ 839 :doc: input 840 841 Calling this function pops up a window asking the player to enter some 842 text. It returns the entered text. 843 844 `prompt` 845 A string giving a prompt to display to the player. 846 847 `default` 848 A string giving the initial text that will be edited by the player. 849 850 `allow` 851 If not None, a string giving a list of characters that will 852 be allowed in the text. 853 854 `exclude` 855 If not None, if a character is present in this string, it is not 856 allowed in the text. 857 858 `length` 859 If not None, this must be an integer giving the maximum length 860 of the input string. 861 862 `pixel_width` 863 If not None, the input is limited to being this many pixels wide, 864 in the font used by the input to display text. 865 866 `screen` 867 The name of the screen that takes input. If not given, the ``input`` 868 screen is used. 869 870 `mask` 871 If not None, a single-character string that replaces the input text that 872 is shown to the player, such as to conceal a password. 873 874 If :var:`config.disable_input` is True, this function only returns 875 `default`. 876 877 Keywords prefixed with ``show_`` have the prefix stripped and 878 are passed to the screen. 879 """ 880 881 if renpy.config.disable_input: 882 return default 883 884 renpy.exports.mode('input') 885 886 roll_forward = renpy.exports.roll_forward_info() 887 if not isinstance(roll_forward, basestring): 888 roll_forward = None 889 890 # use previous data in rollback 891 if roll_forward is not None: 892 default = roll_forward 893 894 fixed = in_fixed_rollback() 895 896 # put arguments with show_ prefix aside 897 show_properties, kwargs = renpy.easy.split_properties(kwargs, "show_", "") 898 899 if kwargs: 900 raise TypeError("renpy.input() got unexpected keyword argument(s): {}".format(", ".join(kwargs.keys()))) 901 902 if has_screen(screen): 903 widget_properties = { } 904 widget_properties["input"] = dict(default=default, length=length, allow=allow, exclude=exclude, editable=not fixed, pixel_width=pixel_width, mask=mask) 905 906 show_screen(screen, _transient=True, _widget_properties=widget_properties, prompt=prompt, **show_properties) 907 908 else: 909 910 if screen != "input": 911 raise Exception("The '{}' screen does not exist.".format(screen)) 912 913 renpy.ui.window(style='input_window') 914 renpy.ui.vbox() 915 916 renpy.ui.text(prompt, style='input_prompt') 917 918 inputwidget = renpy.ui.input(default, length=length, style='input_text', allow=allow, exclude=exclude) 919 920 # disable input in fixed rollback 921 if fixed: 922 inputwidget.disable() 923 924 renpy.ui.close() 925 926 renpy.exports.shown_window() 927 928 if renpy.config.autosave_on_input and not renpy.game.after_rollback: 929 renpy.loadsave.force_autosave(True) 930 931 # use normal "say" click behavior if input can't be changed 932 if fixed: 933 renpy.ui.saybehavior() 934 935 rv = renpy.ui.interact(mouse='prompt', type="input", roll_forward=roll_forward) 936 renpy.exports.checkpoint(rv) 937 938 if with_none is None: 939 with_none = renpy.config.implicit_with_none 940 941 if with_none: 942 renpy.game.interface.do_with(None, None) 943 944 return rv 945 946 947# The arguments and keyword arguments for the current menu call. 948menu_args = None 949menu_kwargs = None 950 951 952def get_menu_args(): 953 """ 954 :other: 955 956 Returns a tuple giving the arguments (as a tuple) and the keyword arguments 957 (as a dict) passed to the current menu statement. 958 """ 959 960 if menu_args is None: 961 return tuple(), dict() 962 963 return menu_args, menu_kwargs 964 965 966def menu(items, set_expr, args=None, kwargs=None, item_arguments=None): 967 """ 968 :undocumented: 969 970 Displays a menu, and returns to the user the value of the selected 971 choice. Also handles conditions and the menuset. 972 """ 973 974 global menu_args 975 global menu_kwargs 976 977 args = args or tuple() 978 kwargs = kwargs or dict() 979 980 nvl = kwargs.pop("nvl", False) 981 982 if renpy.config.menu_arguments_callback is not None: 983 args, kwargs = renpy.config.menu_arguments_callback(*args, **kwargs) 984 985 if renpy.config.old_substitutions: 986 987 def substitute(s): 988 return s % tag_quoting_dict 989 990 else: 991 992 def substitute(s): 993 return s 994 995 if item_arguments is None: 996 item_arguments = [ (tuple(), dict()) ] * len(items) 997 998 # Filter the list of items on the set_expr: 999 if set_expr: 1000 set = renpy.python.py_eval(set_expr) # @ReservedAssignment 1001 1002 new_items = [ ] 1003 new_item_arguments = [ ] 1004 1005 for i, ia in zip(items, item_arguments): 1006 if i[0] not in set: 1007 new_items.append(i) 1008 new_item_arguments.append(ia) 1009 1010 items = new_items 1011 item_arguments = new_item_arguments 1012 else: 1013 set = None # @ReservedAssignment 1014 1015 # Filter the list of items to only include ones for which the 1016 # condition is true. 1017 1018 if renpy.config.menu_actions: 1019 1020 location = renpy.game.context().current 1021 1022 new_items = [ ] 1023 1024 for (label, condition, value), (item_args, item_kwargs) in zip(items, item_arguments): 1025 label = substitute(label) 1026 condition = renpy.python.py_eval(condition) 1027 1028 if (not renpy.config.menu_include_disabled) and (not condition): 1029 continue 1030 1031 if value is not None: 1032 new_items.append((label, renpy.ui.ChoiceReturn(label, value, location, sensitive=condition, args=item_args, kwargs=item_kwargs))) 1033 else: 1034 new_items.append((label, None)) 1035 1036 else: 1037 1038 new_items = [ (substitute(label), value) 1039 for label, condition, value in items 1040 if renpy.python.py_eval(condition) ] 1041 1042 # Check to see if there's at least one choice in set of items: 1043 choices = [ value for label, value in new_items if value is not None ] 1044 1045 # If not, bail out. 1046 if not choices: 1047 return None 1048 1049 # Show the menu. 1050 try: 1051 old_menu_args = menu_args 1052 old_menu_kwargs = menu_kwargs 1053 1054 menu_args = args 1055 menu_kwargs = kwargs 1056 1057 if nvl: 1058 rv = renpy.store.nvl_menu(new_items) # @UndefinedVariable 1059 else: 1060 rv = renpy.store.menu(new_items) 1061 1062 finally: 1063 menu_args = old_menu_args 1064 menu_kwargs = old_menu_kwargs 1065 1066 # If we have a set, fill it in with the label of the chosen item. 1067 if set is not None and rv is not None: 1068 for label, condition, value in items: 1069 if value == rv: 1070 try: 1071 set.append(label) 1072 except AttributeError: 1073 set.add(label) 1074 1075 return rv 1076 1077 1078def choice_for_skipping(): 1079 """ 1080 :doc: other 1081 1082 Tells Ren'Py that a choice is coming up soon. This currently has 1083 two effects: 1084 1085 * If Ren'Py is skipping, and the Skip After Choices preferences is set 1086 to stop skipping, skipping is terminated. 1087 1088 * An auto-save is triggered. 1089 """ 1090 1091 if renpy.config.skipping and not renpy.game.preferences.skip_after_choices: 1092 renpy.config.skipping = None 1093 1094 if renpy.config.autosave_on_choice and not renpy.game.after_rollback: 1095 renpy.loadsave.force_autosave(True) 1096 1097 1098def predict_menu(): 1099 """ 1100 :undocumented: 1101 1102 Predicts widgets that are used by the menu. 1103 """ 1104 1105 # This only makes sense for non-NVL menus. But when we have 1106 # NVL menus, they're likely to have already been predicted. 1107 # 1108 # An item lets us load imagebuttons as necessary. 1109 1110 if not renpy.config.choice_screen_chosen: 1111 return 1112 1113 items = [ ("Menu Prediction", True, False) ] 1114 1115 predict_screen( 1116 "choice", 1117 items=items, 1118 ) 1119 1120 1121class MenuEntry(tuple): 1122 """ 1123 The object passed into the choice screen. 1124 """ 1125 1126 1127def display_menu(items, 1128 window_style='menu_window', 1129 interact=True, 1130 with_none=None, 1131 caption_style='menu_caption', 1132 choice_style='menu_choice', 1133 choice_chosen_style='menu_choice_chosen', 1134 choice_button_style='menu_choice_button', 1135 choice_chosen_button_style='menu_choice_chosen_button', 1136 scope={ }, 1137 widget_properties=None, 1138 screen="choice", 1139 type="menu", # @ReservedAssignment 1140 predict_only=False, 1141 **kwargs): 1142 """ 1143 :doc: se_menu 1144 :name: renpy.display_menu 1145 :args: (items, interact=True, screen="choice") 1146 1147 This displays a menu to the user. `items` should be a list of 2-item tuples. 1148 In each tuple, the first item is a textual label, and the second item is 1149 the value to be returned if that item is selected. If the value is None, 1150 the first item is used as a menu caption. 1151 1152 This function takes many arguments, of which only a few are documented. 1153 Except for `items`, all arguments should be given as keyword arguments. 1154 1155 `interact` 1156 If false, the menu is displayed, but no interaction is performed. 1157 1158 `screen` 1159 The name of the screen used to display the menu. 1160 1161 Note that most Ren'Py games do not use menu captions, but use narration 1162 instead. To display a menu using narration, write:: 1163 1164 $ narrator("Which direction would you like to go?", interact=False) 1165 $ result = renpy.display_menu([ ("East", "east"), ("West", "west") ]) 1166 1167 """ 1168 1169 menu_args, menu_kwargs = get_menu_args() 1170 screen = menu_kwargs.pop("screen", screen) 1171 with_none = menu_kwargs.pop("_with_none", with_none) 1172 mode = menu_kwargs.pop("_mode", type) 1173 1174 if interact: 1175 renpy.exports.mode(mode) 1176 choice_for_skipping() 1177 1178 choices = [ ] 1179 1180 for _, val in items: 1181 if isinstance(val, renpy.ui.ChoiceReturn): 1182 val = val.value 1183 1184 if val is None: 1185 continue 1186 1187 choices.append(val) 1188 1189 # Roll forward. 1190 roll_forward = renpy.exports.roll_forward_info() 1191 1192 if roll_forward not in choices: 1193 roll_forward = None 1194 1195 # Auto choosing. 1196 if renpy.config.auto_choice_delay: 1197 1198 renpy.ui.pausebehavior(renpy.config.auto_choice_delay, 1199 random.choice(choices)) 1200 1201 # The location 1202 location = renpy.game.context().current 1203 1204 # change behavior for fixed rollback 1205 if in_fixed_rollback() and renpy.config.fix_rollback_without_choice: 1206 renpy.ui.saybehavior() 1207 1208 scope = dict(scope) 1209 1210 scope.update(menu_kwargs) 1211 1212 # Show the menu. 1213 if has_screen(screen): 1214 1215 item_actions = [ ] 1216 1217 if widget_properties is None: 1218 props = { } 1219 else: 1220 props = widget_properties 1221 1222 for (label, value) in items: 1223 1224 if not label: 1225 value = None 1226 1227 if isinstance(value, renpy.ui.ChoiceReturn): 1228 action = value 1229 chosen = action.get_chosen() 1230 item_args = action.args 1231 item_kwargs = action.kwargs 1232 1233 elif value is not None: 1234 action = renpy.ui.ChoiceReturn(label, value, location) 1235 chosen = action.get_chosen() 1236 item_args = () 1237 item_kwargs = { } 1238 1239 else: 1240 action = None 1241 chosen = False 1242 item_args = () 1243 item_kwargs = { } 1244 1245 if renpy.config.choice_screen_chosen: 1246 me = MenuEntry((label, action, chosen)) 1247 else: 1248 me = MenuEntry((label, action)) 1249 1250 me.caption = label 1251 me.action = action 1252 me.chosen = chosen 1253 me.args = item_args 1254 me.kwargs = item_kwargs 1255 1256 item_actions.append(me) 1257 1258 show_screen( 1259 screen, 1260 items=item_actions, 1261 _widget_properties=props, 1262 _transient=True, 1263 _layer=renpy.config.choice_layer, 1264 *menu_args, 1265 **scope) 1266 1267 else: 1268 renpy.exports.shown_window() 1269 1270 renpy.ui.window(style=window_style, focus="menu") 1271 renpy.ui.menu(items, 1272 location=renpy.game.context().current, 1273 focus="choices", 1274 default=True, 1275 caption_style=caption_style, 1276 choice_style=choice_style, 1277 choice_chosen_style=choice_chosen_style, 1278 choice_button_style=choice_button_style, 1279 choice_chosen_button_style=choice_chosen_button_style, 1280 **kwargs) 1281 1282 if renpy.config.menu_showed_window: 1283 renpy.exports.shown_window() 1284 1285 # Log the chosen choice. 1286 for label, val in items: 1287 if val is not None: 1288 log("Choice: " + label) 1289 else: 1290 log(label) 1291 1292 log("") 1293 1294 if interact: 1295 1296 rv = renpy.ui.interact(mouse='menu', type=type, roll_forward=roll_forward) 1297 1298 for label, val in items: 1299 1300 if isinstance(val, renpy.ui.ChoiceReturn): 1301 val = val.value 1302 1303 if rv == val: 1304 log("Player chose: " + label) 1305 break 1306 else: 1307 log("No choice chosen.") 1308 1309 log("") 1310 1311 checkpoint(rv) 1312 1313 if with_none is None: 1314 with_none = renpy.config.implicit_with_none 1315 1316 if with_none: 1317 renpy.game.interface.do_with(None, None) 1318 1319 return rv 1320 1321 return None 1322 1323 1324class TagQuotingDict(object): 1325 1326 def __getitem__(self, key): 1327 1328 store = renpy.store.__dict__ 1329 1330 if key in store: 1331 rv = store[key] 1332 1333 if isinstance(rv, basestring): 1334 rv = rv.replace("{", "{{") 1335 1336 return rv 1337 else: 1338 if renpy.config.debug: 1339 raise Exception("During an interpolation, '%s' was not found as a variable." % key) 1340 return "<" + key + " unbound>" 1341 1342 1343tag_quoting_dict = TagQuotingDict() 1344 1345 1346def predict_say(who, what): 1347 """ 1348 :undocumented: 1349 1350 This is called to predict the results of a say command. 1351 """ 1352 1353 if who is None: 1354 who = renpy.store.narrator # E1101 @UndefinedVariable 1355 1356 if isinstance(who, basestring): 1357 return renpy.store.predict_say(who, what) 1358 1359 predict = getattr(who, 'predict', None) 1360 if predict: 1361 predict(what) 1362 1363 1364def scry_say(who, scry): 1365 """ 1366 :undocumented: 1367 1368 Called when scry is called on a say statement. Needs to set 1369 the interacts field. 1370 """ 1371 1372 try: 1373 scry.interacts = who.will_interact() 1374 except: 1375 scry.interacts = True 1376 1377 1378def say(who, what, *args, **kwargs): 1379 """ 1380 :doc: se_say 1381 1382 The equivalent of the say statement. 1383 1384 `who` 1385 Either the character that will say something, None for the narrator, 1386 or a string giving the character name. In the latter case, the 1387 :func:`say` is used to create the speaking character. 1388 1389 `what` 1390 A string giving the line to say. Percent-substitutions are performed 1391 in this string. 1392 1393 `interact` 1394 If true, Ren'Py waits for player input when displaying the dialogue. If 1395 false, Ren'Py shows the dialogue, but does not perform an interaction. 1396 (This is passed in as a keyword argument.) 1397 1398 This function is rarely necessary, as the following three lines are 1399 equivalent. :: 1400 1401 e "Hello, world." 1402 $ renpy.say(e, "Hello, world.") 1403 $ e("Hello, world.") 1404 """ 1405 1406 if renpy.config.old_substitutions: 1407 # Interpolate variables. 1408 what = what % tag_quoting_dict 1409 1410 if who is None: 1411 who = renpy.store.narrator # E1101 @UndefinedVariable 1412 1413 if renpy.config.say_arguments_callback: 1414 args, kwargs = renpy.config.say_arguments_callback(who, *args, **kwargs) 1415 1416 if isinstance(who, basestring): 1417 renpy.store.say(who, what, *args, **kwargs) 1418 else: 1419 who(what, *args, **kwargs) 1420 1421 1422def imagemap(ground, selected, hotspots, unselected=None, overlays=False, 1423 style='imagemap', mouse='imagemap', with_none=None, **properties): 1424 """ 1425 :undocumented: Use screens already. 1426 1427 Displays an imagemap. An image map consists of two images and a 1428 list of hotspots that are defined on that image. When the user 1429 clicks on a hotspot, the value associated with that hotspot is 1430 returned. 1431 1432 @param ground: The name of the file containing the ground 1433 image. The ground image is displayed for areas that are not part 1434 of any hotspots. 1435 1436 @param selected: The name of the file containing the selected 1437 image. This image is displayed in hotspots when the mouse is over 1438 them. 1439 1440 @param hotspots: A list of tuples defining the hotspots in this 1441 image map. Each tuple has the format (x0, y0, x1, y1, result). 1442 (x0, y0) gives the coordinates of the upper-left corner of the 1443 hotspot, (x1, y1) gives the lower-right corner, and result gives 1444 the value returned from this function if the mouse is clicked in 1445 the hotspot. 1446 1447 @param unselected: If provided, then it is the name of a file 1448 containing the image that's used to fill in hotspots that are not 1449 selected as part of any image. If not provided, the ground image 1450 is used instead. 1451 1452 @param overlays: If True, overlays are displayed when this imagemap 1453 is active. If False, the overlays are suppressed. 1454 1455 @param with_none: If True, performs a with None after the input. If None, 1456 takes the value from config.implicit_with_none. 1457 """ 1458 1459 renpy.exports.mode('imagemap') 1460 1461 renpy.ui.imagemap_compat(ground, selected, hotspots, unselected=unselected, 1462 style=style, **properties) 1463 1464 roll_forward = renpy.exports.roll_forward_info() 1465 if roll_forward not in [ result for _x0, _y0, _x1, _y1, result in hotspots]: 1466 roll_forward = None 1467 1468 if in_fixed_rollback() and renpy.config.fix_rollback_without_choice: 1469 renpy.ui.saybehavior() 1470 1471 rv = renpy.ui.interact(suppress_overlay=(not overlays), 1472 type='imagemap', 1473 mouse=mouse, 1474 roll_forward=roll_forward) 1475 1476 renpy.exports.checkpoint(rv) 1477 1478 if with_none is None: 1479 with_none = renpy.config.implicit_with_none 1480 1481 if with_none: 1482 renpy.game.interface.do_with(None, None) 1483 1484 return rv 1485 1486 1487def pause(delay=None, music=None, with_none=None, hard=False, checkpoint=None): 1488 """ 1489 :doc: other 1490 :args: (delay=None, hard=False) 1491 1492 Causes Ren'Py to pause. Returns true if the user clicked to end the pause, 1493 or false if the pause timed out or was skipped. 1494 1495 `delay` 1496 If given, the number of seconds Ren'Py should pause for. 1497 1498 `hard` 1499 This must be given as a keyword argument. When True, Ren'Py may prevent 1500 the user from clicking to interrupt the pause. If the player enables 1501 skipping, the hard pause will be skipped. There may be other circumstances 1502 where the hard pause ends early or prevents Ren'Py from operating properly, 1503 these will not be treated as bugs. 1504 1505 In general, using hard pauses is rude. When the user clicks to advance 1506 the game, it's an explicit request - the user wishes the game to advance. 1507 To override that request is to assume you understand what the player 1508 wants more than the player does. 1509 1510 Calling renpy.pause guarantees that whatever is on the screen will be 1511 displayed for at least one frame, and hence has been shown to the 1512 player. 1513 1514 tl;dr - Don't use renpy.pause with hard=True. 1515 """ 1516 1517 if renpy.config.skipping == "fast": 1518 return False 1519 1520 if checkpoint is None: 1521 if delay is not None: 1522 checkpoint = False 1523 else: 1524 checkpoint = True 1525 1526 roll_forward = renpy.exports.roll_forward_info() 1527 1528 if roll_forward not in [ True, False ]: 1529 roll_forward = None 1530 1531 if (delay is not None) and renpy.game.after_rollback and not renpy.config.pause_after_rollback: 1532 1533 rv = roll_forward 1534 if rv is None: 1535 rv = False 1536 1537 if checkpoint: 1538 renpy.exports.checkpoint(rv, keep_rollback=True, hard=False) 1539 1540 return rv 1541 1542 renpy.exports.mode('pause') 1543 1544 if music is not None: 1545 newdelay = renpy.audio.music.get_delay(music) 1546 1547 if newdelay is not None: 1548 delay = newdelay 1549 1550 if (delay is not None) and renpy.game.after_rollback and roll_forward is None: 1551 delay = 0 1552 1553 if delay is None: 1554 afm = " " 1555 else: 1556 afm = None 1557 1558 if hard or not renpy.store._dismiss_pause: 1559 renpy.ui.saybehavior(afm=afm, dismiss='dismiss_hard_pause', dismiss_unfocused=[]) 1560 else: 1561 renpy.ui.saybehavior(afm=afm) 1562 1563 rv = renpy.ui.interact(mouse='pause', type='pause', roll_forward=roll_forward, pause=delay) 1564 1565 if checkpoint: 1566 renpy.exports.checkpoint(rv, keep_rollback=True, hard=renpy.config.pause_after_rollback or (delay is None)) 1567 1568 if with_none is None: 1569 with_none = renpy.config.implicit_with_none 1570 1571 if with_none: 1572 renpy.game.interface.do_with(None, None) 1573 1574 return rv 1575 1576 1577def movie_cutscene(filename, delay=None, loops=0, stop_music=True): 1578 """ 1579 :doc: movie_cutscene 1580 1581 This displays a movie cutscene for the specified number of 1582 seconds. The user can click to interrupt the cutscene. 1583 Overlays and Underlays are disabled for the duration of the cutscene. 1584 1585 `filename` 1586 The name of a file containing any movie playable by Ren'Py. 1587 1588 `delay` 1589 The number of seconds to wait before ending the cutscene. 1590 Normally the length of the movie, in seconds. If None, then the 1591 delay is computed from the number of loops (that is, loops + 1) * 1592 the length of the movie. If -1, we wait until the user clicks. 1593 1594 `loops` 1595 The number of extra loops to show, -1 to loop forever. 1596 1597 Returns True if the movie was terminated by the user, or False if the 1598 given delay elapsed uninterrupted. 1599 """ 1600 1601 renpy.exports.mode('movie') 1602 1603 if stop_music: 1604 renpy.audio.audio.set_force_stop("music", True) 1605 1606 movie_start_fullscreen(filename, loops=loops) 1607 1608 renpy.ui.saybehavior() 1609 1610 if delay is None or delay < 0: 1611 renpy.ui.soundstopbehavior("movie") 1612 else: 1613 renpy.ui.pausebehavior(delay, False) 1614 1615 if renpy.game.log.forward: 1616 roll_forward = True 1617 else: 1618 roll_forward = None 1619 1620 rv = renpy.ui.interact(suppress_overlay=True, 1621 roll_forward=roll_forward) 1622 1623 # We don't want to put a checkpoint here, as we can't roll back while 1624 # playing a cutscene. 1625 1626 movie_stop() 1627 1628 if stop_music: 1629 renpy.audio.audio.set_force_stop("music", False) 1630 1631 return rv 1632 1633 1634def with_statement(trans, always=False, paired=None, clear=True): 1635 """ 1636 :doc: se_with 1637 :name: renpy.with_statement 1638 :args: (trans, always=False) 1639 1640 Causes a transition to occur. This is the Python equivalent of the 1641 with statement. 1642 1643 `trans` 1644 The transition. 1645 1646 `always` 1647 If True, the transition will always occur, even if the user has 1648 disabled transitions. 1649 1650 This function returns true if the user chose to interrupt the transition, 1651 and false otherwise. 1652 """ 1653 1654 if renpy.game.context().init_phase: 1655 raise Exception("With statements may not run while in init phase.") 1656 1657 if renpy.config.skipping: 1658 trans = None 1659 1660 if not (renpy.game.preferences.transitions or always): 1661 trans = None 1662 1663 renpy.exports.mode('with') 1664 1665 if isinstance(paired, dict): 1666 paired = paired.get(None, None) 1667 1668 if (trans is None) and (paired is None): 1669 return 1670 1671 if isinstance(trans, dict): 1672 1673 for k, v in trans.items(): 1674 if k is None: 1675 continue 1676 1677 renpy.exports.transition(v, layer=k) 1678 1679 if None not in trans: 1680 return 1681 1682 trans = trans[None] 1683 1684 return renpy.game.interface.do_with(trans, paired, clear=clear) 1685 1686 1687globals()["with"] = with_statement 1688 1689 1690def rollback(force=False, checkpoints=1, defer=False, greedy=True, label=None, abnormal=True, current_label=None): 1691 """ 1692 :doc: rollback 1693 :args: (force=False, checkpoints=1, defer=False, greedy=True, label=None, abnormal=True) 1694 1695 Rolls the state of the game back to the last checkpoint. 1696 1697 `force` 1698 If true, the rollback will occur in all circumstances. Otherwise, 1699 the rollback will only occur if rollback is enabled in the store, 1700 context, and config. 1701 1702 `checkpoints` 1703 Ren'Py will roll back through this many calls to renpy.checkpoint. It 1704 will roll back as far as it can, subject to this condition. 1705 1706 `defer` 1707 If true, the call will be deferred until control returns to the main 1708 context. 1709 1710 `greedy` 1711 If true, rollback will finish just after the previous checkpoint. 1712 If false, rollback finish just before the current checkpoint. 1713 1714 `label` 1715 If not None, a label that is called when rollback completes. 1716 1717 `abnormal` 1718 If true, the default, script executed after the transition is run in 1719 an abnormal mode that skips transitions that would have otherwise 1720 occured. Abnormal mode ends when an interaction begins. 1721 """ 1722 1723 if defer and len(renpy.game.contexts) > 1: 1724 renpy.game.contexts[0].defer_rollback = (force, checkpoints) 1725 return 1726 1727 if not force: 1728 1729 if not renpy.store._rollback: 1730 return 1731 1732 if not renpy.game.context().rollback: 1733 return 1734 1735 if not renpy.config.rollback_enabled: 1736 return 1737 1738 renpy.config.skipping = None 1739 renpy.game.log.complete() 1740 renpy.game.log.rollback(checkpoints, greedy=greedy, label=label, force=(force is True), abnormal=abnormal, current_label=current_label) 1741 1742 1743def toggle_fullscreen(): 1744 """ 1745 :undocumented: 1746 Toggles the fullscreen mode. 1747 """ 1748 1749 renpy.game.preferences.fullscreen = not renpy.game.preferences.fullscreen 1750 1751 1752def toggle_music(): 1753 """ 1754 :undocumented: 1755 Does nothing. 1756 """ 1757 1758 1759@renpy_pure 1760def has_label(name): 1761 """ 1762 :doc: label 1763 1764 Returns true if `name` is a valid label the program, or false otherwise. 1765 1766 `name` 1767 Should be a string to check for the existence of a label. It can 1768 also be an opaque tuple giving the name of a non-label statement. 1769 """ 1770 1771 return renpy.game.script.has_label(name) 1772 1773 1774@renpy_pure 1775def get_all_labels(): 1776 """ 1777 :doc: label 1778 1779 Returns the set of all labels defined in the program, including labels 1780 defined for internal use in the libraries. 1781 """ 1782 rv = [ ] 1783 1784 for i in renpy.game.script.namemap.keys(): 1785 if isinstance(i, basestring): 1786 rv.append(i) 1787 1788 return renpy.python.RevertableSet(rv) 1789 1790 1791def take_screenshot(scale=None, background=False): 1792 """ 1793 :doc: loadsave 1794 1795 Causes a screenshot to be taken. This screenshot will be saved as part of 1796 a save game. 1797 """ 1798 1799 if scale is None: 1800 scale = (renpy.config.thumbnail_width, renpy.config.thumbnail_height) 1801 1802 renpy.game.interface.take_screenshot(scale, background=background) 1803 1804 1805def full_restart(transition=False, label="_invoke_main_menu", target="_main_menu", save=False): 1806 """ 1807 :doc: other 1808 1809 Causes Ren'Py to restart, returning the user to the main menu. 1810 1811 `transition` 1812 If given, the transition to run, or None to not run a transition. 1813 False uses :var:`config.end_game_transition`. 1814 1815 `save` 1816 If true, the game is saved in :var:`_quit_slot` before Ren'Py 1817 restarts and returns the user to the main menu. 1818 """ 1819 1820 if save and (renpy.store._quit_slot is not None): 1821 renpy.loadsave.save(renpy.store._quit_slot, getattr(renpy.store, "save_name", "")) 1822 1823 if transition is False: 1824 transition = renpy.config.end_game_transition 1825 1826 raise renpy.game.FullRestartException((transition, label, target)) 1827 1828 1829def utter_restart(keep_renderer=False): 1830 """ 1831 :undocumented: Used in the implementation of shift+R. 1832 1833 Causes an utter restart of Ren'Py. This reloads the script and 1834 re-runs initialization. 1835 """ 1836 1837 renpy.session["_keep_renderer"] = keep_renderer 1838 1839 raise renpy.game.UtterRestartException() 1840 1841 1842def reload_script(): 1843 """ 1844 :doc: other 1845 1846 Causes Ren'Py to save the game, reload the script, and then load the 1847 save. 1848 """ 1849 1850 # Avoid reloading in a replay. 1851 if renpy.store._in_replay: 1852 return 1853 1854 s = get_screen("menu") 1855 1856 session.pop("_reload_screen", None) 1857 session.pop("_reload_screen_args", None) 1858 session.pop("_reload_screen_kwargs", None) 1859 1860 if not renpy.store.main_menu: 1861 1862 if s is not None: 1863 session["_reload_screen"] = s.screen_name[0] 1864 session["_reload_screen_args"] = s.scope.get("_args", ()) 1865 session["_reload_screen_kwargs"] = s.scope.get("_kwargs", { }) 1866 1867 renpy.game.call_in_new_context("_save_reload_game") 1868 1869 else: 1870 1871 if s is not None: 1872 session["_main_menu_screen"] = s.screen_name[0] 1873 session["_main_menu_screen_args"] = s.scope.get("_args", ()) 1874 session["_main_menu_screen_kwargs"] = s.scope.get("_kwargs", { }) 1875 1876 utter_restart() 1877 1878 1879def quit(relaunch=False, status=0, save=False): # @ReservedAssignment 1880 """ 1881 :doc: other 1882 1883 This causes Ren'Py to exit entirely. 1884 1885 `relaunch` 1886 If true, Ren'Py will run a second copy of itself before quitting. 1887 1888 `status` 1889 The status code Ren'Py will return to the operating system. 1890 Generally, 0 is success, and positive integers are failure. 1891 1892 `save` 1893 If true, the game is saved in :var:`_quit_slot` before Ren'Py 1894 terminates. 1895 """ 1896 1897 if save and (renpy.store._quit_slot is not None): 1898 renpy.loadsave.save(renpy.store._quit_slot, getattr(renpy.store, "save_name", "")) 1899 1900 if has_label("quit"): 1901 call_in_new_context("quit") 1902 1903 raise renpy.game.QuitException(relaunch=relaunch, status=status) 1904 1905 1906def jump(label): 1907 """ 1908 :doc: se_jump 1909 1910 Causes the current statement to end, and control to jump to the given 1911 label. 1912 """ 1913 1914 raise renpy.game.JumpException(label) 1915 1916 1917def jump_out_of_context(label): 1918 """ 1919 :doc: label 1920 1921 Causes control to leave the current context, and then to be 1922 transferred in the parent context to the given label. 1923 """ 1924 1925 raise renpy.game.JumpOutException(label) 1926 1927 1928def call(label, *args, **kwargs): 1929 """ 1930 :doc: se_call 1931 1932 Causes the current Ren'Py statement to terminate, and a jump to a 1933 `label` to occur. When the jump returns, control will be passed 1934 to the statement following the current statement. 1935 1936 `from_current` 1937 If true, control will return to the current statement, rather than 1938 the statement following the current statement. (This will lead to 1939 the current statement being run twice. This must be passed as a 1940 keyword argument.) 1941 """ 1942 1943 from_current = kwargs.pop("from_current", False) 1944 raise renpy.game.CallException(label, args, kwargs, from_current=from_current) 1945 1946 1947def return_statement(value=None): 1948 """ 1949 :doc: se_call 1950 1951 Causes Ren'Py to return from the current Ren'Py-level call. 1952 """ 1953 1954 renpy.store._return = value 1955 jump("_renpy_return") 1956 1957 1958def screenshot(filename): 1959 """ 1960 :doc: other 1961 1962 Saves a screenshot in `filename`. 1963 1964 Returns True if the screenshot was saved successfully, False if saving 1965 failed for some reason. 1966 1967 The :var:`config.screenshot_pattern` and :var:`_screenshot_pattern` 1968 variables control the file the screenshot is saved in. 1969 """ 1970 1971 return renpy.game.interface.save_screenshot(filename) 1972 1973 1974def screenshot_to_bytes(size): 1975 """ 1976 :doc: other 1977 1978 Returns a screenshot as a bytes object, that can be passed to im.Data(). 1979 The bytes will be a png-format image, such that:: 1980 1981 $ data = renpy.screenshot_to_bytes((640, 360)) 1982 show expression im.Data(data, "screenshot.png"): 1983 align (0, 0) 1984 1985 Will show the image. The bytes objects returned can be stored in save 1986 files and persistent data. However, these may be large, and care should 1987 be taken to not include too many. 1988 1989 `size` 1990 The size the screenshot will be resized to. If None, the screenshot 1991 will be resized, and hence will be the size of the player's window, 1992 without any letterbars. 1993 1994 This function may be slow, and so it's intended for save-like screenshots, 1995 and not realtime effects. 1996 """ 1997 1998 return renpy.game.interface.screenshot_to_bytes(size) 1999 2000 2001@renpy_pure 2002def version(tuple=False): # @ReservedAssignment 2003 """ 2004 :doc: renpy_version 2005 2006 If `tuple` is false, returns a string containing "Ren'Py ", followed by 2007 the current version of Ren'Py. 2008 2009 If `tuple` is true, returns a tuple giving each component of the 2010 version as an integer. 2011 """ 2012 2013 if tuple: 2014 return renpy.version_tuple 2015 2016 return renpy.version 2017 2018 2019version_string = renpy.version 2020version_only = renpy.version_only 2021version_name = renpy.version_name 2022version_tuple = renpy.version_tuple 2023license = "" # @ReservedAssignment 2024 2025try: 2026 import platform as _platform 2027 platform = "-".join(_platform.platform().split("-")[:2]) 2028except: 2029 if renpy.android: 2030 platform = "Android" 2031 elif renpy.ios: 2032 platform = "iOS" 2033 else: 2034 platform = "Unknown" 2035 2036 2037def transition(trans, layer=None, always=False, force=False): 2038 """ 2039 :doc: other 2040 :args: (trans, layer=None, always=False) 2041 2042 Sets the transition that will be used during the next interaction. 2043 2044 `layer` 2045 The layer the transition applies to. If None, the transition 2046 applies to the entire scene. 2047 2048 `always` 2049 If false, this respects the transition preference. If true, the 2050 transition is always run. 2051 """ 2052 2053 if isinstance(trans, dict): 2054 for layer, t in trans.items(): 2055 transition(t, layer=layer, always=always, force=force) 2056 return 2057 2058 if (not always) and not renpy.game.preferences.transitions: 2059 trans = None 2060 2061 renpy.game.interface.set_transition(trans, layer, force=force) 2062 2063 2064def get_transition(layer=None): 2065 """ 2066 :doc: other 2067 2068 Gets the transition for `layer`, or the entire scene if 2069 `layer` is None. This returns the transition that is queued up 2070 to run during the next interaction, or None if no such 2071 transition exists. 2072 """ 2073 2074 return renpy.game.interface.transition.get(layer, None) 2075 2076 2077def clear_game_runtime(): 2078 """ 2079 :doc: other 2080 2081 Resets the game runtime counter. 2082 """ 2083 2084 renpy.game.contexts[0].runtime = 0 2085 2086 2087def get_game_runtime(): 2088 """ 2089 :doc: other 2090 2091 Returns the game runtime counter. 2092 2093 The game runtime counter counts the number of seconds that have 2094 elapsed while waiting for user input in the top-level context. 2095 (It does not count time spent in the main or game menus.) 2096 """ 2097 2098 return renpy.game.contexts[0].runtime 2099 2100 2101@renpy_pure 2102def loadable(filename): 2103 """ 2104 :doc: file 2105 2106 Returns True if the given filename is loadable, meaning that it 2107 can be loaded from the disk or from inside an archive. Returns 2108 False if this is not the case. 2109 """ 2110 2111 return renpy.loader.loadable(filename) 2112 2113 2114@renpy_pure 2115def exists(filename): 2116 """ 2117 :doc: file_rare 2118 2119 Returns true if the given filename can be found in the 2120 searchpath. This only works if a physical file exists on disk. It 2121 won't find the file if it's inside of an archive. 2122 2123 You almost certainly want to use :func:`renpy.loadable` in preference 2124 to this function. 2125 """ 2126 2127 try: 2128 renpy.loader.transfn(filename) 2129 return True 2130 except: 2131 return False 2132 2133 2134def restart_interaction(): 2135 """ 2136 :doc: other 2137 2138 Restarts the current interaction. Among other things, this displays 2139 images added to the scene, re-evaluates screens, and starts any 2140 queued transitions. 2141 2142 This only does anything when called from within an interaction (for 2143 example, from an action). Outside an interaction, this function has 2144 no effect. 2145 """ 2146 2147 try: 2148 renpy.game.interface.restart_interaction = True 2149 except: 2150 pass 2151 2152 2153def context(): 2154 """ 2155 :doc: context 2156 2157 Returns an object that is unique to the current context. The object 2158 is copied when entering a new context, but changes to the copy do 2159 not change the original. 2160 2161 The object is saved and participates in rollback. 2162 """ 2163 2164 return renpy.game.context().info 2165 2166 2167def context_nesting_level(): 2168 """ 2169 :doc: context 2170 2171 Returns the nesting level of the current context. This is 0 for the 2172 outermost context (the context that is saved, loaded, and rolled-back), 2173 and is non-zero in other contexts, such as menu and replay contexts. 2174 """ 2175 2176 return len(renpy.game.contexts) - 1 2177 2178 2179def music_start(filename, loops=True, fadeout=None, fadein=0): 2180 """ 2181 Deprecated music start function, retained for compatibility. Use 2182 renpy.music.play() or .queue() instead. 2183 """ 2184 2185 renpy.audio.music.play(filename, loop=loops, fadeout=fadeout, fadein=fadein) 2186 2187 2188def music_stop(fadeout=None): 2189 """ 2190 Deprecated music start function, retained for compatibility. Use 2191 renpy.music.play() or .queue() instead. 2192 """ 2193 2194 renpy.audio.music.stop(fadeout=fadeout) 2195 2196 2197def get_filename_line(): 2198 """ 2199 :doc: debug 2200 2201 Returns a pair giving the filename and line number of the current 2202 statement. 2203 """ 2204 2205 n = renpy.game.script.namemap.get(renpy.game.context().current, None) 2206 2207 if n is None: 2208 return "unknown", 0 2209 else: 2210 return n.filename, n.linenumber 2211 2212 2213# A file that log logs to. 2214logfile = None 2215 2216 2217def log(msg): 2218 """ 2219 :doc: debug 2220 2221 If :var:`config.log` is not set, this does nothing. Otherwise, it opens 2222 the logfile (if not already open), formats the message to :var:`config.log_width` 2223 columns, and prints it to the logfile. 2224 """ 2225 2226 global logfile 2227 2228 if not renpy.config.log: 2229 return 2230 2231 if msg is None: 2232 return 2233 2234 try: 2235 msg = unicode(msg) 2236 except: 2237 pass 2238 2239 try: 2240 2241 if not logfile: 2242 import os 2243 logfile = open(os.path.join(renpy.config.basedir, renpy.config.log), "a") 2244 2245 if not logfile.tell(): 2246 logfile.write("\ufeff") 2247 2248 import textwrap 2249 2250 wrapped = textwrap.fill(msg, renpy.config.log_width) 2251 wrapped = unicode(wrapped) 2252 2253 logfile.write(wrapped + "\n") 2254 logfile.flush() 2255 2256 except: 2257 renpy.config.log = None 2258 2259 2260def force_full_redraw(): 2261 """ 2262 :doc: other 2263 2264 Forces the screen to be redrawn in full. Call this after using pygame 2265 to redraw the screen directly. 2266 """ 2267 2268 renpy.game.interface.full_redraw = True 2269 2270 2271def do_reshow_say(who, what, interact=False, *args, **kwargs): 2272 2273 if who is not None: 2274 who = renpy.python.py_eval(who) 2275 2276 say(who, what, interact=interact, *args, **kwargs) 2277 2278 2279curried_do_reshow_say = curry(do_reshow_say) 2280 2281 2282def get_reshow_say(**kwargs): 2283 kw = dict(renpy.store._last_say_kwargs) 2284 kw.update(kwargs) 2285 2286 return curried_do_reshow_say( 2287 renpy.store._last_say_who, 2288 renpy.store._last_say_what, 2289 renpy.store._last_say_args, 2290 **kw) 2291 2292 2293def reshow_say(**kwargs): 2294 get_reshow_say()(**kwargs) 2295 2296 2297def current_interact_type(): 2298 return getattr(renpy.game.context().info, "_current_interact_type", None) 2299 2300 2301def last_interact_type(): 2302 return getattr(renpy.game.context().info, "_last_interact_type", None) 2303 2304 2305def dynamic(*vars, **kwargs): # @ReservedAssignment 2306 """ 2307 :doc: other 2308 2309 This can be given one or more variable names as arguments. This makes 2310 the variables dynamically scoped to the current call. The variables will 2311 be reset to their original value when the call returns. 2312 2313 If the variables are given as keyword arguments, the value of the argument 2314 is assigned to the variable name. 2315 2316 Example calls are:: 2317 2318 $ renpy.dynamic("x", "y", "z") 2319 $ renpy.dynamic(players=2, score=0) 2320 """ 2321 2322 vars = vars + tuple(kwargs) # @ReservedAssignment 2323 renpy.game.context().make_dynamic(vars) 2324 2325 for k, v in kwargs.items(): 2326 setattr(renpy.store, k, v) 2327 2328 2329def context_dynamic(*vars): # @ReservedAssignment 2330 """ 2331 :doc: other 2332 2333 This can be given one or more variable names as arguments. This makes 2334 the variables dynamically scoped to the current context. The variables will 2335 be reset to their original value when the call returns. 2336 2337 An example call is:: 2338 2339 $ renpy.context_dynamic("x", "y", "z") 2340 """ 2341 2342 renpy.game.context().make_dynamic(vars, context=True) 2343 2344 2345def seen_label(label): 2346 """ 2347 :doc: label 2348 2349 Returns true if the named label has executed at least once on the current user's 2350 system, and false otherwise. This can be used to unlock scene galleries, for 2351 example. 2352 """ 2353 return label in renpy.game.persistent._seen_ever # @UndefinedVariable 2354 2355 2356def mark_label_seen(label): 2357 """ 2358 :doc: label 2359 2360 Marks the named label as if it has been already executed on the current user's 2361 system. 2362 """ 2363 renpy.game.persistent._seen_ever[label] = True 2364 2365 2366def mark_label_unseen(label): 2367 """ 2368 :doc: label 2369 2370 Marks the named label as if it has not been executed on the current user's 2371 system yet. 2372 """ 2373 if label in renpy.game.persistent._seen_ever: 2374 del renpy.game.persistent._seen_ever[label] 2375 2376 2377def seen_audio(filename): 2378 """ 2379 :doc: audio 2380 2381 Returns True if the given filename has been played at least once on the current 2382 user's system. 2383 """ 2384 filename = re.sub(r'^<.*?>', '', filename) 2385 2386 return filename in renpy.game.persistent._seen_audio # @UndefinedVariable 2387 2388 2389def mark_audio_seen(filename): 2390 """ 2391 :doc: audio 2392 2393 Marks the given filename as if it has been already played on the current user's 2394 system. 2395 """ 2396 filename = re.sub(r'^<.*?>', '', filename) 2397 2398 renpy.game.persistent._seen_audio[filename] = True 2399 2400 2401def mark_audio_unseen(filename): 2402 """ 2403 :doc: audio 2404 2405 Marks the given filename as if it has not been played on the current user's 2406 system yet. 2407 """ 2408 filename = re.sub(r'^<.*?>', '', filename) 2409 2410 if filename in renpy.game.persistent._seen_audio: 2411 del renpy.game.persistent._seen_audio[filename] 2412 2413 2414def seen_image(name): 2415 """ 2416 :doc: image_func 2417 2418 Returns True if the named image has been seen at least once on the user's 2419 system. An image has been seen if it's been displayed using the show statement, 2420 scene statement, or :func:`renpy.show` function. (Note that there are cases 2421 where the user won't actually see the image, like a show immediately followed by 2422 a hide.) 2423 """ 2424 if not isinstance(name, tuple): 2425 name = tuple(name.split()) 2426 2427 return name in renpy.game.persistent._seen_images # @UndefinedVariable 2428 2429 2430def mark_image_seen(name): 2431 """ 2432 :doc: image_func 2433 2434 Marks the named image as if it has been already displayed on the current user's 2435 system. 2436 """ 2437 if not isinstance(name, tuple): 2438 name = tuple(name.split()) 2439 2440 renpy.game.persistent._seen_images[name] = True 2441 2442 2443def mark_image_unseen(name): 2444 """ 2445 :doc: image_func 2446 2447 Marks the named image as if it has not been displayed on the current user's 2448 system yet. 2449 """ 2450 if not isinstance(name, tuple): 2451 name = tuple(name.split()) 2452 2453 if name in renpy.game.persistent._seen_images: 2454 del renpy.game.persistent._seen_images[name] 2455 2456 2457def file(fn): # @ReservedAssignment 2458 """ 2459 :doc: file 2460 2461 Returns a read-only file-like object that accesses the file named `fn`. The file is 2462 accessed using Ren'Py's standard search method, and may reside in an RPA archive. 2463 or as an Android asset. 2464 2465 The object supports a wide subset of the fields and methods found on Python's 2466 standard file object, opened in binary mode. (Basically, all of the methods that 2467 are sensible for a read-only file.) 2468 """ 2469 return renpy.loader.load(fn) 2470 2471 2472def notl_file(fn): # @ReservedAssignment 2473 """ 2474 :undocumented: 2475 2476 Like file, but doesn't search the translation prefix. 2477 """ 2478 return renpy.loader.load(fn, tl=False) 2479 2480 2481def image_size(im): 2482 """ 2483 :doc: file_rare 2484 2485 Given an image manipulator, loads it and returns a (``width``, 2486 ``height``) tuple giving its size. 2487 2488 This reads the image in from disk and decompresses it, without 2489 using the image cache. This can be slow. 2490 """ 2491 2492 # Index the archives, if we haven't already. 2493 renpy.loader.index_archives() 2494 2495 im = renpy.easy.displayable(im) 2496 2497 if not isinstance(im, renpy.display.im.Image): 2498 raise Exception("renpy.image_size expects it's argument to be an image.") 2499 2500 surf = im.load() 2501 return surf.get_size() 2502 2503 2504def get_at_list(name, layer=None, camera=False): 2505 """ 2506 :doc: se_images 2507 2508 Returns the list of transforms being applied to the image with tag `name` 2509 on `layer`. Returns an empty list if no transforms are being applied, or 2510 None if the image is not shown. 2511 2512 If `layer` is None, uses the default layer for the given tag. 2513 """ 2514 2515 if isinstance(name, basestring): 2516 name = tuple(name.split()) 2517 2518 tag = name[0] 2519 layer = default_layer(layer, tag) 2520 2521 return renpy.game.context().scene_lists.at_list[layer].get(tag, None) 2522 2523 2524def show_layer_at(at_list, layer='master', reset=True, camera=False): 2525 """ 2526 :doc: se_images 2527 :name: renpy.show_layer_at 2528 2529 The Python equivalent of the ``show layer`` `layer` ``at`` `at_list` 2530 statement. If `camera` is True, the equivalent of the ``camera`` statement. 2531 2532 `reset` 2533 If true, the transform state is reset to the start when it is shown. 2534 If false, the transform state is persisted, allowing the new transform 2535 to update that state. 2536 """ 2537 2538 if not isinstance(at_list, list): 2539 at_list = [ at_list ] 2540 2541 renpy.game.context().scene_lists.set_layer_at_list(layer, at_list, reset=reset, camera=camera) 2542 2543 2544layer_at_list = show_layer_at 2545 2546 2547def free_memory(): 2548 """ 2549 :doc: other 2550 2551 Attempts to free some memory. Useful before running a renpygame-based 2552 minigame. 2553 """ 2554 2555 force_full_redraw() 2556 renpy.display.interface.kill_textures() 2557 renpy.display.interface.kill_surfaces() 2558 renpy.text.font.free_memory() 2559 2560 gc.collect(2) 2561 2562 if gc.garbage: 2563 del gc.garbage[:] 2564 2565 2566def flush_cache_file(fn): 2567 """ 2568 :doc: other 2569 2570 This flushes all image cache entries that refer to the file `fn`. This 2571 may be called when an image file changes on disk to force Ren'Py to 2572 use the new version. 2573 """ 2574 2575 renpy.display.im.cache.flush_file(fn) 2576 2577 2578@renpy_pure 2579def easy_displayable(d, none=False): 2580 """ 2581 :undocumented: 2582 """ 2583 2584 if none: 2585 return renpy.easy.displayable(d) 2586 else: 2587 return renpy.easy.displayable_or_none(d) 2588 2589 2590def quit_event(): 2591 """ 2592 :doc: other 2593 2594 Triggers a quit event, as if the player clicked the quit button in the 2595 window chrome. 2596 """ 2597 2598 renpy.game.interface.quit_event() 2599 2600 2601def iconify(): 2602 """ 2603 :doc: other 2604 2605 Iconifies the game. 2606 """ 2607 2608 renpy.game.interface.iconify() 2609 2610 2611# New context stuff. 2612call_in_new_context = renpy.game.call_in_new_context 2613curried_call_in_new_context = renpy.curry.curry(renpy.game.call_in_new_context) 2614invoke_in_new_context = renpy.game.invoke_in_new_context 2615curried_invoke_in_new_context = renpy.curry.curry(renpy.game.invoke_in_new_context) 2616call_replay = renpy.game.call_replay 2617 2618renpy_pure("curried_call_in_new_context") 2619renpy_pure("curried_invoke_in_new_context") 2620 2621 2622# Error handling stuff. 2623def _error(msg): 2624 raise Exception(msg) 2625 2626 2627_error_handlers = [ _error ] 2628 2629 2630def push_error_handler(eh): 2631 _error_handlers.append(eh) 2632 2633 2634def pop_error_handler(): 2635 _error_handlers.pop() 2636 2637 2638def error(msg): 2639 """ 2640 :doc: lint 2641 2642 Reports `msg`, a string, as as error for the user. This is logged as a 2643 parse or lint error when approprate, and otherwise it is raised as an 2644 exception. 2645 """ 2646 2647 _error_handlers[-1](msg) 2648 2649 2650def timeout(seconds): 2651 """ 2652 :doc: udd_utility 2653 2654 Causes an event to be generated before `seconds` seconds have elapsed. 2655 This ensures that the event method of a user-defined displayable will be 2656 called. 2657 """ 2658 2659 renpy.game.interface.timeout(seconds) 2660 2661 2662def end_interaction(value): 2663 """ 2664 :doc: udd_utility 2665 2666 If `value` is not None, immediately ends the current interaction, causing 2667 the interaction to return `value`. If `value` is None, does nothing. 2668 2669 This can be called from inside the render and event methods of a 2670 creator-defined displayable. 2671 """ 2672 2673 if value is None: 2674 return 2675 2676 raise renpy.display.core.EndInteraction(value) 2677 2678 2679def scry(): 2680 """ 2681 :doc: other 2682 2683 Returns the scry object for the current statement. 2684 2685 The scry object tells Ren'Py about things that must be true in the 2686 future of the current statement. Right now, the scry object has one 2687 field: 2688 2689 ``nvl_clear`` 2690 Is true if an ``nvl clear`` statement will execute before the 2691 next interaction. 2692 """ 2693 2694 name = renpy.game.context().current 2695 node = renpy.game.script.lookup(name) 2696 return node.scry() 2697 2698 2699@renpy_pure 2700def munged_filename(): 2701 return renpy.parser.munge_filename(get_filename_line()[0]) 2702 2703# Module loading stuff. 2704 2705 2706loaded_modules = set() 2707 2708 2709def load_module(name, **kwargs): 2710 """ 2711 :doc: other 2712 2713 This loads the Ren'Py module named name. A Ren'Py module consists of Ren'Py script 2714 that is loaded into the usual (store) namespace, contained in a file named 2715 name.rpym or name.rpymc. If a .rpym file exists, and is newer than the 2716 corresponding .rpymc file, it is loaded and a new .rpymc file is created. 2717 2718 All of the init blocks (and other init-phase code) in the module are run 2719 before this function returns. An error is raised if the module name cannot 2720 be found, or is ambiguous. 2721 2722 Module loading may only occur from inside an init block. 2723 """ 2724 2725 if not renpy.game.context().init_phase: 2726 raise Exception("Module loading is only allowed in init code.") 2727 2728 if name in loaded_modules: 2729 return 2730 2731 loaded_modules.add(name) 2732 2733 old_locked = renpy.config.locked 2734 renpy.config.locked = False 2735 2736 initcode = renpy.game.script.load_module(name) 2737 2738 context = renpy.execution.Context(False) 2739 context.init_phase = True 2740 renpy.game.contexts.append(context) 2741 2742 context.make_dynamic(kwargs) 2743 renpy.store.__dict__.update(kwargs) # @UndefinedVariable 2744 2745 for prio, node in initcode: # @UnusedVariable 2746 if isinstance(node, renpy.ast.Node): 2747 renpy.game.context().run(node) 2748 else: 2749 node() 2750 2751 context.pop_all_dynamic() 2752 2753 renpy.game.contexts.pop() 2754 2755 renpy.config.locked = old_locked 2756 2757 2758def load_string(s, filename="<string>"): 2759 """ 2760 :doc: other 2761 2762 Loads `s` as Ren'Py script that can be called. 2763 2764 Returns the name of the first statement in s. 2765 2766 `filename` is the name of the filename that statements in the string will 2767 appear to be from. 2768 """ 2769 2770 old_exception_info = renpy.game.exception_info 2771 2772 try: 2773 2774 old_locked = renpy.config.locked 2775 renpy.config.locked = False 2776 2777 stmts, initcode = renpy.game.script.load_string(filename, str(s)) 2778 2779 if stmts is None: 2780 return None 2781 2782 context = renpy.execution.Context(False) 2783 context.init_phase = True 2784 renpy.game.contexts.append(context) 2785 2786 for prio, node in initcode: # @UnusedVariable 2787 if isinstance(node, renpy.ast.Node): 2788 renpy.game.context().run(node) 2789 else: 2790 node() 2791 2792 context.pop_all_dynamic() 2793 renpy.game.contexts.pop() 2794 2795 renpy.config.locked = old_locked 2796 2797 renpy.game.script.analyze() 2798 2799 return stmts[0].name 2800 2801 finally: 2802 renpy.game.exception_info = old_exception_info 2803 2804 2805def pop_call(): 2806 """ 2807 :doc: other 2808 :name: renpy.pop_call 2809 2810 Pops the current call from the call stack, without returning to 2811 the location. 2812 2813 This can be used if a label that is called decides not to return 2814 to its caller. 2815 """ 2816 2817 renpy.game.context().pop_call() 2818 2819 2820pop_return = pop_call 2821 2822 2823def call_stack_depth(): 2824 """ 2825 :doc: other 2826 2827 Returns the depth of the call stack of the current context - the number 2828 of calls that have run without being returned from or popped from the 2829 call stack. 2830 """ 2831 2832 return len(renpy.game.context().return_stack) 2833 2834 2835def game_menu(screen=None): 2836 """ 2837 :undocumented: Probably not what we want in the presence of 2838 screens. 2839 """ 2840 2841 if screen is None: 2842 call_in_new_context("_game_menu") 2843 else: 2844 call_in_new_context("_game_menu", _game_menu_screen=screen) 2845 2846 2847def shown_window(): 2848 """ 2849 :doc: other 2850 2851 Call this to indicate that the window has been shown. This interacts 2852 with the "window show" statement, which shows an empty window whenever 2853 this functions has not been called during an interaction. 2854 """ 2855 2856 renpy.game.context().scene_lists.shown_window = True 2857 2858 2859class placement(renpy.python.RevertableObject): 2860 2861 def __init__(self, p): 2862 super(placement, self).__init__() 2863 2864 self.xpos = p[0] 2865 self.ypos = p[1] 2866 self.xanchor = p[2] 2867 self.yanchor = p[3] 2868 self.xoffset = p[4] 2869 self.yoffset = p[5] 2870 self.subpixel = p[6] 2871 2872 @property 2873 def pos(self): 2874 return self.xpos, self.ypos 2875 2876 @property 2877 def anchor(self): 2878 return self.xanchor, self.yanchor 2879 2880 @property 2881 def offset(self): 2882 return self.xoffset, self.yoffset 2883 2884 2885def get_placement(d): 2886 """ 2887 :doc: image_func 2888 2889 This gets the placement of displayable d. There's very little warranty on this 2890 information, as it might change when the displayable is rendered, and might not 2891 exist until the displayable is first rendered. 2892 2893 This returns an object with the following fields, each corresponding to a style 2894 property: 2895 2896 * pos 2897 * xpos 2898 * ypos 2899 * anchor 2900 * xanchor 2901 * yanchor 2902 * offset 2903 * xoffset 2904 * yoffset 2905 * subpixel 2906 2907 """ 2908 p = d.get_placement() 2909 2910 return placement(p) 2911 2912 2913def get_image_bounds(tag, width=None, height=None, layer=None): 2914 """ 2915 :doc: image_func 2916 2917 If an image with `tag` exists on `layer`, returns the bounding box of 2918 that image. Returns None if the image is not found. 2919 2920 The bounding box is an (x, y, width, height) tuple. The components of 2921 the tuples are expressed in pixels, and may be floating point numbers. 2922 2923 `width`, `height` 2924 The width and height of the area that contains the image. If None, 2925 defaults the width and height of the screen, respectively. 2926 2927 `layer` 2928 If None, uses the default layer for `tag`. 2929 """ 2930 2931 tag = tag.split()[0] 2932 layer = default_layer(layer, tag) 2933 2934 if width is None: 2935 width = renpy.config.screen_width 2936 if height is None: 2937 height = renpy.config.screen_height 2938 2939 return scene_lists().get_image_bounds(layer, tag, width, height) 2940 2941# User-Defined Displayable stuff. 2942 2943 2944Render = renpy.display.render.Render 2945render = renpy.display.render.render 2946IgnoreEvent = renpy.display.core.IgnoreEvent 2947redraw = renpy.display.render.redraw 2948 2949 2950class Displayable(renpy.display.core.Displayable, renpy.python.RevertableObject): 2951 pass 2952 2953 2954class Container(renpy.display.layout.Container, renpy.python.RevertableObject): 2955 _list_type = renpy.python.RevertableList 2956 2957 2958def get_roll_forward(): 2959 return renpy.game.interface.shown_window 2960 2961 2962def cache_pin(*args): 2963 """ 2964 :undocumented: Cache pin is deprecated. 2965 """ 2966 2967 new_pins = renpy.python.RevertableSet() 2968 2969 for i in args: 2970 2971 im = renpy.easy.displayable(i) 2972 2973 if not isinstance(im, renpy.display.im.ImageBase): 2974 raise Exception("Cannot pin non-image-manipulator %r" % im) 2975 2976 new_pins.add(im) 2977 2978 renpy.store._cache_pin_set = new_pins | renpy.store._cache_pin_set 2979 2980 2981def cache_unpin(*args): 2982 """ 2983 :undocumented: Cache pin is deprecated. 2984 """ 2985 2986 new_pins = renpy.python.RevertableSet() 2987 2988 for i in args: 2989 2990 im = renpy.easy.displayable(i) 2991 2992 if not isinstance(im, renpy.display.im.ImageBase): 2993 raise Exception("Cannot unpin non-image-manipulator %r" % im) 2994 2995 new_pins.add(im) 2996 2997 renpy.store._cache_pin_set = renpy.store._cache_pin_set - new_pins 2998 2999 3000def expand_predict(d): 3001 """ 3002 :undocumented: 3003 3004 Use the fnmatch function to expland `d` for the purposes of prediction. 3005 """ 3006 3007 if not isinstance(d, basestring): 3008 return [ d ] 3009 3010 if not "*" in d: 3011 return [ d ] 3012 3013 if "." in d: 3014 l = list_files(False) 3015 else: 3016 l = list_images() 3017 3018 return fnmatch.filter(l, d) 3019 3020 3021def start_predict(*args): 3022 """ 3023 :doc: image_func 3024 3025 This function takes one or more displayables as arguments. It causes 3026 Ren'Py to predict those displayables during every interaction until 3027 the displayables are removed by :func:`renpy.stop_predict`. 3028 3029 If a displayable name is a string containing one or more \\* 3030 characters, the asterisks are used as a wildcard pattern. If there 3031 is at least one . in the string, the pattern is matched against 3032 filenames, otherwise it is matched against image names. 3033 3034 For example:: 3035 3036 $ renpy.start_predict("eileen *") 3037 3038 starts predicting all images with the name eileen, while:: 3039 3040 $ renpy.start_predict("images/concert*.*") 3041 3042 matches all files starting with concert in the images directory. 3043 """ 3044 3045 new_predict = renpy.python.RevertableSet(renpy.store._predict_set) 3046 3047 for i in args: 3048 for d in expand_predict(i): 3049 d = renpy.easy.displayable(d) 3050 new_predict.add(d) 3051 3052 renpy.store._predict_set = new_predict 3053 3054 3055def stop_predict(*args): 3056 """ 3057 :doc: image_func 3058 3059 This function takes one or more displayables as arguments. It causes 3060 Ren'Py to stop predicting those displayables during every interaction. 3061 3062 Wildcard patterns can be used as described in :func:`renpy.start_predict`. 3063 """ 3064 3065 new_predict = renpy.python.RevertableSet(renpy.store._predict_set) 3066 3067 for i in args: 3068 for d in expand_predict(i): 3069 d = renpy.easy.displayable(d) 3070 new_predict.discard(d) 3071 3072 renpy.store._predict_set = new_predict 3073 3074 3075def start_predict_screen(_screen_name, *args, **kwargs): 3076 """ 3077 :doc: screens 3078 3079 Causes Ren'Py to start predicting the screen named `_screen_name` 3080 with the given arguments. This replaces any previous prediction 3081 of `_screen_name`. To stop predicting a screen, call :func:`renpy.stop_predict_screen`. 3082 """ 3083 3084 new_predict = renpy.python.RevertableDict(renpy.store._predict_screen) 3085 new_predict[_screen_name] = (args, kwargs) 3086 renpy.store._predict_screen = new_predict 3087 3088 3089def stop_predict_screen(name): 3090 """ 3091 :doc: screens 3092 3093 Causes Ren'Py to stop predicting the screen named `name`. 3094 """ 3095 3096 new_predict = renpy.python.RevertableDict(renpy.store._predict_screen) 3097 new_predict.pop(name, None) 3098 renpy.store._predict_screen = new_predict 3099 3100 3101def call_screen(_screen_name, *args, **kwargs): 3102 """ 3103 :doc: screens 3104 3105 The programmatic equivalent of the call screen statement. 3106 3107 This shows `_screen_name` as a screen, then causes an interaction 3108 to occur. The screen is hidden at the end of the interaction, and 3109 the result of the interaction is returned. 3110 3111 Positional arguments, and keyword arguments that do not begin with 3112 _ are passed to the screen. 3113 3114 If the keyword argument `_with_none` is false, "with None" is not 3115 run at the end of end of the interaction. 3116 3117 If the keyword argument `_mode` in kwargs, it will be mode of this 3118 interaction, otherwise it will be "screen" mode. 3119 """ 3120 3121 mode = "screen" 3122 if "_mode" in kwargs: 3123 mode = kwargs.pop("_mode") 3124 renpy.exports.mode(mode) 3125 3126 with_none = renpy.config.implicit_with_none 3127 3128 if "_with_none" in kwargs: 3129 with_none = kwargs.pop("_with_none") 3130 3131 show_screen(_screen_name, _transient=True, *args, **kwargs) 3132 3133 roll_forward = renpy.exports.roll_forward_info() 3134 3135 try: 3136 rv = renpy.ui.interact(mouse="screen", type="screen", roll_forward=roll_forward) 3137 except (renpy.game.JumpException, renpy.game.CallException) as e: 3138 rv = e 3139 3140 renpy.exports.checkpoint(rv) 3141 3142 if with_none: 3143 renpy.game.interface.do_with(None, None) 3144 3145 if isinstance(rv, (renpy.game.JumpException, renpy.game.CallException)): 3146 raise rv 3147 3148 return rv 3149 3150 3151@renpy_pure 3152def list_files(common=False): 3153 """ 3154 :doc: file 3155 3156 Lists the files in the game directory and archive files. Returns 3157 a list of files, with / as the directory separator. 3158 3159 `common` 3160 If true, files in the common directory are included in the 3161 listing. 3162 """ 3163 3164 rv = [ ] 3165 3166 for dir, fn in renpy.loader.listdirfiles(common): # @ReservedAssignment 3167 if fn.startswith("saves/"): 3168 continue 3169 3170 rv.append(fn) 3171 3172 rv.sort() 3173 3174 return rv 3175 3176 3177def get_renderer_info(): 3178 """ 3179 :doc: other 3180 3181 Returns a dictionary, giving information about the renderer Ren'Py is 3182 currently using. Defined keys are: 3183 3184 ``"renderer"`` 3185 A string giving the name of the renderer that is in use. 3186 3187 ``"resizable"`` 3188 True if and only if the window is resizable. 3189 3190 ``"additive"`` 3191 True if and only if the renderer supports additive blending. 3192 3193 ``"model"`` 3194 Present and true if model-based rendering is supported. 3195 3196 Other, renderer-specific, keys may also exist. The dictionary should 3197 be treated as immutable. This should only be called once the display 3198 has been started (that is, after the init phase has finished). 3199 """ 3200 3201 return renpy.display.draw.info 3202 3203 3204def display_reset(): 3205 """ 3206 :undocumented: Used internally. 3207 3208 Causes the display to be restarted at the start of the next interaction. 3209 """ 3210 3211 renpy.display.interface.display_reset = True 3212 3213 3214def mode(mode): 3215 """ 3216 :doc: modes 3217 3218 Causes Ren'Py to enter the named mode, or stay in that mode if it's 3219 already in it. 3220 """ 3221 3222 ctx = renpy.game.context() 3223 3224 if not ctx.use_modes: 3225 return 3226 3227 modes = ctx.modes 3228 3229 try: 3230 ctx.use_modes = False 3231 3232 if mode != modes[0]: 3233 for c in renpy.config.mode_callbacks: 3234 c(mode, modes) 3235 3236 finally: 3237 ctx.use_modes = True 3238 3239 if mode in modes: 3240 modes.remove(mode) 3241 3242 modes.insert(0, mode) 3243 3244 3245def get_mode(): 3246 """ 3247 :doc: modes 3248 3249 Returns the current mode, or None if it is not defined. 3250 """ 3251 3252 ctx = renpy.game.context() 3253 3254 if not ctx.use_modes: 3255 return None 3256 3257 modes = ctx.modes 3258 3259 return modes[0] 3260 3261 3262def notify(message): 3263 """ 3264 :doc: other 3265 3266 Causes Ren'Py to display the `message` using the notify screen. By 3267 default, this will cause the message to be dissolved in, displayed 3268 for two seconds, and dissolved out again. 3269 3270 This is useful for actions that otherwise wouldn't produce feedback, 3271 like screenshots or quicksaves. 3272 3273 Only one notification is displayed at a time. If a second notification 3274 is displayed, the first notification is replaced. 3275 3276 This function just calls :var:`config.notify`, allowing its implementation 3277 to be replaced by assigning a new function to that variable. 3278 """ 3279 3280 renpy.config.notify(message) 3281 3282 3283def display_notify(message): 3284 """ 3285 :doc: other 3286 3287 The default implementation of :func:`renpy.notify`. 3288 """ 3289 3290 hide_screen('notify') 3291 show_screen('notify', message=message) 3292 restart_interaction() 3293 3294 3295@renpy_pure 3296def variant(name): 3297 """ 3298 :doc: screens 3299 3300 Returns true if a `name` is a screen variant that can be chosen 3301 by Ren'Py. See :ref:`screen-variants` for more details. This function 3302 can be used as the condition in a Python if statement to set up the 3303 appropriate styles for the selected screen variant. 3304 3305 `name` can also be a list of variants, in which case this function 3306 returns True if any of the variants is selected. 3307 """ 3308 3309 if isinstance(name, basestring): 3310 return name in renpy.config.variants 3311 else: 3312 for n in name: 3313 if n in renpy.config.variants: 3314 return True 3315 3316 return False 3317 3318 3319def vibrate(duration): 3320 """ 3321 :doc: other 3322 3323 Causes the device to vibrate for `duration` seconds. Currently, this 3324 is only supported on Android. 3325 """ 3326 3327 if renpy.android: 3328 import android # @UnresolvedImport 3329 android.vibrate(duration) 3330 3331 3332def get_say_attributes(): 3333 """ 3334 :doc: other 3335 3336 Gets the attributes associated with the current say statement, or 3337 None if no attributes are associated with this statement. 3338 3339 This is only valid when executing or predicting a say statement. 3340 """ 3341 3342 return renpy.game.context().say_attributes 3343 3344 3345def get_side_image(prefix_tag, image_tag=None, not_showing=None, layer=None): 3346 """ 3347 :doc: side 3348 3349 This attempts to find an image to show as the side image. 3350 3351 It begins by determining a set of image attributes. If `image_tag` is 3352 given, it gets the image attributes from the tag. Otherwise, it gets 3353 them from the currently showing character. 3354 3355 It then looks up an image with the tag `prefix_tag` and those attributes, 3356 and returns it if it exists. 3357 3358 If not_showing is True, this only returns a side image if the image the 3359 attributes are taken from is not on the screen. If Nome, the value 3360 is taken from :var:`config.side_image_only_not_showing`. 3361 3362 If `layer` is None, uses the default layer for the currently showing 3363 tag. 3364 """ 3365 3366 if not_showing is None: 3367 not_showing = renpy.config.side_image_only_not_showing 3368 3369 images = renpy.game.context().images 3370 3371 if image_tag is not None: 3372 image_layer = default_layer(layer, image_tag) 3373 attrs = (image_tag,) + images.get_attributes(image_layer, image_tag) 3374 3375 if renpy.config.side_image_requires_attributes and (len(attrs) < 2): 3376 return None 3377 3378 else: 3379 attrs = renpy.store._side_image_attributes 3380 3381 if not attrs: 3382 return None 3383 3384 attr_layer = default_layer(layer, attrs) 3385 3386 if not_showing and images.showing(attr_layer, (attrs[0],)): 3387 return None 3388 3389 required = [ attrs[0] ] 3390 optional = list(attrs[1:]) 3391 3392 return images.choose_image(prefix_tag, required, optional, None) 3393 3394 3395def get_physical_size(): 3396 """ 3397 :doc: other 3398 3399 Returns the size of the physical window. 3400 """ 3401 3402 return renpy.display.draw.get_physical_size() 3403 3404 3405def set_physical_size(size): 3406 """ 3407 :doc: other 3408 3409 Attempts to set the size of the physical window to `size`. This has the 3410 side effect of taking the screen out of fullscreen mode. 3411 """ 3412 3413 width = int(size[0]) 3414 height = int(size[1]) 3415 3416 renpy.game.preferences.fullscreen = False 3417 3418 if get_renderer_info()["resizable"]: 3419 3420 renpy.game.preferences.physical_size = (width, height) 3421 3422 if renpy.display.draw is not None: 3423 renpy.display.draw.resize() 3424 3425 3426def reset_physical_size(): 3427 """ 3428 :doc: other 3429 3430 Attempts to set the size of the physical window to the specified values 3431 in renpy.config. (That is, screen_width and screen_height.) This has the 3432 side effect of taking the screen out of fullscreen mode. 3433 """ 3434 3435 set_physical_size((renpy.config.screen_width, renpy.config.screen_height)) 3436 3437 3438@renpy_pure 3439def fsencode(s): 3440 """ 3441 :doc: file_rare 3442 :name: renpy.fsencode 3443 3444 Converts s from unicode to the filesystem encoding. 3445 """ 3446 3447 if not PY2: 3448 return s 3449 3450 if not isinstance(s, str): 3451 return s 3452 3453 fsencoding = sys.getfilesystemencoding() or "utf-8" 3454 return s.encode(fsencoding) 3455 3456 3457@renpy_pure 3458def fsdecode(s): 3459 """ 3460 :doc: file_rare 3461 :name: renpy.fsdecode 3462 3463 Converts s from filesystem encoding to unicode. 3464 """ 3465 3466 if not PY2: 3467 return s 3468 3469 if not isinstance(s, pystr): 3470 return s 3471 3472 fsencoding = sys.getfilesystemencoding() or "utf-8" 3473 return s.decode(fsencoding) 3474 3475 3476from renpy.editor import launch_editor # @UnusedImport 3477 3478 3479def get_image_load_log(age=None): 3480 """ 3481 :doc: other 3482 3483 A generator that yields a log of image loading activity. For the last 100 3484 image loads, this returns: 3485 3486 * The time the image was loaded (in seconds since the epoch). 3487 * The filename of the image that was loaded. 3488 * A boolean that is true if the image was preloaded, and false if the 3489 game stalled to load it. 3490 3491 The entries are ordered from newest to oldest. 3492 3493 `age` 3494 If not None, only images that have been loaded in the past `age` 3495 seconds are included. 3496 3497 The image load log is only kept if config.developer = True. 3498 """ 3499 3500 if age is not None: 3501 deadline = time.time() - age 3502 else: 3503 deadline = 0 3504 3505 for i in renpy.display.im.cache.load_log: 3506 if i[0] < deadline: 3507 break 3508 3509 yield i 3510 3511 3512def end_replay(): 3513 """ 3514 :doc: replay 3515 3516 If we're in a replay, ends the replay immediately. Otherwise, does 3517 nothing. 3518 """ 3519 3520 if renpy.store._in_replay: 3521 raise renpy.game.EndReplay() 3522 3523 3524def save_persistent(): 3525 """ 3526 :doc: persistent 3527 3528 Saves the persistent data to disk. 3529 """ 3530 3531 renpy.persistent.update(True) 3532 3533 3534def is_seen(ever=True): 3535 """ 3536 :doc: other 3537 3538 Returns true if the current line has been seen by the player. 3539 3540 If `ever` is true, we check to see if the line has ever been seen by the 3541 player. If false, we check if the line has been seen in the current 3542 play-through. 3543 """ 3544 3545 return renpy.game.context().seen_current(ever) 3546 3547 3548def get_mouse_pos(): 3549 """ 3550 :doc: other 3551 3552 Returns an (x, y) tuple giving the location of the mouse pointer or the 3553 current touch location. If the device does not support a mouse and is not 3554 currently being touched, x and y are numbers, but not meaningful. 3555 """ 3556 return renpy.display.draw.get_mouse_pos() 3557 3558 3559def set_mouse_pos(x, y, duration=0): 3560 """ 3561 :doc: other 3562 3563 Jump the mouse pointer to the location given by arguments x and y. 3564 If the device does not have a mouse pointer, this does nothing. 3565 3566 `duration` 3567 The time it will take to perform the move, in seconds. 3568 During this time, the mouse may be unresponsive. 3569 """ 3570 3571 renpy.display.interface.set_mouse_pos(x, y, duration) 3572 3573 3574def set_autoreload(autoreload): 3575 """ 3576 :doc: other 3577 3578 Sets the autoreload flag, which determines if the game will be 3579 automatically reloaded after file changes. Autoreload will not be 3580 fully enabled until the game is reloaded with :func:`renpy.utter_restart`. 3581 """ 3582 3583 renpy.autoreload = autoreload 3584 3585 3586def get_autoreload(): 3587 """ 3588 :doc: other 3589 3590 Gets the autoreload flag. 3591 """ 3592 3593 return renpy.autoreload 3594 3595 3596def count_dialogue_blocks(): 3597 """ 3598 :doc: other 3599 3600 Returns the number of dialogue blocks in the game's original language. 3601 """ 3602 3603 return renpy.game.script.translator.count_translates() 3604 3605 3606def count_seen_dialogue_blocks(): 3607 """ 3608 :doc: other 3609 3610 Returns the number of dialogue blocks the user has seen in any play-through 3611 of the current game. 3612 """ 3613 3614 return renpy.game.seen_translates_count 3615 3616 3617def count_newly_seen_dialogue_blocks(): 3618 """ 3619 :doc: other 3620 3621 Returns the number of dialogue blocks the user has seen for the first time 3622 during this session. 3623 """ 3624 3625 return renpy.game.new_translates_count 3626 3627 3628def substitute(s, scope=None, translate=True): 3629 """ 3630 :doc: other 3631 3632 Applies translation and new-style formatting to the string `s`. 3633 3634 `scope` 3635 If not None, a scope which is used in formatting, in addition to the 3636 default store. 3637 3638 `translate` 3639 Determines if translation occurs. 3640 3641 Returns the translated and formatted string. 3642 """ 3643 3644 return renpy.substitutions.substitute(s, scope=scope, translate=translate)[0] 3645 3646 3647def munge(name, filename=None): 3648 """ 3649 :doc: other 3650 3651 Munges `name`, which must begin with __. 3652 3653 `filename` 3654 The filename the name is munged into. If None, the name is munged 3655 into the filename containing the call to this function. 3656 """ 3657 3658 if filename is None: 3659 filename = sys._getframe(1).f_code.co_filename 3660 3661 if not name.startswith("__"): 3662 return name 3663 3664 if name.endswith("__"): 3665 return name 3666 3667 return renpy.parser.munge_filename(filename) + name[2:] 3668 3669 3670def get_return_stack(): 3671 """ 3672 :doc: label 3673 3674 Returns a list giving the current return stack. The return stack is a 3675 list of statement names. 3676 3677 The statement names will be strings (for labels), or opaque tuples (for 3678 non-label statements). 3679 """ 3680 3681 return renpy.game.context().get_return_stack() 3682 3683 3684def set_return_stack(stack): 3685 """ 3686 :doc: label 3687 3688 Sets the current return stack. The return stack is a list of statement 3689 names. 3690 3691 Statement names may be strings (for labels) or opaque tuples (for 3692 non-label statements). 3693 """ 3694 3695 renpy.game.context().set_return_stack(stack) 3696 3697 3698def invoke_in_thread(fn, *args, **kwargs): 3699 """ 3700 :doc: other 3701 3702 Invokes the function `fn` in a background thread, passing it the 3703 provided arguments and keyword arguments. Restarts the interaction 3704 once the thread returns. 3705 3706 This function creates a daemon thread, which will be automatically 3707 stopped when Ren'Py is shutting down. 3708 3709 This thread is very limited in what it can do with the Ren'Py API. 3710 Changing store variables is allowed, as is calling the :func:`renpy.queue_event` 3711 function. Most other portions of the Ren'Py API are expected to be called from 3712 the main thread. 3713 3714 The primary use of this function is to place accesss to a web API in a second 3715 thread, and then update variables with the results of that call, by storing 3716 the result in variables and then relying on the interaction restart to cause 3717 screens to display those variables. 3718 """ 3719 3720 def run(): 3721 try: 3722 fn(*args, **kwargs) 3723 except: 3724 import traceback 3725 traceback.print_exc() 3726 3727 restart_interaction() 3728 3729 t = threading.Thread(target=run) 3730 t.daemon = True 3731 t.start() 3732 3733 3734def cancel_gesture(): 3735 """ 3736 :doc: gesture 3737 3738 Cancels the current gesture, preventing the gesture from being recognized. 3739 This should be called by displayables that have gesture-like behavior. 3740 """ 3741 3742 renpy.display.gesture.recognizer.cancel() # @UndefinedVariable 3743 3744 3745def execute_default_statement(start=False): 3746 """ 3747 :undocumented: 3748 3749 Executes the default statement. 3750 """ 3751 3752 for i in renpy.ast.default_statements: 3753 i.set_default(start) 3754 3755 3756def write_log(s, *args): 3757 """ 3758 :undocumented: 3759 3760 Writes to log.txt. 3761 """ 3762 3763 renpy.display.log.write(s, *args) 3764 3765 3766def predicting(): 3767 """ 3768 :doc: screens 3769 3770 Returns true if Ren'Py is currently predicting the screen. 3771 """ 3772 3773 return renpy.display.predict.predicting 3774 3775 3776def get_line_log(): 3777 """ 3778 :undocumented: 3779 3780 Returns the list of lines that have been shown since the last time 3781 :func:`renpy.clear_line_log` was called. 3782 """ 3783 3784 return renpy.game.context().line_log[:] 3785 3786 3787def clear_line_log(): 3788 """ 3789 :undocumented: 3790 3791 Clears the line log. 3792 """ 3793 3794 renpy.game.context().line_log = [ ] 3795 3796 3797def add_layer(layer, above=None, below=None, menu_clear=True): 3798 """ 3799 :doc: other 3800 3801 Adds a new layer to the screen. If the layer already exists, this 3802 function does nothing. 3803 3804 One of `behind` or `above` must be given. 3805 3806 `layer` 3807 A string giving the name of the new layer to add. 3808 3809 `above` 3810 If not None, a string giving the name of a layer the new layer will 3811 be placed above. 3812 3813 `below` 3814 If not None, a string giving the name of a layer the new layer will 3815 be placed below. 3816 3817 `menu_clear` 3818 If true, this layer will be cleared when entering the game menu 3819 context, and restored when leaving the 3820 """ 3821 3822 layers = renpy.config.layers 3823 3824 if layer in renpy.config.layers: 3825 return 3826 3827 if (above is not None) and (below is not None): 3828 raise Exception("The above and below arguments to renpy.add_layer are mutually exclusive.") 3829 3830 elif above is not None: 3831 try: 3832 index = layers.index(above) + 1 3833 except ValueError: 3834 raise Exception("Layer '%s' does not exist." % above) 3835 3836 elif below is not None: 3837 try: 3838 index = layers.index(below) 3839 except ValueError: 3840 raise Exception("Layer '%s' does not exist." % below) 3841 3842 else: 3843 raise Exception("The renpy.add_layer function requires either the above or below argument.") 3844 3845 layers.insert(index, layer) 3846 3847 if menu_clear: 3848 renpy.config.menu_clear_layers.append(layer) # @UndefinedVariable 3849 3850 3851def maximum_framerate(t): 3852 """ 3853 :doc: other 3854 3855 Forces Ren'Py to draw the screen at the maximum framerate for `t` seconds. 3856 If `t` is None, cancels the maximum framerate request. 3857 """ 3858 3859 if renpy.display.interface is not None: 3860 renpy.display.interface.maximum_framerate(t) 3861 else: 3862 if t is None: 3863 renpy.display.core.initial_maximum_framerate = 0 3864 else: 3865 renpy.display.core.initial_maximum_framerate = max(renpy.display.core.initial_maximum_framerate, t) 3866 3867 3868def is_start_interact(): 3869 """ 3870 :doc: other 3871 3872 Returns true if restart_interaction has not been called during the current 3873 interaction. This can be used to determine if the interaction is just being 3874 started, or has been restarted. 3875 """ 3876 3877 return renpy.display.interface.start_interact 3878 3879 3880def play(filename, channel=None, **kwargs): 3881 """ 3882 :doc: audio 3883 3884 Plays a sound effect. If `channel` is None, it defaults to 3885 :var:`config.play_channel`. This is used to play sounds defined in 3886 styles, :propref:`hover_sound` and :propref:`activate_sound`. 3887 """ 3888 3889 if filename is None: 3890 return 3891 3892 if channel is None: 3893 channel = renpy.config.play_channel 3894 3895 renpy.audio.music.play(filename, channel=channel, loop=False, **kwargs) 3896 3897 3898def get_editable_input_value(): 3899 """ 3900 :undocumented: 3901 3902 Returns the current input value, and a flag that is true if it is editable. 3903 and false otherwise. 3904 """ 3905 3906 return renpy.display.behavior.current_input_value, renpy.display.behavior.input_value_active 3907 3908 3909def set_editable_input_value(input_value, editable): 3910 """ 3911 :undocumented: 3912 3913 Sets the currently active input value, and if it should be marked as 3914 editable. 3915 """ 3916 3917 renpy.display.behavior.current_input_value = input_value 3918 renpy.display.behavior.input_value_active = editable 3919 3920 3921def get_refresh_rate(precision=5): 3922 """ 3923 :doc: other 3924 3925 Returns the refresh rate of the current screen, as a floating-point 3926 number of frames per second. 3927 3928 `precision` 3929 The raw data Ren'Py gets is number of frames per second, rounded down. 3930 This means that a monitor that runs at 59.95 frames per second will 3931 be reported at 59 fps. The precision argument reduces the precision 3932 of this reading, such that the only valid readings are multiples of 3933 the precision. 3934 3935 Since all monitor framerates tend to be multiples of 5 (25, 30, 60, 3936 75, and 120), this likely will improve accuracy. Setting precision 3937 to 1 disables this. 3938 """ 3939 3940 precision *= 1.0 3941 3942 info = renpy.display.get_info() 3943 rv = info.refresh_rate 3944 rv = round(rv / precision) * precision 3945 3946 return rv 3947 3948 3949def get_identifier_checkpoints(identifier): 3950 """ 3951 :doc: rollback 3952 3953 Given a rollback_identifier from a HistoryEntry object, returns the number 3954 of checkpoints that need to be passed to :func:`renpy.rollback` to reach 3955 that identifier. Returns None of the identifier is not in the rollback 3956 history. 3957 """ 3958 3959 return renpy.game.log.get_identifier_checkpoints(identifier) 3960 3961 3962def get_adjustment(bar_value): 3963 """ 3964 :doc: other 3965 3966 Given `bar_value`, a :class:`BarValue`, returns the :func:`ui.adjustment` 3967 if uses. The adjustment has the following to attributes defined: 3968 3969 .. attribute:: value 3970 3971 The current value of the bar. 3972 3973 .. attribute:: range 3974 3975 The current range of the bar. 3976 """ 3977 3978 return bar_value.get_adjustment() 3979 3980 3981def get_skipping(): 3982 """ 3983 :doc: other 3984 3985 Returns "slow" if the Ren'Py is skipping, "fast" if Ren'Py is fast skipping, 3986 and None if it is not skipping. 3987 """ 3988 3989 return renpy.config.skipping 3990 3991 3992def get_texture_size(): 3993 """ 3994 :undocumented: 3995 3996 Returns the number of bytes of memory locked up in OpenGL textures and the 3997 number of textures that are defined. 3998 """ 3999 4000 return renpy.display.draw.get_texture_size() 4001 4002 4003old_battery = False 4004 4005 4006def get_on_battery(): 4007 """ 4008 :other: 4009 4010 Returns True if Ren'Py is running on a device that is powered by an internal 4011 battery, or False if the device is being charged by some external source. 4012 """ 4013 4014 global old_battery 4015 4016 pi = pygame_sdl2.power.get_power_info() # @UndefinedVariable 4017 4018 if pi.state == pygame_sdl2.POWERSTATE_UNKNOWN: # @UndefinedVariable 4019 return old_battery 4020 elif pi.state == pygame_sdl2.POWERSTATE_ON_BATTERY: # @UndefinedVariable 4021 old_battery = True 4022 return True 4023 else: 4024 old_battery = False 4025 return False 4026 4027 4028def get_say_image_tag(): 4029 """ 4030 :doc: image_func 4031 4032 Returns the tag corresponding to the currently speaking character (the 4033 `image` argument given to that character). Returns None if no character 4034 is speaking or the current speaking character does not have a corresponding 4035 image tag. 4036 """ 4037 4038 if renpy.store._side_image_attributes is None: 4039 return None 4040 4041 return renpy.store._side_image_attributes[0] 4042 4043 4044def is_skipping(): 4045 """ 4046 :doc: other 4047 4048 Returns True if Ren'Py is currently skipping (in fast or slow skip mode), 4049 or False otherwise. 4050 """ 4051 4052 return not not renpy.config.skipping 4053 4054 4055def is_init_phase(): 4056 """ 4057 :doc: other 4058 4059 Returns True if Ren'Py is currently executing init code, or False otherwise. 4060 """ 4061 4062 return renpy.game.context().init_phase 4063 4064 4065def add_to_all_stores(name, value): 4066 """ 4067 :doc: other 4068 4069 Adds the `value` by the `name` to all creator defined namespaces. If the name 4070 already exist in that namespace - do nothing for it. 4071 4072 This function may only be run from inside an init block. It is an 4073 error to run this function once the game has started. 4074 """ 4075 4076 if not is_init_phase(): 4077 raise Exception("add_to_all_stores is only allowed in init code.") 4078 4079 for _k, ns in renpy.python.store_dicts.items(): 4080 4081 if name not in ns: 4082 ns[name] = value 4083 4084 4085def get_zorder_list(layer): 4086 """ 4087 :doc: image_func 4088 4089 Returns a list of (tag, zorder) pairs for `layer`. 4090 """ 4091 4092 return renpy.display.core.scene_lists().get_zorder_list(layer) 4093 4094 4095def change_zorder(layer, tag, zorder): 4096 """ 4097 :doc: image_func 4098 4099 Changes the zorder of `tag` on `layer` to `zorder`. 4100 """ 4101 4102 return renpy.display.core.scene_lists().change_zorder(layer, tag, zorder) 4103 4104 4105sdl_dll = False 4106 4107 4108def get_sdl_dll(): 4109 """ 4110 :doc: sdl 4111 4112 This returns a ctypes.cdll object that refers to the library that contains 4113 the instance of SDL2 that Ren'Py is using. 4114 4115 If this can not be done, None is returned. 4116 """ 4117 4118 global sdl_dll 4119 4120 if sdl_dll is not False: 4121 return sdl_dll 4122 4123 try: 4124 4125 DLLS = [ None, "librenpython.dll", "librenpython.dylib", "librenpython.so", "SDL2.dll", "libSDL2.dylib", "libSDL2-2.0.so.0" ] 4126 4127 import ctypes 4128 4129 for i in DLLS: 4130 try: 4131 # Look for the DLL. 4132 dll = ctypes.cdll[i] 4133 # See if it has SDL_GetError.. 4134 dll.SDL_GetError 4135 except: 4136 continue 4137 4138 sdl_dll = dll 4139 return dll 4140 4141 except: 4142 pass 4143 4144 sdl_dll = None 4145 return None 4146 4147 4148def get_sdl_window_pointer(): 4149 """ 4150 :doc: sdl 4151 4152 Returns a pointer (of type ctypes.c_void_p) to the main window, or None 4153 if the main window is not displayed, or some other problem occurs. 4154 """ 4155 4156 try: 4157 window = pygame_sdl2.display.get_window() 4158 4159 if window is None: 4160 return 4161 4162 return window.get_sdl_window_pointer() 4163 4164 except: 4165 return None 4166 4167 4168def is_mouse_visible(): 4169 """ 4170 :doc: other 4171 4172 Returns True if the mouse cursor is visible, False otherwise. 4173 """ 4174 4175 if not renpy.display.interface: 4176 return True 4177 4178 if not renpy.display.interface.mouse_focused: 4179 return False 4180 4181 return renpy.display.interface.is_mouse_visible() 4182 4183 4184def get_mouse_name(interaction=False): 4185 """ 4186 :doc: other 4187 4188 Returns the name of the mouse that should be shown. 4189 4190 4191 `interaction` 4192 If true, get a mouse name that is based on the type of interaction 4193 occuring. (This is rarely useful.) 4194 """ 4195 4196 if not renpy.display.interface: 4197 return 'default' 4198 4199 return renpy.display.interface.get_mouse_name(interaction=interaction) 4200 4201 4202def set_focus(screen, id, layer="screens"): # @ReservedAssignment 4203 """ 4204 :doc: screens 4205 4206 This attempts to focus the displayable with `id` in the screen `screen`. 4207 Focusing will fail if the displayable isn't found, the window isn't 4208 focused, or something else is grabbing focus. 4209 4210 The focus may change if the mouse moves, even slightly, after this call 4211 is processed. 4212 """ 4213 4214 renpy.display.focus.override = (screen, id, layer) 4215 renpy.display.interface.last_event = None 4216 restart_interaction() 4217 4218 4219def check_permission(permission): 4220 """ 4221 :doc: android_permission 4222 4223 Checks to see if an Android permission has been granted to this application. 4224 4225 `permission` 4226 A string giving the name of the permission, for example, "android.permission.WRITE_EXTERNAL_STORAGE". 4227 4228 Returns true if the permission has been granted, false if it has not or if called on 4229 a non-Android platform. 4230 """ 4231 4232 if not renpy.android: 4233 return False 4234 4235 from jnius import autoclass 4236 PythonSDLActivity = autoclass("org.renpy.android.PythonSDLActivity") 4237 activity = PythonSDLActivity.mActivity 4238 4239 try: 4240 return activity.checkSelfPermission(permission) == 0 # PackageManager.PERMISSION_GRANTED 4241 except: 4242 return False 4243 4244 4245def request_permission(permission): 4246 """ 4247 :doc: android_permission 4248 4249 Asks Android to grant a permission to this application. The user may be 4250 prompted to grant the permission. 4251 4252 `permission` 4253 A string giving the name of the permission, for example, "android.permission.WRITE_EXTERNAL_STORAGE". 4254 4255 Returns true if the permission has been granted, false if not or if called on a 4256 non-Android platform. 4257 """ 4258 4259 if not renpy.android: 4260 return False 4261 4262 return get_sdl_dll().SDL_AndroidRequestPermission(permission.encode("utf-8")) 4263