Compare commits
190 Commits
6.18.0.573
...
6.99
| Author | SHA1 | Date | |
|---|---|---|---|
| 366a09d708 | |||
| 3fe3df9f23 | |||
| e942545e39 | |||
| 9fe39eb8f3 | |||
| b1b17bd9cc | |||
| 1b34b59f5e | |||
| 719f06339c | |||
| 7abba42bca | |||
| c1120fc5b2 | |||
| 7d29b8968a | |||
| 994adf2ca5 | |||
| bd55020512 | |||
| b4f7d641b0 | |||
| 1197cff85b | |||
| 5e8fc44fb3 | |||
| 5df33b0f56 | |||
| fc9e826976 | |||
| e80d6f95a9 | |||
| 8815e5efb8 | |||
| 9874bc4dc3 | |||
| 82b597f62b | |||
| 4b35493447 | |||
| 69b203fbaa | |||
| 875a585e90 | |||
| 935d065712 | |||
| c0c44896a8 | |||
| b7a9266bf3 | |||
| 8bf5f05270 | |||
| 996d3c2fd6 | |||
| f68a4caec2 | |||
| f06e5861e7 | |||
| a93f4f1f76 | |||
| 572054c6e1 | |||
| bc3f659f4b | |||
| db63d0db4e | |||
| e7424e1140 | |||
| c345b6a84c | |||
| 5fd9bbe651 | |||
| d19b49d418 | |||
| f5103f4bf9 | |||
| dc5357c7f2 | |||
| 61f940a2f2 | |||
| b38d0edb2c | |||
| 36834b094d | |||
| cefdc342b6 | |||
| 1c409025e1 | |||
| 29cbac1c95 | |||
| 596cc4e6b6 | |||
| 19d52e85f1 | |||
| 75789bb8f2 | |||
| 55c00a86aa | |||
| 3f4f86f0fd | |||
| 81c3e0c28e | |||
| dc058298f7 | |||
| 4609a1139c | |||
| 9b5cb37b74 | |||
| ff0893155d | |||
| 127f46c1d9 | |||
| 2edea5b052 | |||
| a256ed1c1e | |||
| 54d8b5733c | |||
| d59e6d0d45 | |||
| 66d3fbd6b0 | |||
| f83f217385 | |||
| c0b6d2dd3e | |||
| 42e6d3f368 | |||
| 9e3d1db244 | |||
| 8f0d132104 | |||
| 3813f0dc26 | |||
| 1cb04cd09f | |||
| fa8d11a13c | |||
| c9c74ec020 | |||
| cccd957545 | |||
| 938a6f3fa8 | |||
| ad2763a460 | |||
| 779912dd80 | |||
| f058d56d0f | |||
| c081ad9f78 | |||
| bbd505b378 | |||
| 1382c299fb | |||
| 84429c3826 | |||
| 971e33aa97 | |||
| 9cf92c7f34 | |||
| 20ca7fb463 | |||
| 5834069ddf | |||
| ee2dc4aaea | |||
| 7057ce19a1 | |||
| a190738a24 | |||
| 60a9589a80 | |||
| 2ea6291b0d | |||
| 4bd9c96d9c | |||
| 46c1f8067c | |||
| 4deae69732 | |||
| ac09cb8363 | |||
| b397f4b235 | |||
| 389749b221 | |||
| 2da32702fe | |||
| f6b2161ac9 | |||
| 6343c2cd6b | |||
| 7960b6b7be | |||
| f9875d9bad | |||
| 72027f7f69 | |||
| da532392d9 | |||
| b1a392e171 | |||
| 252baf8f1e | |||
| 75d41125a1 | |||
| 76c7c2aa86 | |||
| 61466cf927 | |||
| 2befad5da1 | |||
| c1c046788b | |||
| 1af82edd66 | |||
| 6a9835ad43 | |||
| 5402d84831 | |||
| b30e7de686 | |||
| 312d64b361 | |||
| 8bfb4d9f00 | |||
| 7253663eff | |||
| df6e8db1f1 | |||
| 7bc51c30db | |||
| d2aa4adfe4 | |||
| f29df20878 | |||
| 57e935e1f4 | |||
| 88cb519b4d | |||
| 4a9becb351 | |||
| 0a4e788349 | |||
| ed9f598098 | |||
| 529bb95a43 | |||
| d8a945095e | |||
| 77b65c7778 | |||
| 2ed8af936c | |||
| 3ecf7cf565 | |||
| 0902ccd28b | |||
| 2a217bf064 | |||
| 3243f4c3ac | |||
| 4cf2921310 | |||
| 53fc982bba | |||
| 8a88c6d6f9 | |||
| 136e31ada7 | |||
| dfe32a1339 | |||
| bab6f8afc6 | |||
| c0ea8ebcf2 | |||
| 033fcbbeaf | |||
| a2398afaf1 | |||
| cacef7e71a | |||
| 54f9662bc0 | |||
| 0fea7ee77c | |||
| 1c71db539e | |||
| e8a0b8413d | |||
| e192814d02 | |||
| 066a6a6185 | |||
| 4034f87f26 | |||
| 3ee319ba9e | |||
| 4c094852e8 | |||
| a4aef8ceb1 | |||
| 5794e8b3b7 | |||
| 3ab4f62cf8 | |||
| 7f70d22344 | |||
| 4a7ca192e9 | |||
| 74fce0049c | |||
| 22397c225f | |||
| 8f80e828c7 | |||
| c901b4c1bd | |||
| 2f1455351d | |||
| 83c7eef6c8 | |||
| f29ab675ec | |||
| d4e1a1d1f3 | |||
| cede3f651d | |||
| 4ed0c8e313 | |||
| ba4c6d8b10 | |||
| 87f2975dd0 | |||
| 15717d87af | |||
| 59174e44fb | |||
| b6778f1a9e | |||
| e693038479 | |||
| f1cae21fdb | |||
| 33e557c04f | |||
| 32773f3832 | |||
| 32a6de49c9 | |||
| 64f6038b52 | |||
| 813ef90eb2 | |||
| 3ef409b4f2 | |||
| 34ad1df5b2 | |||
| 41afb8e5b2 | |||
| 15e0d57277 | |||
| 04ce5eaf09 | |||
| 130d92c5a2 | |||
| 504f2ff708 | |||
| 99f44f7eff | |||
| 0a95f50724 | |||
| 4da7ac8af7 |
+10
-1
@@ -7,6 +7,7 @@ http://www.renpy.org
|
||||
Ren'Py development takes place on the ``master`` branch, and occasionally
|
||||
on feature branches.
|
||||
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
@@ -132,10 +133,18 @@ For example::
|
||||
renpy.engine.warp_drive.engage(factor)
|
||||
|
||||
|
||||
Translating
|
||||
===========
|
||||
|
||||
For best practices when it comes to translating the launcher and template
|
||||
game, please read:
|
||||
|
||||
http://lemmasoft.renai.us/forums/viewtopic.php?p=321603#p321603
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
For bug fixes, documentation improvements, and simple changes, just
|
||||
make a pull request. For more complex changes, it might make sense
|
||||
to file an issue first so we can discuss the design.
|
||||
|
||||
|
||||
@@ -92,6 +92,11 @@ def main():
|
||||
|
||||
print "Version {} ({})".format(args.version, full_version)
|
||||
|
||||
# Perhaps autobuild.
|
||||
if "RENPY_BUILD_ALL" in os.environ:
|
||||
print("Autobuild...")
|
||||
subprocess.check_call(["scripts/autobuild.sh"])
|
||||
|
||||
# Copy over the screens, to keep them up to date.
|
||||
copy_tutorial_file("tutorial/game/screens.rpy", "templates/english/game/screens.rpy")
|
||||
|
||||
|
||||
@@ -234,6 +234,8 @@ init python:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
|
||||
self.yes_thread = None
|
||||
|
||||
try:
|
||||
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action)
|
||||
|
||||
@@ -241,7 +243,12 @@ init python:
|
||||
if yes:
|
||||
kwargs["stdin"] = subprocess.PIPE
|
||||
|
||||
self.process = subprocess.Popen(cmd, cwd=RAPT_PATH, stdout=f, stderr=f, startupinfo=startupinfo, **kwargs)
|
||||
try:
|
||||
self.process = subprocess.Popen(cmd, cwd=RAPT_PATH, stdout=f, stderr=f, startupinfo=startupinfo, **kwargs)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc(file=f)
|
||||
raise
|
||||
|
||||
if yes:
|
||||
import threading
|
||||
@@ -260,6 +267,7 @@ init python:
|
||||
self.yes_thread.join()
|
||||
|
||||
self.process = None
|
||||
self.yes_thread = None
|
||||
|
||||
def check_process(self):
|
||||
rv = self.process.poll()
|
||||
|
||||
@@ -85,6 +85,12 @@ init python:
|
||||
return theme, scheme
|
||||
|
||||
def implement_theme(theme, scheme):
|
||||
"""
|
||||
Implement the current theme.
|
||||
|
||||
This function uses non-public APIs.
|
||||
"""
|
||||
|
||||
global showing_theme, showing_scheme
|
||||
|
||||
if theme == showing_theme and scheme == showing_scheme:
|
||||
@@ -92,7 +98,12 @@ init python:
|
||||
|
||||
renpy.style.restore(style_backup)
|
||||
exec theme_data.THEME[theme][scheme] in globals()
|
||||
renpy.style.rebuild()
|
||||
|
||||
# Rebuild the style cache.
|
||||
renpy.style.rebuild(False)
|
||||
|
||||
# Bust the render cache, so we re-evaluate the styles.
|
||||
renpy.display.interface.kill_textures()
|
||||
|
||||
showing_theme = theme
|
||||
showing_scheme = scheme
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -518,3 +518,11 @@ translate arabic strings:
|
||||
old "<repr() failed>"
|
||||
new "<repr() failed>"
|
||||
|
||||
# Translation updated at 2014-09-30 23:01
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:80
|
||||
old "Location"
|
||||
new "الموقع"
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
# Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
# game/editor.rpy:120
|
||||
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
|
||||
new "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
|
||||
new "{b}نقترح.{/b} محرر نص له واجهة سهلة الاستعمال ويعين على كتابة النصوص البرمجية يفضل برنامج يحتوي على مدقق لغوي. Editraحالياً لا يدعم اللغات الأجنبية مثل اللغه الكورية و الصينية و اليابانية."
|
||||
|
||||
# game/editor.rpy:121
|
||||
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
|
||||
new "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
|
||||
new "{b}نقترح.{/b} محرر نص له واجهة سهلة الاستعمال ويعين على كتابة النصوص البرمجية يفضل برنامج يحتوي على مدقق لغوي. Editraحالياً لا يدعم اللغات الأجنبية مثل اللغه الكورية و الصينية و اليابانية. على نظام لينوكس, Editra يحتاج wxPython."
|
||||
|
||||
# game/editor.rpy:137
|
||||
old "The may have occured because wxPython is not installed on this system."
|
||||
@@ -16,11 +16,11 @@ translate arabic strings:
|
||||
|
||||
# game/editor.rpy:144
|
||||
old "Up to 22 MB download required."
|
||||
new "Up to 22 MB download required."
|
||||
new "مطلوب تحميل ملف بحجم 22 ميغا بايت."
|
||||
|
||||
# game/editor.rpy:157
|
||||
old "1.8 MB download required."
|
||||
new "1.8 MB download required."
|
||||
new "مطلوب تحميل ملف بحجم 1.8 ميغا بايت."
|
||||
|
||||
# game/editor.rpy:158
|
||||
old "This may have occured because Java is not installed on this system."
|
||||
@@ -36,13 +36,13 @@ translate arabic strings:
|
||||
|
||||
# game/editor.rpy:393
|
||||
old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
|
||||
new ""
|
||||
new "محرر النصوص هو برنامج يساعدك على تعديل ملفات رينباي البرمجية والحوار. هنا, يمكنك اختيار المحرر الذي سيستعلمه رينباي. إذا لم يكن لديك مسبقاً, سيتم تحميله و تنصيبه بشكل اوتوماتيكي."
|
||||
|
||||
# game/editor.rpy:415
|
||||
old "Cancel"
|
||||
new "إلغاء الامر"
|
||||
|
||||
# TODO: Translation updated at 2013-11-17 23:18
|
||||
# Translation updated at 2013-11-17 23:18
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -94,3 +94,23 @@ translate arabic strings:
|
||||
old "[p.name!q] (template)"
|
||||
new "[p.name!q] (template)"
|
||||
|
||||
# Translation updated at 2014-09-30 23:01
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
# game/front_page.rpy:35
|
||||
old "Open [text] directory."
|
||||
new "فتح المجلد [text]"
|
||||
|
||||
# game/front_page.rpy:150
|
||||
old "Select project [text]."
|
||||
new "اختر المشروع [text]"
|
||||
|
||||
# game/front_page.rpy:234
|
||||
old "Force Recompile"
|
||||
new "إعادة حزم الملفات"
|
||||
|
||||
# game/front_page.rpy:285
|
||||
old "Recompiling all rpy files into rpyc files..."
|
||||
new "يتم إعادة حزم الملفات من صيغة rpy إلى rpyc..."
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
@@ -82,7 +81,6 @@ translate arabic strings:
|
||||
old "QUESTION"
|
||||
new "سؤال"
|
||||
|
||||
# TODO: Translation updated at 2013-11-17 23:18
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ translate arabic strings:
|
||||
old "Language:"
|
||||
new "اللغة:"
|
||||
|
||||
# : Translation updated at 2014-04-17 13:01
|
||||
# Translation updated at 2014-04-17 13:01
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
@@ -66,3 +66,19 @@ translate arabic strings:
|
||||
old "Show templates"
|
||||
new "عرض القوالب"
|
||||
|
||||
# Translation updated at 2014-09-30 23:01
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
# game/preferences.rpy:91
|
||||
old "Projects directory: [text]"
|
||||
new "مجلد المشاريع [text]"
|
||||
|
||||
# game/preferences.rpy:114
|
||||
old "Text editor: [text]"
|
||||
new "محرر النصوص [text]"
|
||||
|
||||
# game/preferences.rpy:171
|
||||
old "Large fonts"
|
||||
new "خط كبير"
|
||||
|
||||
|
||||
@@ -58,3 +58,11 @@ translate arabic strings:
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory. Please install the python-tk or tkinter package."
|
||||
new "رينباي لم يتمكن من تشغيل بايثون مع tkinter لكي يختار مجلد المشاريع, الرجاء تنصيب Python-tk او tkinter"
|
||||
|
||||
# Translation updated at 2014-09-30 23:01
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
# game/project.rpy:47
|
||||
old "Have you backed up your projects recently?"
|
||||
new "هل قمت بعمل نسخة احتياطية من مشاريعك مؤخراً؟"
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-04-30 07:54
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
@@ -22,7 +21,6 @@ translate arabic strings:
|
||||
old "Ren'Py has finished generating [language] translations."
|
||||
new "انتهى رينباي من صناعة ملفات الترجمة إلى [language]"
|
||||
|
||||
# TODO: Translation updated at 2013-11-17 23:18
|
||||
|
||||
translate arabic strings:
|
||||
|
||||
|
||||
@@ -166,7 +166,6 @@ translate german strings:
|
||||
old "It looks like you're ready to start packaging games."
|
||||
new "Es sieht aus, als wären Sie bereit, Spiele zu erstellen."
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 13:54
|
||||
|
||||
translate german strings:
|
||||
|
||||
@@ -179,7 +178,6 @@ translate german strings:
|
||||
old "Japanese"
|
||||
new "Japanese"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 14:07
|
||||
|
||||
translate german strings:
|
||||
|
||||
|
||||
@@ -451,7 +451,6 @@ translate japanese strings:
|
||||
old "Done"
|
||||
new "完了"
|
||||
|
||||
# TODO: Translation updated at 2014-07-08 18:59
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
@@ -491,3 +490,10 @@ translate japanese strings:
|
||||
old "<repr() failed>"
|
||||
new "<repr() 失敗>"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:273
|
||||
old "{b}Missing Images{/b}"
|
||||
new "{b}M画像が見付かりません{/b}"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:80
|
||||
old "Location"
|
||||
new "ファイル"
|
||||
|
||||
@@ -89,3 +89,19 @@ translate japanese strings:
|
||||
old "[p.name!q] (template)"
|
||||
new "[p.name!q] (テンプレート)"
|
||||
|
||||
# game/front_page.rpy:35
|
||||
old "Open [text] directory."
|
||||
new "[text] ディレクトリーを開きます。"
|
||||
|
||||
# game/front_page.rpy:150
|
||||
old "Select project [text]."
|
||||
new "プロジェクト [text] を選択します。"
|
||||
|
||||
# game/front_page.rpy:234
|
||||
old "Force Recompile"
|
||||
new "強制再コンパイル"
|
||||
|
||||
# game/front_page.rpy:285
|
||||
old "Recompiling all rpy files into rpyc files..."
|
||||
new "すべての rpy ファイルを rpyc ファイルにコンパイルしています。"
|
||||
|
||||
|
||||
@@ -65,3 +65,11 @@ translate japanese strings:
|
||||
old "Large fonts"
|
||||
new "フォントを大きくする"
|
||||
|
||||
# game/preferences.rpy:91
|
||||
old "Projects directory: [text]"
|
||||
new "プロジェクトディレクトリー: [text]"
|
||||
|
||||
# game/preferences.rpy:114
|
||||
old "Text editor: [text]"
|
||||
new "テキストエディター: [text]"
|
||||
|
||||
|
||||
@@ -53,3 +53,7 @@ translate japanese strings:
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory. Please install the python-tk or tkinter package."
|
||||
new "Ren'Pyはプロジェクトディレクトリー選択のためのtkinterをPythonの実行時に読み込めませんでした。python-tkもしくはtkinterパッケージをインストールして下さい。"
|
||||
|
||||
# game/project.rpy:47
|
||||
old "Have you backed up your projects recently?"
|
||||
new "最近ゲームのバックアップはしましたか?"
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ translate korean strings:
|
||||
old "Quick save complete."
|
||||
new "퀵세이브했습니다."
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -82,7 +81,6 @@ translate korean strings:
|
||||
old "jump <label>: jumps to label"
|
||||
new "jump <label>: label로 점프한다"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -106,7 +104,6 @@ translate korean strings:
|
||||
old "return"
|
||||
new "돌아가기"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -202,7 +199,6 @@ translate korean strings:
|
||||
old "Restart"
|
||||
new "다시 시작"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -214,7 +210,6 @@ translate korean strings:
|
||||
old "Autoreload"
|
||||
new "자동 다시 불러오기"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -254,7 +249,6 @@ translate korean strings:
|
||||
old "Are you sure you want to skip to unseen dialogue or the next choice?"
|
||||
new "읽지 않은 대사나 다음 선택지가 나타날 때까지 스킵하겠습니까?"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -266,7 +260,6 @@ translate korean strings:
|
||||
old "Fast Skip Mode"
|
||||
new "고속 스킵 모드"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -306,7 +299,6 @@ translate korean strings:
|
||||
old "The updates were cancelled."
|
||||
new "업데이트가 취소되었습니다."
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -322,7 +314,6 @@ translate korean strings:
|
||||
old "Next"
|
||||
new "앞으로"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -330,7 +321,6 @@ translate korean strings:
|
||||
old "Joystick Mapping"
|
||||
new "조이스틱 설정"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -398,7 +388,6 @@ translate korean strings:
|
||||
old "Done"
|
||||
new "완료"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -438,7 +427,6 @@ translate korean strings:
|
||||
old "<repr() failed>"
|
||||
new "<repr() 실패>"
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
@@ -494,7 +482,6 @@ translate korean strings:
|
||||
old "Opens the errors.txt file in a text editor."
|
||||
new "errors.txt 파일을 스크립트 에디터로 엽니다."
|
||||
|
||||
# TODO: Translation updated at 2014-05-02 21:49
|
||||
|
||||
translate korean strings:
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ translate russian strings:
|
||||
old "q"
|
||||
new "q"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -22,7 +21,6 @@ translate russian strings:
|
||||
old "Joystick Mapping"
|
||||
new "Назначение джойстика"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -34,7 +32,6 @@ translate russian strings:
|
||||
old "Quick save complete."
|
||||
new "Быстрое сохранение завершено."
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -74,7 +71,6 @@ translate russian strings:
|
||||
old "Are you sure you want to skip to unseen dialogue or the next choice?"
|
||||
new "Вы уверены, что хотите пропустить все до невиданного диалога или следующего выбора?"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -86,7 +82,6 @@ translate russian strings:
|
||||
old "Next"
|
||||
new "Следующий"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -94,7 +89,6 @@ translate russian strings:
|
||||
old "Saved screenshot as %s."
|
||||
new "Скришнот сохранен как %s."
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -134,7 +128,6 @@ translate russian strings:
|
||||
old "The updates were cancelled."
|
||||
new "Обновления были отменены."
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -230,7 +223,6 @@ translate russian strings:
|
||||
old "Restart"
|
||||
new "Перезапустить"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -254,7 +246,6 @@ translate russian strings:
|
||||
old "return"
|
||||
new "вернуться"
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -310,7 +301,6 @@ translate russian strings:
|
||||
old "Opens the errors.txt file in a text editor."
|
||||
new "Открывает файл errors.txt в текстовом редакторе."
|
||||
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -90,3 +89,22 @@ translate russian strings:
|
||||
old "Deleting persistent data..."
|
||||
new "Удаление постоянных данных..."
|
||||
|
||||
|
||||
translate russian strings:
|
||||
|
||||
# game/front_page.rpy:35
|
||||
old "Open [text] directory."
|
||||
new "Открыть папку [text]."
|
||||
|
||||
# game/front_page.rpy:150
|
||||
old "Select project [text]."
|
||||
new "Выбрать проект [text]."
|
||||
|
||||
# game/front_page.rpy:234
|
||||
old "Force Recompile"
|
||||
new "Перекомпилировать проект"
|
||||
|
||||
# game/front_page.rpy:285
|
||||
old "Recompiling all rpy files into rpyc files..."
|
||||
new "Перекомпиляция всех файлов rpy в файлы rpyc..."
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# TODO: Translation updated at 2013-12-08 21:52
|
||||
|
||||
translate russian strings:
|
||||
|
||||
@@ -62,3 +61,18 @@ translate russian strings:
|
||||
old "Language:"
|
||||
new "Язык:"
|
||||
|
||||
|
||||
translate russian strings:
|
||||
|
||||
# game/preferences.rpy:91
|
||||
old "Projects directory: [text]"
|
||||
new "Папка проектов: [text]"
|
||||
|
||||
# game/preferences.rpy:114
|
||||
old "Text editor: [text]"
|
||||
new "Текстовый редактор: [text]"
|
||||
|
||||
# game/preferences.rpy:171
|
||||
old "Large fonts"
|
||||
new "Большие шрифты"
|
||||
|
||||
|
||||
@@ -497,3 +497,11 @@ translate spanish strings:
|
||||
old "Autoreload"
|
||||
new "Autorecarga"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:80
|
||||
old "Location"
|
||||
new "Ubicación"
|
||||
|
||||
# renpy/common/00preferences.rpy:373
|
||||
old "Self-voicing enabled. Press 'v' to disable."
|
||||
new "Self-voicing activado. Presiona 'v' para desactivarlo."
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
DroidSansFallback.ttf is destributed under Apache License 2.0.
|
||||
--------------------------------
|
||||
Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
##########
|
||||
|
||||
This directory contains the fonts for the platform. They are licensed
|
||||
under the Apache 2 license.
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/about.rpy:21
|
||||
old "[version!q]"
|
||||
new "[version!q]"
|
||||
|
||||
# game/about.rpy:25
|
||||
old "View license"
|
||||
new "檢視許可證"
|
||||
|
||||
# game/about.rpy:27
|
||||
old "Back"
|
||||
new "返回"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/add_file.rpy:7
|
||||
old "FILENAME"
|
||||
new "檔案名稱"
|
||||
|
||||
# game/add_file.rpy:7
|
||||
old "Enter the name of the script file to create."
|
||||
new "請輸入需要建立的腳本名稱。"
|
||||
|
||||
# game/add_file.rpy:10
|
||||
old "The filename must have the .rpy extension."
|
||||
new "檔案名稱必須以 .rpy 為副檔名。"
|
||||
|
||||
# game/add_file.rpy:18
|
||||
old "The file already exists."
|
||||
new "該檔已存在。"
|
||||
|
||||
# game/add_file.rpy:21
|
||||
old "# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n"
|
||||
new "# Ren'Py 將自動載入以 .rpy 結尾的腳本。若要使用\n# 檔案,從其它檔案中定義一個標籤跳轉到該檔案。\n"
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/android.rpy:13
|
||||
old "A 32-bit Java Development Kit is required to build Android packages on Windows. The JDK is different from the JRE, so it's possible you have Java without having the JDK.\n\nPlease {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}download and install the JDK{/a}, then restart the Ren'Py launcher."
|
||||
new "需要一個32位元的 Java 開發套件(JDK)來在 Windows 中建立 Android 套件。JDK 不同於 JRE,所以您可能有 Java 但不包含 JDK。\n\n請 {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html} 下載和安裝 JDK{/a},然後重新啟動 Ren'Py 啟動器。"
|
||||
|
||||
# game/android.rpy:14
|
||||
old "To build Android packages, please download RAPT (from {a=http://www.renpy.org/dl/android}here{/a}), unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
|
||||
new "要建立 Android 套件,請下載 RAPT(從{a=http://www.renpy.org/dl/android}這裡{/a}下載),解壓縮到 Ren'Py 目錄下。然後重新啟動 Ren'Py 啟動器。"
|
||||
|
||||
# game/android.rpy:15
|
||||
old "RAPT has been installed, but you'll need to install the Android SDK before you can build Android packages. Choose Install SDK to do this."
|
||||
new "RAPT 已經安裝了,但是您還需要安裝 Android SDK 才可以建立 Android 套件。選擇安裝 SDK 來實現它。"
|
||||
|
||||
# game/android.rpy:16
|
||||
old "RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore."
|
||||
new "RAPT 已經安裝了,但是 KEY 尚未設定。請建立一個新的 KEY,或者恢複 android.keystore。"
|
||||
|
||||
# game/android.rpy:17
|
||||
old "The current project has not been configured. Use \"Configure\" to configure it before building."
|
||||
new "當前專案尚未配置。使用「設定」,在建設之前配置它。"
|
||||
|
||||
# game/android.rpy:18
|
||||
old "Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device."
|
||||
new "選擇「建立」來建立當前專案,或者選擇「建立並安裝」來添加到一個 Android 裝置中建立並安裝。"
|
||||
|
||||
# game/android.rpy:20
|
||||
old "Attempts to emulate an Android phone.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
|
||||
new "模擬一臺 Android 手機。\n\n當按鈕被按下時,觸控輸入會模擬為滑鼠。Esc 按鍵映射為手機的選單鍵,PageUp 鍵映射為手機的返回鍵。"
|
||||
|
||||
# game/android.rpy:21
|
||||
old "Attempts to emulate an Android tablet.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
|
||||
new "模擬一個 Android 平板。\n\n當按鈕被按下時,觸控輸入會模擬為滑鼠。Esc 按鍵映射為平板的選單鍵,PageUp 鍵映射為平板的返回鍵。"
|
||||
|
||||
# game/android.rpy:22
|
||||
old "Attempts to emulate an OUYA console.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
|
||||
new "模擬一個 OUYA 控制器。\n\n控制器的按鍵映射為 OUYA 的方向鍵,確認鍵映射為 OUYA 的 select 按鍵,Esc 按鍵映射為 OUYA 的選單鍵,PageUp 按鍵被映射到 OUYA 的返回鍵。"
|
||||
|
||||
# game/android.rpy:24
|
||||
old "Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package."
|
||||
new "下載和安裝 Android SDK 以及支援套件。可選擇性地設定產生金鑰來簽署套件。"
|
||||
|
||||
# game/android.rpy:25
|
||||
old "Configures the package name, version, and other information about this project."
|
||||
new "設定套件名稱,版本以及其它關於專案的資訊。"
|
||||
|
||||
# game/android.rpy:26
|
||||
old "Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details."
|
||||
new "在編輯器中開啟包含 Google Play keys 的檔案。\n\n這是在應用程式需要一個擴展的 APK 套件時才需要。閱讀檔案來瞭解更多細節。"
|
||||
|
||||
# game/android.rpy:27
|
||||
old "Builds the Android package."
|
||||
new "建立 Android 套件。"
|
||||
|
||||
# game/android.rpy:28
|
||||
old "Builds the Android package, and installs it on an Android device connected to your computer."
|
||||
new "建立 Android 套件,並安裝到已連線到電腦的 Android 裝置中。"
|
||||
|
||||
# game/android.rpy:148
|
||||
old "{a=%s}%s{/a}"
|
||||
new "{a=%s}%s{/a}"
|
||||
|
||||
# game/android.rpy:371
|
||||
old "Android: [project.current.name!q]"
|
||||
new "Android: [project.current.name!q]"
|
||||
|
||||
# game/android.rpy:391
|
||||
old "Emulation:"
|
||||
new "模擬:"
|
||||
|
||||
# game/android.rpy:399
|
||||
old "Phone"
|
||||
new "手機"
|
||||
|
||||
# game/android.rpy:403
|
||||
old "Tablet"
|
||||
new "平板"
|
||||
|
||||
# game/android.rpy:407
|
||||
old "Television / OUYA"
|
||||
new "電視/OUYA"
|
||||
|
||||
# game/android.rpy:419
|
||||
old "Build:"
|
||||
new "建立:"
|
||||
|
||||
# game/android.rpy:427
|
||||
old "Install SDK & Create Keys"
|
||||
new "安裝 SDK 並創建金鑰"
|
||||
|
||||
# game/android.rpy:431
|
||||
old "Configure"
|
||||
new "設定"
|
||||
|
||||
# game/android.rpy:516
|
||||
old "Other:"
|
||||
new "其他:"
|
||||
|
||||
# game/android.rpy:435
|
||||
old "Build Package"
|
||||
new "建立套件"
|
||||
|
||||
# game/android.rpy:439
|
||||
old "Build & Install"
|
||||
new "建立並安裝"
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/android.rpy:30
|
||||
old "To build Android packages, please download RAPT, unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
|
||||
new "要建立 Android 套件,請下載 RAPT,解壓縮並將其放到 Ren'Py 目錄下,然後重新啟動 Ren'Py 啟動器。"
|
||||
|
||||
# game/android.rpy:506
|
||||
old "Before packaging Android apps, you'll need to download RAPT, the Ren'Py Android Packaging Tool. Would you like to download RAPT now?"
|
||||
new "在包裝 Android 應用程式前,您必須下載 RAPT(Ren'Py Android Packaging Tool),Ren'Py 的 Android 包裝程式。您要現在下載 RAPT 嗎?"
|
||||
|
||||
# game/android.rpy:39
|
||||
old "Attempts to emulate a televison-based Android console, like the OUYA or Fire TV.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
|
||||
new "模擬一臺基於 Android 的電視,例如 OUYA 或 Fire TV。\n\n控制器的按鍵映射為 OUYA 的方向鍵,確認鍵映射為 OUYA 的 select 按鍵,Esc 按鍵映射為 OUYA 的選單鍵,PageUp 按鍵被映射到 OUYA 的返回鍵。"
|
||||
|
||||
# game/android.rpy:524
|
||||
old "Remote ADB Connect"
|
||||
new "遠端 ADB 連接"
|
||||
|
||||
# game/android.rpy:528
|
||||
old "Remote ADB Disconnect"
|
||||
new "斷開遠端 ADB 連接"
|
||||
|
||||
# game/android.rpy:608
|
||||
old "Remote ADB Address"
|
||||
new "遠端 ADB 位址"
|
||||
|
||||
# game/android.rpy:609
|
||||
old "Please enter the IP address and port number to connect to, in the form \"192.168.1.143:5555\". Consult your device's documentation to determine if it supports remote ADB, and if so, the address and port to use."
|
||||
new "\"192.168.1.143:5555\" 是連接裝置的 IP 位址和埠的輸入形式。請鍵入裝置的 IP 位址和埠來連接。注意,確保裝置支援遠端 ADB,然後鍵入位址和埠來使用。"
|
||||
|
||||
# game/android.rpy:619
|
||||
old "Invalid remote ADB address"
|
||||
new "遠端 ADB 位址無效"
|
||||
|
||||
# game/android.rpy:619
|
||||
old "The address must contain one exactly one ':'."
|
||||
new "位址必須包含一個精確的 ':'。"
|
||||
|
||||
# game/android.rpy:623
|
||||
old "The host may not contain whitespace."
|
||||
new "主機位址不能包含空格。"
|
||||
|
||||
# game/android.rpy:629
|
||||
old "The port must be a number."
|
||||
new "埠必須是數位。"
|
||||
|
||||
# game/android.rpy:47
|
||||
old "Connects to an Android device running ADB in TCP/IP mode."
|
||||
new "在 TCP/IP 模式下運行 ADB Android 裝置。"
|
||||
|
||||
# game/android.rpy:48
|
||||
old "Disconnects from an Android device running ADB in TCP/IP mode."
|
||||
new "在 TCP/IP 模式下運行 ADB Android 裝置,並斷開連接。"
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/choose_theme.rpy:274
|
||||
old "Could not change the theme. Perhaps options.rpy was changed too much."
|
||||
new "無法更改介面主題。Options.rpy 也許改變了太多。"
|
||||
|
||||
# game/choose_theme.rpy:332
|
||||
old "Display"
|
||||
new "Display"
|
||||
|
||||
# game/choose_theme.rpy:333
|
||||
old "Window"
|
||||
new "Window"
|
||||
|
||||
# game/choose_theme.rpy:334
|
||||
old "Fullscreen"
|
||||
new "Fullscreen"
|
||||
|
||||
# game/choose_theme.rpy:335
|
||||
old "Planetarium"
|
||||
new "Planetarium"
|
||||
|
||||
# game/choose_theme.rpy:342
|
||||
old "Sound Volume"
|
||||
new "Sound Volume"
|
||||
|
||||
# game/choose_theme.rpy:376
|
||||
old "Choose Theme"
|
||||
new "Choose Theme"
|
||||
|
||||
# game/choose_theme.rpy:389
|
||||
old "Theme"
|
||||
new "介面主題"
|
||||
|
||||
# game/choose_theme.rpy:413
|
||||
old "Color Scheme"
|
||||
new "色彩配置"
|
||||
|
||||
# game/choose_theme.rpy:444
|
||||
old "Continue"
|
||||
new "繼續"
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00action_file.rpy:118
|
||||
old "%b %d, %H:%M"
|
||||
new "%%m月%d日, %H:%M"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00gltest.rpy:50
|
||||
old "Graphics Acceleration"
|
||||
new "圖形加速"
|
||||
|
||||
# renpy/common/00gltest.rpy:54
|
||||
old "Automatically Choose"
|
||||
new "自動選擇"
|
||||
|
||||
# renpy/common/00gltest.rpy:59
|
||||
old "Force Angle/DirectX Renderer"
|
||||
new "強制 Angle/DirectX 渲染"
|
||||
|
||||
# renpy/common/00gltest.rpy:63
|
||||
old "Force OpenGL Renderer"
|
||||
new "強制 OpenGL 渲染"
|
||||
|
||||
# renpy/common/00gltest.rpy:67
|
||||
old "Force Software Renderer"
|
||||
new "強制軟體渲染"
|
||||
|
||||
# renpy/common/00gltest.rpy:73
|
||||
old "Changes will take effect the next time this program is run."
|
||||
new "更改將會在下次啟動程式時生效。"
|
||||
|
||||
# renpy/common/00gltest.rpy:77
|
||||
old "Quit"
|
||||
new "離開"
|
||||
|
||||
# renpy/common/00gltest.rpy:82
|
||||
old "Return"
|
||||
new "返回"
|
||||
|
||||
# renpy/common/00gltest.rpy:112
|
||||
old "Performance Warning"
|
||||
new "效能警告"
|
||||
|
||||
# renpy/common/00gltest.rpy:117
|
||||
old "This computer is using software rendering."
|
||||
new "該電腦正在使用軟體渲染。"
|
||||
|
||||
# renpy/common/00gltest.rpy:119
|
||||
old "This computer is not using shaders."
|
||||
new "該電腦沒有使用著色器"
|
||||
|
||||
# renpy/common/00gltest.rpy:121
|
||||
old "This computer is displaying graphics slowly."
|
||||
new "該電腦圖形顯示緩慢。"
|
||||
|
||||
# renpy/common/00gltest.rpy:123
|
||||
old "This computer has a problem displaying graphics: [problem]."
|
||||
new "該電腦圖形顯示出錯:[problem]。"
|
||||
|
||||
# renpy/common/00gltest.rpy:128
|
||||
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
|
||||
new "目前的圖形驅動程式版本可能過舊或者運作不正確。這樣會導致圖形顯示緩慢或者錯誤。升級 DirectX 可能會解決該問題。"
|
||||
|
||||
# renpy/common/00gltest.rpy:130
|
||||
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
|
||||
new "目前圖形驅動程式版本可能過舊或者運作不正確。這樣會導致圖形顯示緩慢或者錯誤。"
|
||||
|
||||
# renpy/common/00gltest.rpy:135
|
||||
old "Update DirectX"
|
||||
new "更新 DirectX"
|
||||
|
||||
# renpy/common/00gltest.rpy:141
|
||||
old "Continue, Show this warning again"
|
||||
new "繼續,下次再顯示該警告"
|
||||
|
||||
# renpy/common/00gltest.rpy:145
|
||||
old "Continue, Don't show warning again"
|
||||
new "繼續,不再顯示該警告"
|
||||
|
||||
# renpy/common/00gltest.rpy:171
|
||||
old "Updating DirectX."
|
||||
new "正在更新 DirectX。"
|
||||
|
||||
# renpy/common/00gltest.rpy:175
|
||||
old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
|
||||
new "DirectX 線上安裝已啟動。將會最小化到狀態列中。請按照說明安裝 DirectX。"
|
||||
|
||||
# renpy/common/00gltest.rpy:179
|
||||
old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
|
||||
new "{b}警告:{/b} Microsoft's DirectX 線上安裝程式會預設安裝 Bing 瀏覽器工具列。如果您不需要安裝這個工具列,請取消勾選對應選項。"
|
||||
|
||||
# renpy/common/00gltest.rpy:183
|
||||
old "When setup finishes, please click below to restart this program."
|
||||
new "當安裝完成後請點選下方來重新啟動應用程式。"
|
||||
|
||||
# renpy/common/00gltest.rpy:185
|
||||
old "Restart"
|
||||
new "重新啟動"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00keymap.rpy:167
|
||||
old "Saved screenshot as %s."
|
||||
new "儲存螢幕截圖為 %s。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00layout.rpy:439
|
||||
old "Are you sure?"
|
||||
new "是否確認?"
|
||||
|
||||
# renpy/common/00layout.rpy:443
|
||||
old "Are you sure you want to quit?"
|
||||
new "您確定您要離開嗎?"
|
||||
|
||||
# renpy/common/00layout.rpy:444
|
||||
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
|
||||
new "您確定您想回到標題畫面嗎?\n這將使您失去所有未儲存的進度。"
|
||||
|
||||
# renpy/common/00layout.rpy:441
|
||||
old "Are you sure you want to overwrite your save?"
|
||||
new "您確定您要覆寫您的存檔?"
|
||||
|
||||
# renpy/common/00layout.rpy:442
|
||||
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
|
||||
new "載入將會失去所有未儲存的進度。\n您確定您要這麼做嗎?"
|
||||
|
||||
# renpy/common/00layout.rpy:440
|
||||
old "Are you sure you want to delete this save?"
|
||||
new "您確定您要刪掉這份存檔嗎?"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00library.rpy:77
|
||||
old "Skip Mode"
|
||||
new "跳過對話模式"
|
||||
|
||||
# renpy/common/00library.rpy:80
|
||||
old "Fast Skip Mode"
|
||||
new "快速跳過對話模式"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00updater.rpy:1258
|
||||
old "Updater"
|
||||
new "更新"
|
||||
|
||||
# renpy/common/00updater.rpy:1267
|
||||
old "This program is up to date."
|
||||
new "該程式已是最新版本。"
|
||||
|
||||
# renpy/common/00updater.rpy:1269
|
||||
old "[u.version] is available. Do you want to install it?"
|
||||
new "[u.version] 已釋出。是否確認安裝?"
|
||||
|
||||
# renpy/common/00updater.rpy:1271
|
||||
old "Preparing to download the updates."
|
||||
new "正在準備下載更新。"
|
||||
|
||||
# renpy/common/00updater.rpy:1273
|
||||
old "Downloading the updates."
|
||||
new "正在下載更新。"
|
||||
|
||||
# renpy/common/00updater.rpy:1275
|
||||
old "Unpacking the updates."
|
||||
new "解壓縮更新檔案。"
|
||||
|
||||
# renpy/common/00updater.rpy:1279
|
||||
old "The updates have been installed. The program will restart."
|
||||
new "該更新檔案已安裝,程式將會重新啟動。"
|
||||
|
||||
# renpy/common/00updater.rpy:1281
|
||||
old "The updates have been installed."
|
||||
new "已完成更新。"
|
||||
|
||||
# renpy/common/00updater.rpy:1283
|
||||
old "The updates were cancelled."
|
||||
new "已取消更新。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:180
|
||||
old "Empty Slot."
|
||||
new "空白欄位"
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:337
|
||||
old "Previous"
|
||||
new "上一頁"
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:344
|
||||
old "Next"
|
||||
new "下一頁"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_compat/preferences.rpym:411
|
||||
old "Joystick Mapping"
|
||||
new "遊戲桿映射"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_errorhandling.rpym:408
|
||||
old "An exception has occurred."
|
||||
new "發生一個異常狀況。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:434
|
||||
old "Rollback"
|
||||
new "回滾"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:436
|
||||
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
|
||||
new "嘗試回滾到先前的狀態,使您可以存檔或者選擇不同選項。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:439
|
||||
old "Ignore"
|
||||
new "忽略"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:441
|
||||
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
|
||||
new "忽略異常,讓您可以繼續。這通常會產生額外的錯誤。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:444
|
||||
old "Reload"
|
||||
new "重新載入"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:446
|
||||
old "Reloads the game from disk, saving and restoring game state if possible."
|
||||
new "從硬碟重新載入遊戲,請您儲存遊戲狀態。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:448
|
||||
old "Open Traceback"
|
||||
new "開啟回溯"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:450
|
||||
old "Opens the traceback.txt file in a text editor."
|
||||
new "在編輯器中開啟回溯檔案(traceback.txt)。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:456
|
||||
old "Quits the game."
|
||||
new "離開遊戲。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:483
|
||||
old "Parsing the script failed."
|
||||
new "解析腳本失敗。"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:510
|
||||
old "Open Parse Errors"
|
||||
new "開啟解析錯誤"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:512
|
||||
old "Opens the errors.txt file in a text editor."
|
||||
new "在編輯器中開啟解析錯誤檔案(errors.txt)。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_layout/classic_load_save.rpym:152
|
||||
old "a"
|
||||
new "a"
|
||||
|
||||
# renpy/common/_layout/classic_load_save.rpym:161
|
||||
old "q"
|
||||
new "q"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00action_file.rpy:587
|
||||
old "Quick save complete."
|
||||
new "快速儲存。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00gallery.rpy:521
|
||||
old "Image [index] of [count] locked."
|
||||
new "[count]個圖片中的第[index]個圖片被鎖定。"
|
||||
|
||||
# renpy/common/00gallery.rpy:539
|
||||
old "prev"
|
||||
new "上一頁"
|
||||
|
||||
# renpy/common/00gallery.rpy:540
|
||||
old "next"
|
||||
new "下一頁"
|
||||
|
||||
# renpy/common/00gallery.rpy:541
|
||||
old "slideshow"
|
||||
new "幻燈片"
|
||||
|
||||
# renpy/common/00gallery.rpy:542
|
||||
old "return"
|
||||
new "返回"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00layout.rpy:427
|
||||
old "Are you sure you want to begin skipping?"
|
||||
new "是否確定開始略過?"
|
||||
|
||||
# renpy/common/00layout.rpy:428
|
||||
old "Are you sure you want to skip to the next choice?"
|
||||
new "是否確定跳到下一個選項?"
|
||||
|
||||
# renpy/common/00layout.rpy:429
|
||||
old "Are you sure you want to skip to unseen dialogue or the next choice?"
|
||||
new "是否確定略過未看過的訊息或下一選項?"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/00console.rpy:179
|
||||
old "%(version)s console, originally by Shiz, C, and delta.\n"
|
||||
new "%(version)s 控制臺,作者: Shiz, C, delta。"
|
||||
|
||||
# renpy/common/00console.rpy:180
|
||||
old "Press <esc> to exit console. Type help for help.\n"
|
||||
new "按 <esc> 來退出控制臺。輸入 help 來檢視說明。\n"
|
||||
|
||||
# renpy/common/00console.rpy:184
|
||||
old "Ren'Py script enabled."
|
||||
new "使用 Ren'Py 腳本。"
|
||||
|
||||
# renpy/common/00console.rpy:186
|
||||
old "Ren'Py script disabled."
|
||||
new "禁用 Ren'Py 腳本。"
|
||||
|
||||
# renpy/common/00console.rpy:392
|
||||
old "help: show this help"
|
||||
new "help: 顯示說明資訊"
|
||||
|
||||
# renpy/common/00console.rpy:397
|
||||
old "commands:\n"
|
||||
new "命令列:\n"
|
||||
|
||||
# renpy/common/00console.rpy:407
|
||||
old " <renpy script statement>: run the statement\n"
|
||||
new " <renpy script statement>:運行語句\n"
|
||||
|
||||
# renpy/common/00console.rpy:409
|
||||
old " <python expression or statement>: run the expression or statement"
|
||||
new " <python expression or statement>:運行運算式或語句"
|
||||
|
||||
# renpy/common/00console.rpy:417
|
||||
old "clear: clear the console history"
|
||||
new "clear: 清除控制臺歷史記錄"
|
||||
|
||||
# renpy/common/00console.rpy:421
|
||||
old "exit: exit the console"
|
||||
new "exit: 離開控制臺"
|
||||
|
||||
# renpy/common/00console.rpy:429
|
||||
old "load <slot>: loads the game from slot"
|
||||
new "load <slot>:載入遊戲存檔(以 slot 為存檔號)"
|
||||
|
||||
# renpy/common/00console.rpy:442
|
||||
old "save <slot>: saves the game in slot"
|
||||
new "save <slot>:儲存遊戲存檔(以 slot 為存檔號)"
|
||||
|
||||
# renpy/common/00console.rpy:453
|
||||
old "reload: reloads the game, refreshing the scripts"
|
||||
new "reload: 重新載入遊戲,並重新整理腳本"
|
||||
|
||||
# renpy/common/00console.rpy:461
|
||||
old "watch <expression>: watch a python expression"
|
||||
new "watch <expression>: 監視一個 python 運算式"
|
||||
|
||||
# renpy/common/00console.rpy:470
|
||||
old "unwatch <expression>: stop watching an expression"
|
||||
new "unwatch <expression>:停止監視某個運算式"
|
||||
|
||||
# renpy/common/00console.rpy:478
|
||||
old "unwatchall: stop watching all expressions"
|
||||
new "unwatchall:停止監視索引運算式"
|
||||
|
||||
# renpy/common/00console.rpy:484
|
||||
old "jump <label>: jumps to label"
|
||||
new "jump <label>: 跳移至標籤"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_developer/developer.rpym:65
|
||||
old "Developer Menu"
|
||||
new "開發者選單"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:67
|
||||
old "Reload Game (Shift+R)"
|
||||
new "重新載入遊戲(Shift+R)"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:69
|
||||
old "Console (Shift+O)"
|
||||
new "控制臺(Shift+O)"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:71
|
||||
old "Variable Viewer"
|
||||
new "變數觀察器"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:73
|
||||
old "Theme Test"
|
||||
new "介面主題測試"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:75
|
||||
old "Image Location Picker"
|
||||
new "圖片座標撿選器"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:77
|
||||
old "Filename List"
|
||||
new "檔案清單"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:81
|
||||
old "Show Image Load Log"
|
||||
new "顯示圖片載入記錄"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:84
|
||||
old "Hide Image Load Log"
|
||||
new "隱藏圖片載入記錄"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:149
|
||||
old "No variables have changed since the game started."
|
||||
new "遊戲開始至此沒有任何變數被改變。"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:152
|
||||
old "Return to the developer menu"
|
||||
new "回到開發者選單"
|
||||
|
||||
# renpy/c72
|
||||
old "{b}Missing Images{/b}"
|
||||
new "{b}丟失圖片{/b}"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:424
|
||||
old "Rectangle: %r"
|
||||
new "矩形區域:%r"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:429
|
||||
old "Mouse position: %r"
|
||||
new "滑鼠位置:%r"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:431
|
||||
old "Right-click or escape to quit."
|
||||
new "點選滑鼠右鍵或者按 ESC 鍵來退出。"
|
||||
|
||||
# renpy/common/_developer/developer.rpym:482
|
||||
old "Done"
|
||||
new "完成"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:43
|
||||
old "Displayable Inspector"
|
||||
new "Displayable 檢閱器"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:49
|
||||
old "Nothing to inspect."
|
||||
new "沒有東西被檢閱"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:58
|
||||
old "Size"
|
||||
new "大小"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:63
|
||||
old "Style"
|
||||
new "風格"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:123
|
||||
old "Inspecting Styles of [displayable_name!q]"
|
||||
new "檢閱[displayable_name!q]的風格"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:135
|
||||
old "displayable:"
|
||||
new "displayable"
|
||||
# renpy/common/_developer/inspector.rpym:142
|
||||
old " (no properties affect the displayable)"
|
||||
new " (沒有偏好的可顯示屬性)"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:144
|
||||
old " (default properties omitted)"
|
||||
new " (忽略預設屬性)"
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:174
|
||||
old "<repr() failed>"
|
||||
new "<repr() failed>"
|
||||
|
||||
|
||||
|
||||
|
||||
# Translation updated at 2014-10-18 06:00
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# renpy/common/_developer/inspector.rpym:80
|
||||
old "Location"
|
||||
new "位置"
|
||||
|
||||
# renpy/common/00preferences.rpy:373
|
||||
old "Self-voicing enabled. Press 'v' to disable."
|
||||
new "Self-voicing 啟用。可按下 'v' 來禁用。"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/distribute.rpy:333
|
||||
old "Nothing to do."
|
||||
new "什麼都不做。"
|
||||
|
||||
# game/distribute.rpy:337
|
||||
old "Scanning project files..."
|
||||
new "掃描專案檔案..."
|
||||
|
||||
# game/distribute.rpy:344
|
||||
old "Scanning Ren'Py files..."
|
||||
new "掃描 Ren'Py 檔案..."
|
||||
|
||||
# game/distribute.rpy:494
|
||||
old "Archiving files..."
|
||||
new "壓縮檔案..."
|
||||
|
||||
# game/distribute.rpy:745
|
||||
old "Writing the [variant] [format] package."
|
||||
new "寫入 [variant] [format] 套件。"
|
||||
|
||||
# game/distribute.rpy:758
|
||||
old "Making the [variant] update zsync file."
|
||||
new "新增 [variant] 更新 zsync 檔案。"
|
||||
|
||||
# game/distribute.rpy:854
|
||||
old "Processed {b}[complete]{/b} of {b}[total]{/b} files."
|
||||
new "完成處理 {b}[complete]{/b} ,共 {b}[total]{/b}個檔案。"
|
||||
|
||||
# game/distribute.rpy:915
|
||||
old "All packages have been built.\n\nDue to the presence of permission information, unpacking and repacking the Linux and Macintosh distributions on Windows is not supported."
|
||||
new "所有套件已被建立。\n\n由於含有授權資訊存在,因此在 Windows 中不支援解開和重新包裝 Linux 及 Mac 的套件。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/distribute.rpy:358
|
||||
old "No packages are selected, so there's nothing to do."
|
||||
new "沒有選擇套件,沒有可以處理的事情。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/distribute.rpy:335
|
||||
old "Building distributions failed:\n\nThe build.directory_name variable may not include the space, colon, or semicolon characters."
|
||||
new "建立釋出版失敗:\n\n build.directory_name 變數可能包含空格,冒號或分號。"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/distribute_gui.rpy:139
|
||||
old "Build Distributions: [project.current.name!q]"
|
||||
new "建立釋出版:[project.current.name!q]"
|
||||
|
||||
# game/distribute_gui.rpy:154
|
||||
old "Directory Name:"
|
||||
new "目錄名稱:"
|
||||
|
||||
# game/distribute_gui.rpy:158
|
||||
old "Executable Name:"
|
||||
new "執行檔案名稱:"
|
||||
|
||||
# game/distribute_gui.rpy:167
|
||||
old "Actions:"
|
||||
new "動作:"
|
||||
|
||||
# game/distribute_gui.rpy:175
|
||||
old "Edit options.rpy"
|
||||
new "編輯 options.rpy"
|
||||
|
||||
# game/distribute_gui.rpy:176
|
||||
old "Refresh"
|
||||
new "重新整理"
|
||||
|
||||
# game/distribute_gui.rpy:193
|
||||
old "Build Packages:"
|
||||
new "建立套件:"
|
||||
|
||||
# game/distribute_gui.rpy:208
|
||||
old "Build Updates"
|
||||
new "建立更新檔"
|
||||
|
||||
# game/distribute_gui.rpy:212
|
||||
old "Build"
|
||||
new "建立"
|
||||
|
||||
# game/distribute_gui.rpy:219
|
||||
old "Errors were detected when running the project. Please ensure the project runs without errors before building distributions."
|
||||
new "當運行專案時發生了錯誤。在開始釋出前請確保專案運行無誤。"
|
||||
|
||||
# game/distribute_gui.rpy:236
|
||||
old "Your project does not contain build information. Would you like to add build information to the end of options.rpy?"
|
||||
new "您的專案不包含建置資訊。是否加入建置資訊到 options.rpy?"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/editor.rpy:120
|
||||
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
|
||||
new "{b}推薦{/b} 一個有簡單易用介面和功能的測試版編輯器能夠幫助開發,例如拼字的校對功能。Editra 目前缺乏中文、日文,韓文的輸入的 IME 支援。"
|
||||
|
||||
# game/editor.rpy:121
|
||||
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
|
||||
new "{b}推薦{/b} 一個有簡單易用的介面和功能的測試版編輯器能夠幫助開發,例如拼字的校對功能。Editra 現在沒有中文,日文,韓文的輸入功能。在 linux 中 Editra 需要 wxPython(模組支援)。"
|
||||
|
||||
# game/editor.rpy:137
|
||||
old "The may have occured because wxPython is not installed on this system."
|
||||
new "這可能是由於 wxPython 未安裝在此系統中而出現的。"
|
||||
|
||||
# game/editor.rpy:144
|
||||
old "Up to 22 MB download required."
|
||||
new "22 MB 需要下載。"
|
||||
|
||||
# game/editor.rpy:157
|
||||
old "1.8 MB download required."
|
||||
new "1.8 MB 需要下載。"
|
||||
|
||||
# game/editor.rpy:158
|
||||
old "This may have occured because Java is not installed on this system."
|
||||
new "這可能是由於 Java 未安裝在此系統中而出現的。"
|
||||
|
||||
# game/editor.rpy:327
|
||||
old "An exception occured while launching the text editor:\n[exception!q]"
|
||||
new "啟動以下編輯器出現異常:\n[exception!q]"
|
||||
|
||||
# game/editor.rpy:378
|
||||
old "Select Editor"
|
||||
new "選擇編輯器"
|
||||
|
||||
# game/editor.rpy:393
|
||||
old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
|
||||
new "文字編輯器是您用於編輯 Ren'py 腳本的程式。在這裡您可以選擇 Ren'py 會使用到編輯器。如果選定則編輯器將會自動下載並安裝。"
|
||||
|
||||
# game/editor.rpy:415
|
||||
old "Cancel"
|
||||
new "取消"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/editor.rpy:155
|
||||
old "A mature editor that requires Java."
|
||||
new "一個成熟的編輯器,它需要 Java。"
|
||||
|
||||
# game/editor.rpy:164
|
||||
old "Invokes the editor your operating system has associated with .rpy files."
|
||||
new "調用作業系統已與 .rpy 檔案關聯的編輯器。"
|
||||
|
||||
# game/editor.rpy:180
|
||||
old "Prevents Ren'Py from opening a text editor."
|
||||
new "防止 Ren'Py 開啟文字編輯器。"
|
||||
|
||||
# Translation updated at 2014-10-18 06:00
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/editor.rpy:167
|
||||
old "This may have occured because wxPython is not installed on this system."
|
||||
new "這可能是因為 wxPython 沒有被安裝在當前系統中而發生的。"
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/front_page.rpy:79
|
||||
old "+ Create New Project"
|
||||
new "+ 新增專案"
|
||||
|
||||
# game/front_page.rpy:90
|
||||
old "Launch Project"
|
||||
new "啟動專案"
|
||||
|
||||
# game/front_page.rpy:111
|
||||
old "Tutorial"
|
||||
new "教程"
|
||||
|
||||
# game/front_page.rpy:112
|
||||
old "The Question"
|
||||
new "問題"
|
||||
|
||||
# game/front_page.rpy:128
|
||||
old "Active Project"
|
||||
new "活動專案"
|
||||
|
||||
# game/front_page.rpy:136
|
||||
old "Open Directory"
|
||||
new "開啟目錄"
|
||||
|
||||
# game/front_page.rpy:141
|
||||
old "game"
|
||||
new "game"
|
||||
|
||||
# game/front_page.rpy:142
|
||||
old "base"
|
||||
new "base"
|
||||
|
||||
# game/front_page.rpy:148
|
||||
old "Edit File"
|
||||
new "編輯檔案"
|
||||
|
||||
# game/front_page.rpy:156
|
||||
old "All script files"
|
||||
new "開啟所有檔案"
|
||||
|
||||
# game/front_page.rpy:165
|
||||
old "Navigate Script"
|
||||
new "腳本導航"
|
||||
|
||||
# game/front_page.rpy:176
|
||||
old "Check Script (Lint)"
|
||||
new "檢查腳本(Lint)"
|
||||
|
||||
# game/front_page.rpy:177
|
||||
old "Change Theme"
|
||||
new "變更介面主題"
|
||||
|
||||
# game/front_page.rpy:178
|
||||
old "Delete Persistent"
|
||||
new "刪除永久性資料"
|
||||
|
||||
# game/front_page.rpy:186
|
||||
old "Build Distributions"
|
||||
new "建立釋出版"
|
||||
|
||||
# game/front_page.rpy:188
|
||||
old "Generate Translations"
|
||||
new "產生翻譯"
|
||||
|
||||
# game/front_page.rpy:204
|
||||
old "Checking script for potential problems..."
|
||||
new "檢查腳本中的潛在錯誤..."
|
||||
|
||||
# game/front_page.rpy:219
|
||||
old "Deleting persistent data..."
|
||||
new "刪除永久性資料..."
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/front_page.rpy:69
|
||||
old "PROJECTS:"
|
||||
new "專案列表:"
|
||||
# game/front_page.rpy:122
|
||||
old "[p.name!q] (template)"
|
||||
new "[p.name!q] (template)"
|
||||
|
||||
# game/front_page.rpy:215
|
||||
old "Android"
|
||||
new "Android"
|
||||
|
||||
# game/front_page.rpy:217
|
||||
old "Extract Dialogue"
|
||||
new "產生對話框"
|
||||
|
||||
# Translation updated at 2014-10-18 06:00
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/front_page.rpy:35
|
||||
old "Open [text] directory."
|
||||
new "開啟 [text] 目錄。"
|
||||
|
||||
# game/front_page.rpy:150
|
||||
old "Select project [text]."
|
||||
new "選擇專案 [text]。"
|
||||
|
||||
# game/front_page.rpy:234
|
||||
old "Force Recompile"
|
||||
new "強制重編譯"
|
||||
|
||||
# game/front_page.rpy:285
|
||||
old "Recompiling all rpy files into rpyc files..."
|
||||
new "重編譯所有 rpy 檔案為 rpyc 檔案……"
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/interface.rpy:89
|
||||
old "Documentation"
|
||||
new "文件"
|
||||
|
||||
# game/interface.rpy:90
|
||||
old "Ren'Py Website"
|
||||
new "Ren'Py網站"
|
||||
|
||||
# game/interface.rpy:91
|
||||
old "Ren'Py Games List"
|
||||
new "Ren'Py遊戲列表"
|
||||
|
||||
# game/interface.rpy:92
|
||||
old "About"
|
||||
new "關於"
|
||||
|
||||
# game/interface.rpy:99
|
||||
old "update"
|
||||
new "更新"
|
||||
|
||||
# game/interface.rpy:101
|
||||
old "preferences"
|
||||
new "設定"
|
||||
|
||||
# game/interface.rpy:102
|
||||
old "quit"
|
||||
new "離開"
|
||||
|
||||
# game/interface.rpy:149
|
||||
old "Yes"
|
||||
new "確定"
|
||||
|
||||
# game/interface.rpy:151
|
||||
old "No"
|
||||
new "取消"
|
||||
|
||||
# game/interface.rpy:181
|
||||
old "Due to package format limitations, non-ASCII file and directory names are not allowed."
|
||||
new "由於套件格式的限制,非 ASCII 編碼的檔案和目錄將不被支援。"
|
||||
|
||||
# game/interface.rpy:183
|
||||
old "[title]"
|
||||
new "[title]"
|
||||
|
||||
# game/interface.rpy:248
|
||||
old "ERROR"
|
||||
new "錯誤"
|
||||
|
||||
# game/interface.rpy:280
|
||||
old "While [what!q], an error occured:"
|
||||
new "[what!q]時,出現錯誤:"
|
||||
|
||||
# game/interface.rpy:281
|
||||
old "[exception!q]"
|
||||
new "[exception!q]"
|
||||
|
||||
# game/interface.rpy:298
|
||||
old "Text input may not contain the {{ or [[ characters."
|
||||
new "文字輸入可能不包含{{ 或 [[ 字元。"
|
||||
|
||||
# game/interface.rpy:303
|
||||
old "File and directory names may not contain / or \\."
|
||||
new "檔案或目錄不包含/或\\。"
|
||||
|
||||
# game/interface.rpy:309
|
||||
old "File and directory names must consist of ASCII characters."
|
||||
new "檔案名稱和目錄名稱必須是 ASCII 字元。"
|
||||
|
||||
# game/interface.rpy:330
|
||||
old "INFORMATION"
|
||||
new "資訊"
|
||||
|
||||
# game/interface.rpy:373
|
||||
old "PROCESSING"
|
||||
new "正在處理"
|
||||
|
||||
# game/interface.rpy:390
|
||||
old "QUESTION"
|
||||
new "問題"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/interface.rpy:456
|
||||
old "CHOICE"
|
||||
new "選擇"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/navigation.rpy:150
|
||||
old "Navigate: [project.current.name]"
|
||||
new "導航:[project.current.name]"
|
||||
|
||||
# game/navigation.rpy:159
|
||||
old "Order: "
|
||||
new "排序:"
|
||||
|
||||
# game/navigation.rpy:160
|
||||
old "alphabetical"
|
||||
new "按字母順序"
|
||||
|
||||
# game/navigation.rpy:162
|
||||
old "by-file"
|
||||
new "按檔案"
|
||||
|
||||
# game/navigation.rpy:164
|
||||
old "natural"
|
||||
new "natural"
|
||||
|
||||
# game/navigation.rpy:168
|
||||
old "refresh"
|
||||
new "重新整理"
|
||||
|
||||
# game/navigation.rpy:176
|
||||
old "Category:"
|
||||
new "類別:"
|
||||
|
||||
# game/navigation.rpy:178
|
||||
old "files"
|
||||
new "檔案"
|
||||
|
||||
# game/navigation.rpy:179
|
||||
old "labels"
|
||||
new "標籤"
|
||||
|
||||
# game/navigation.rpy:180
|
||||
old "defines"
|
||||
new "定義"
|
||||
|
||||
# game/navigation.rpy:181
|
||||
old "transforms"
|
||||
new "轉換"
|
||||
|
||||
# game/navigation.rpy:182
|
||||
old "screens"
|
||||
new "螢幕"
|
||||
|
||||
# game/navigation.rpy:183
|
||||
old "callables"
|
||||
new "可呼叫"
|
||||
|
||||
# game/navigation.rpy:184
|
||||
old "TODOs"
|
||||
new "待辦事項"
|
||||
|
||||
# game/navigation.rpy:223
|
||||
old "+ Add script file"
|
||||
new "+ 加入腳本檔案"
|
||||
|
||||
# game/navigation.rpy:231
|
||||
old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
|
||||
new "沒有待辦的事項被發現。\n\n要建立一個包含\"# TODO\"到您的腳本中。"
|
||||
|
||||
# game/navigation.rpy:238
|
||||
old "The list of names is empty."
|
||||
new "名稱清單為空。"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/new_project.rpy:22
|
||||
old "Choose Project Template"
|
||||
new "選擇專案模版"
|
||||
|
||||
# game/new_project.rpy:40
|
||||
old "Please select a template to use for your new project. Ren'Py ships with a default template that creates an English-language game with standard screens."
|
||||
new "請選擇一個用於新專案的模版。Ren'Py 中預設了一個標準視窗的英文遊戲。"
|
||||
|
||||
# game/new_project.rpy:55
|
||||
old "PROJECT NAME"
|
||||
new "專案名稱"
|
||||
|
||||
# game/new_project.rpy:56
|
||||
old "Please enter the name of your project:"
|
||||
new "請輸入專案名稱:"
|
||||
|
||||
# game/new_project.rpy:62
|
||||
old "The project name may not be empty."
|
||||
new "專案名稱不能為空。"
|
||||
|
||||
# game/new_project.rpy:67
|
||||
old "[project_name!q] already exists. Please choose a different project name."
|
||||
new "[project_name!q]已存在。請選擇不同的名稱。"
|
||||
|
||||
# game/new_project.rpy:70
|
||||
old "[project_dir!q] already exists. Please choose a different project name."
|
||||
new "[project_dir!q] 已存在。請選擇不同的名稱。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/new_project.rpy:40
|
||||
old "Please select a template to use for your new project. The template sets the default font and the user interface language. If your language is not supported, choose 'english'."
|
||||
new "請為您新增的專案選擇一個模版。該模版將設定為預設的字型和語言。如果您的所使用的語言沒有被支援,那麼請選擇「english」。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/new_project.rpy:71
|
||||
old "The projects directory could not be set. Giving up."
|
||||
new "無法設定專案目錄。放棄。"
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/preferences.rpy:40
|
||||
old "Launcher Preferences"
|
||||
new "啟動器偏好"
|
||||
|
||||
# game/preferences.rpy:61
|
||||
old "Projects Directory:"
|
||||
new "專案目錄:"
|
||||
|
||||
# game/preferences.rpy:68
|
||||
old "[persistent.projects_directory!q]"
|
||||
new "[persistent.projects_directory!q]"
|
||||
|
||||
# game/preferences.rpy:70
|
||||
old "Not Set"
|
||||
new "未設定"
|
||||
|
||||
# game/preferences.rpy:84
|
||||
old "Text Editor:"
|
||||
new "文字編輯器: "
|
||||
|
||||
# game/preferences.rpy:106
|
||||
old "Update Channel:"
|
||||
new "更新頻道:"
|
||||
|
||||
# game/preferences.rpy:126
|
||||
old "Navigation Options:"
|
||||
new "導航選項:"
|
||||
|
||||
# game/preferences.rpy:130
|
||||
old "Include private names"
|
||||
new "包含私有名稱"
|
||||
|
||||
# game/preferences.rpy:131
|
||||
old "Include library names"
|
||||
new "包含資料庫名稱"
|
||||
|
||||
# game/preferences.rpy:141
|
||||
old "Launcher Options:"
|
||||
new "啟動器選項:"
|
||||
|
||||
# game/preferences.rpy:145
|
||||
old "Hardware rendering"
|
||||
new "硬體渲染"
|
||||
|
||||
# game/preferences.rpy:148
|
||||
old "Console output"
|
||||
new "控制臺輸出"
|
||||
|
||||
# game/preferences.rpy:169
|
||||
old "Open launcher project"
|
||||
new "開啟啟動器專案"
|
||||
|
||||
# game/preferences.rpy:183
|
||||
old "Language:"
|
||||
new "語言:"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/preferences.rpy:146
|
||||
old "Show templates"
|
||||
new "顯示模版"
|
||||
|
||||
# game/preferences.rpy:165
|
||||
old "Large fonts"
|
||||
new "大字體"
|
||||
|
||||
# Translation updated at 2014-10-18 06:00
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/preferences.rpy:91
|
||||
old "Projects directory: [text]"
|
||||
new "專案資料夾: [text]"
|
||||
|
||||
# game/preferences.rpy:114
|
||||
old "Text editor: [text]"
|
||||
new "文字編輯器: [text]"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/project.rpy:196
|
||||
old "Ren'Py is scanning the project..."
|
||||
new "Ren'Py 正在掃描專案..."
|
||||
|
||||
# game/project.rpy:485
|
||||
old "PROJECTS DIRECTORY"
|
||||
new "專案目錄"
|
||||
|
||||
# game/project.rpy:485
|
||||
old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
|
||||
new "請使用目錄選擇器選擇專案目錄。\n{b}目錄選擇視窗可能會開啟在本視窗後面。{/b}"
|
||||
|
||||
# game/project.rpy:485
|
||||
old "This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."
|
||||
new "啟動器會掃描該目錄下的專案,新增的專案也將在該目錄下建置。專案也在該目錄下建立。"
|
||||
|
||||
# game/project.rpy:525
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory."
|
||||
new "Ren'Py 無法運行 python 的 tkinter 來選擇專案目錄。"
|
||||
|
||||
# game/project.rpy:529
|
||||
old "Ren'Py has set the projects directory to:"
|
||||
new "Ren'Py 已將專案目錄設定為:"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/project.rpy:48
|
||||
old "After making changes to the script, press shift+R to reload your game."
|
||||
new "改變腳本後,請按 shift+R 來重新載入您的遊戲。"
|
||||
|
||||
# game/project.rpy:49
|
||||
old "Press shift+O (the letter) to access the console."
|
||||
new "按 shift+O (the letter)來進入控制臺。"
|
||||
|
||||
# game/project.rpy:50
|
||||
old "Press shift+D to access the developer menu."
|
||||
new "按 shift+D 來進入開發者選單"
|
||||
|
||||
# game/project.rpy:219
|
||||
old "Launching the project failed."
|
||||
new "啟動專案失敗。"
|
||||
|
||||
# game/project.rpy:219
|
||||
old "Please ensure that your project launches normally before running this command."
|
||||
new "請確保您的專案能正常啟動再執行本指令。"
|
||||
|
||||
# game/project.rpy:516
|
||||
old "Launching"
|
||||
new "正在啟動"
|
||||
|
||||
# game/project.rpy:585
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory. Please install the python-tk or tkinter package."
|
||||
new "Ren'Py 無法運行 python 的 tkinter 來選擇專案目錄。請安裝 python-tk 或 tkinter。"
|
||||
|
||||
# Translation updated at 2014-10-18 06:00
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/project.rpy:47
|
||||
old "Have you backed up your projects recently?"
|
||||
new "您最近有備份您的專案嗎?"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
translate traditional_chinese python:
|
||||
DROID = "tl/traditional_chinese/DroidSansFallback.ttf"
|
||||
|
||||
translate traditional_chinese style l_default:
|
||||
font DROID
|
||||
size 16
|
||||
|
||||
translate traditional_chinese style l_button_text:
|
||||
selected_font DROID
|
||||
selected_bold True
|
||||
|
||||
translate traditional_chinese style l_link_text:
|
||||
font DROID
|
||||
|
||||
translate traditional_chinese style l_alternate_text:
|
||||
font DROID
|
||||
|
||||
translate traditional_chinese style l_navigation_button_text:
|
||||
font DROID
|
||||
|
||||
translate traditional_chinese style l_navigation_text:
|
||||
font DROID
|
||||
bold True
|
||||
|
||||
translate traditional_chinese style l_checkbox_text:
|
||||
selected_font DROID
|
||||
|
||||
translate traditional_chinese style l_nonbox_text:
|
||||
selected_font DROID
|
||||
|
||||
translate traditional_chinese style hyperlink_text:
|
||||
font DROID
|
||||
|
||||
translate traditional_chinese python:
|
||||
make_style_backup()
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/translations.rpy:10
|
||||
old "Create or Update Translations"
|
||||
new "新增或更新翻譯"
|
||||
|
||||
# game/translations.rpy:10
|
||||
old "Please enter the name of the language for which you want to create or update translations."
|
||||
new "請輸入您要新增或者更新語言的名稱。"
|
||||
|
||||
# game/translations.rpy:15
|
||||
old "The language name can not be the empty string."
|
||||
new "語言名稱不能為空字串。"
|
||||
|
||||
# game/translations.rpy:26
|
||||
old "Ren'Py is generating translations...."
|
||||
new "Ren'Py 正在產生翻譯..."
|
||||
|
||||
# game/translations.rpy:30
|
||||
old "Ren'Py has finished generating [language] translations."
|
||||
new "Ren'Py 已經完成[language]翻譯檔案。"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/translations.rpy:44
|
||||
old "What format would you like for the extracted dialogue?"
|
||||
new "您要使用什麼格式來提取對話框?"
|
||||
|
||||
# game/translations.rpy:56
|
||||
old "Ren'Py is extracting dialogue...."
|
||||
new "Ren'Py 正在提取對話框..."
|
||||
|
||||
# game/translations.rpy:60
|
||||
old "Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[format] in the base directory."
|
||||
new "Ren'Py 已經完成對話框提取。提取的對話可以在底層目錄下 dialogue.[format] 中找到。"
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/updater.rpy:54
|
||||
old "Select Update Channel"
|
||||
new "選擇更新頻道"
|
||||
|
||||
# game/updater.rpy:65
|
||||
old "The update channel controls the version of Ren'Py the updater will download. Please select an update channel:"
|
||||
new "更新頻道控制 Ren'Py 更新將會下載的版本。請選擇一個更新頻道。"
|
||||
|
||||
# game/updater.rpy:70
|
||||
old "Release"
|
||||
new "Release"
|
||||
|
||||
# game/updater.rpy:76
|
||||
old "{b}Recommended.{/b} The version of Ren'Py that should be used in all newly-released games."
|
||||
new "{b}推薦{/b} Ren'py 的版本應在所有新釋出的遊戲中使用。"
|
||||
|
||||
# game/updater.rpy:81
|
||||
old "Prerelease"
|
||||
new "Prerelease"
|
||||
|
||||
# game/updater.rpy:87
|
||||
old "A preview of the next version of Ren'Py that can be used for testing and taking advantage of new features, but not for final releases of games."
|
||||
new "預覽 Ren'py 的下一個版本,適合用於測試和體驗新功能,但不適合遊戲的最終版本。"
|
||||
|
||||
# game/updater.rpy:93
|
||||
old "Experimental"
|
||||
new "Experimental"
|
||||
|
||||
# game/updater.rpy:99
|
||||
old "Experimental versions of Ren'Py. You shouldn't select this channel unless asked by a Ren'Py developer."
|
||||
new "Ren'py 的實驗版本,除非您被 Ren'py 的開發者要求,否則您不應該選擇此頻道。"
|
||||
|
||||
# game/updater.rpy:119
|
||||
old "An error has occured:"
|
||||
new "一個錯誤發生:"
|
||||
|
||||
# game/updater.rpy:121
|
||||
old "Checking for updates."
|
||||
new "檢查更新"
|
||||
|
||||
# game/updater.rpy:123
|
||||
old "Ren'Py is up to date."
|
||||
new "Ren'Py 已是最新版本"
|
||||
|
||||
# game/updater.rpy:125
|
||||
old "[u.version] is now available. Do you want to install it?"
|
||||
new "[u.version] 已經可以更新。你要下載它嗎?"
|
||||
|
||||
# game/updater.rpy:127
|
||||
old "Preparing to download the update."
|
||||
new "準備下載更新。"
|
||||
|
||||
# game/updater.rpy:129
|
||||
old "Downloading the update."
|
||||
new "正在下載更新。"
|
||||
|
||||
# game/updater.rpy:131
|
||||
old "Unpacking the update."
|
||||
new "正在解壓縮更新檔案。"
|
||||
|
||||
# game/updater.rpy:133
|
||||
old "Finishing up."
|
||||
new "即將完成。"
|
||||
|
||||
# game/updater.rpy:135
|
||||
old "The update has been installed. Ren'Py will restart."
|
||||
new "已安裝更新。Ren'Py 將會重新啟動。"
|
||||
|
||||
# game/updater.rpy:137
|
||||
old "The update has been installed."
|
||||
new "已安裝更新。"
|
||||
|
||||
# game/updater.rpy:139
|
||||
old "The update was cancelled."
|
||||
new "已取消更新。"
|
||||
|
||||
# game/updater.rpy:156
|
||||
old "Ren'Py Update"
|
||||
new "Ren'Py 更新"
|
||||
|
||||
# game/updater.rpy:162
|
||||
old "Proceed"
|
||||
new "繼續"
|
||||
|
||||
|
||||
translate traditional_chinese strings:
|
||||
|
||||
# game/updater.rpy:129
|
||||
old "Nightly"
|
||||
new "Nightly"
|
||||
|
||||
# game/updater.rpy:135
|
||||
old "The bleeding edge of Ren'Py development. This may have the latest features, or might not run at all."
|
||||
new "Ren'Py 最新的開發版本。這可能會擁有最新的功能,或可能根本無法運作。"
|
||||
|
||||
+31
-34
@@ -25,8 +25,7 @@
|
||||
* 11/08/2004 - Compr fix, levels -1,1-7 now work - Tyler Montbriand
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_byteorder.h>
|
||||
#include <SDL.h>
|
||||
#include <png.h>
|
||||
#include <zlib.h>
|
||||
#include "IMG_savepng.h"
|
||||
@@ -38,7 +37,7 @@
|
||||
int IMG_SavePNG(const char *file, SDL_Surface *surf,int compression){
|
||||
SDL_RWops *fp;
|
||||
int ret;
|
||||
|
||||
|
||||
fp=SDL_RWFromFile(file,"wb");
|
||||
|
||||
if( fp == NULL ) {
|
||||
@@ -60,24 +59,25 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
|
||||
png_infop info_ptr;
|
||||
SDL_PixelFormat *fmt=NULL;
|
||||
SDL_Surface *tempsurf=NULL;
|
||||
int ret,funky_format,used_alpha;
|
||||
unsigned int i,temp_alpha;
|
||||
int ret,funky_format;
|
||||
unsigned int i;
|
||||
png_colorp palette;
|
||||
Uint8 *palette_alpha=NULL;
|
||||
png_byte **row_pointers=NULL;
|
||||
png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1;
|
||||
funky_format=0;
|
||||
|
||||
SDL_BlendMode temp_blend;
|
||||
|
||||
if( !src || !surf) {
|
||||
goto savedone; /* Nothing to do. */
|
||||
}
|
||||
|
||||
row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*));
|
||||
if (!row_pointers) {
|
||||
if (!row_pointers) {
|
||||
SDL_SetError("Couldn't allocate memory for rowpointers");
|
||||
goto savedone;
|
||||
}
|
||||
|
||||
|
||||
png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
|
||||
if (!png_ptr){
|
||||
SDL_SetError("Couldn't allocate memory for PNG file");
|
||||
@@ -126,19 +126,19 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
|
||||
palette[i].blue=fmt->palette->colors[i].b;
|
||||
}
|
||||
png_set_PLTE(png_ptr,info_ptr,palette,fmt->palette->ncolors);
|
||||
if (surf->flags&SDL_SRCCOLORKEY) {
|
||||
palette_alpha=(Uint8 *)malloc((fmt->colorkey+1)*sizeof(Uint8));
|
||||
if (!palette_alpha) {
|
||||
SDL_SetError("Couldn't create memory for palette transparency");
|
||||
goto savedone;
|
||||
}
|
||||
/* FIXME: memset? */
|
||||
for (i=0;i<(fmt->colorkey+1);i++) {
|
||||
palette_alpha[i]=255;
|
||||
}
|
||||
palette_alpha[fmt->colorkey]=0;
|
||||
png_set_tRNS(png_ptr,info_ptr,palette_alpha,fmt->colorkey+1,NULL);
|
||||
}
|
||||
// if (surf->flags&SDL_SRCCOLORKEY) {
|
||||
// palette_alpha=(Uint8 *)malloc((fmt->colorkey+1)*sizeof(Uint8));
|
||||
// if (!palette_alpha) {
|
||||
// SDL_SetError("Couldn't create memory for palette transparency");
|
||||
// goto savedone;
|
||||
// }
|
||||
// /* FIXME: memset? */
|
||||
// for (i=0;i<(fmt->colorkey+1);i++) {
|
||||
// palette_alpha[i]=255;
|
||||
// }
|
||||
// palette_alpha[fmt->colorkey]=0;
|
||||
// png_set_tRNS(png_ptr,info_ptr,palette_alpha,fmt->colorkey+1,NULL);
|
||||
// }
|
||||
}else{ /* Truecolor */
|
||||
if (fmt->Amask) {
|
||||
png_set_IHDR(png_ptr,info_ptr,
|
||||
@@ -172,11 +172,11 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
|
||||
}else{
|
||||
/* Check for RGB/BGR/GBR/RBG/etc surfaces.*/
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
if(fmt->Rmask!=0xFF0000
|
||||
if(fmt->Rmask!=0xFF0000
|
||||
|| fmt->Gmask!=0x00FF00
|
||||
|| fmt->Bmask!=0x0000FF){
|
||||
#else
|
||||
if(fmt->Rmask!=0x0000FF
|
||||
if(fmt->Rmask!=0x0000FF
|
||||
|| fmt->Gmask!=0x00FF00
|
||||
|| fmt->Bmask!=0xFF0000){
|
||||
#endif
|
||||
@@ -185,7 +185,7 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
|
||||
}
|
||||
}else if (fmt->BytesPerPixel==4){
|
||||
if (!fmt->Amask) { /* check for 32bit but no alpha */
|
||||
funky_format=1;
|
||||
funky_format=1;
|
||||
}else{
|
||||
/* Check for ARGB/ABGR/GBAR/RABG/etc surfaces.*/
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
@@ -228,21 +228,18 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
|
||||
SDL_SetError("Couldn't allocate temp surface");
|
||||
goto savedone;
|
||||
}
|
||||
if(surf->flags&SDL_SRCALPHA){
|
||||
temp_alpha=fmt->alpha;
|
||||
used_alpha=1;
|
||||
SDL_SetAlpha(surf,0,255); /* Set for an opaque blit */
|
||||
}else{
|
||||
used_alpha=0;
|
||||
}
|
||||
|
||||
SDL_GetSurfaceBlendMode(surf, &temp_blend);
|
||||
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE);
|
||||
|
||||
if(SDL_BlitSurface(surf,NULL,tempsurf,NULL)!=0){
|
||||
SDL_SetError("Couldn't blit surface to temp surface");
|
||||
SDL_FreeSurface(tempsurf);
|
||||
goto savedone;
|
||||
}
|
||||
if (used_alpha) {
|
||||
SDL_SetAlpha(surf,SDL_SRCALPHA,(Uint8)temp_alpha); /* Restore alpha settings*/
|
||||
}
|
||||
|
||||
SDL_SetSurfaceBlendMode(surf, temp_blend);
|
||||
|
||||
for(i=0;i<tempsurf->h;i++){
|
||||
row_pointers[i]= ((png_byte*)tempsurf->pixels) + i*tempsurf->pitch;
|
||||
}
|
||||
|
||||
+5
-9
@@ -23,17 +23,13 @@
|
||||
def version():
|
||||
return (6, 12, 0)
|
||||
|
||||
cdef extern from "pygame/pygame.h":
|
||||
cdef struct SDL_RWops:
|
||||
pass
|
||||
|
||||
void import_pygame_rwobject()
|
||||
SDL_RWops* RWopsFromPython(object obj)
|
||||
|
||||
from sdl2 cimport *
|
||||
from pygame_sdl2 cimport *
|
||||
|
||||
cdef extern from "renpy.h":
|
||||
|
||||
void core_init()
|
||||
void subpixel_init()
|
||||
|
||||
void save_png_core(object, SDL_RWops *, int)
|
||||
|
||||
@@ -425,6 +421,6 @@ def subpixel(pysrc, pydst, xoffset, yoffset, shift):
|
||||
|
||||
# Be sure to update scale.py when adding something new here!
|
||||
|
||||
import_pygame_rwobject()
|
||||
import_pygame_sdl2__rwobject()
|
||||
core_init()
|
||||
|
||||
subpixel_init()
|
||||
|
||||
+172
-172
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -19,7 +19,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <pygame/pygame.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <libavutil/avstring.h>
|
||||
@@ -35,6 +34,8 @@
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
|
||||
#include <pygame_sdl2/pygame_sdl2.surface_api.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
#endif
|
||||
@@ -1296,7 +1297,7 @@ static int stream_component_open(VideoState *is, int stream_index)
|
||||
is->video_current_pts_time = av_gettime();
|
||||
|
||||
packet_queue_init(&is->videoq);
|
||||
is->video_tid = SDL_CreateThread(video_thread, is);
|
||||
is->video_tid = SDL_CreateThread(video_thread, "video_thread", is);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1606,7 +1607,7 @@ VideoState *ffpy_stream_open(SDL_RWops *rwops, const char *filename)
|
||||
is->quit_mutex = SDL_CreateMutex();
|
||||
is->quit_cond = SDL_CreateCond();
|
||||
|
||||
is->parse_tid = SDL_CreateThread(decode_thread, is);
|
||||
is->parse_tid = SDL_CreateThread(decode_thread, "decode_thread", is);
|
||||
|
||||
is->first_frame = 1;
|
||||
|
||||
@@ -1665,6 +1666,8 @@ void ffpy_init(int rate, int status) {
|
||||
|
||||
ffpy_did_init = 1;
|
||||
|
||||
import_pygame_sdl2__surface();
|
||||
|
||||
show_status = status;
|
||||
|
||||
audio_sample_rate = rate;
|
||||
|
||||
@@ -128,12 +128,13 @@ style_properties = sorted_dict(
|
||||
child = 'renpy.easy.displayable_or_none',
|
||||
clipping = None,
|
||||
color = 'renpy.easy.color',
|
||||
debug = None,
|
||||
drop_shadow = None,
|
||||
drop_shadow_color = 'renpy.easy.color',
|
||||
first_indent = None,
|
||||
first_spacing = None,
|
||||
fit_first = None,
|
||||
focus_mask = None,
|
||||
focus_mask = 'expand_focus_mask',
|
||||
focus_rect = None,
|
||||
font = None,
|
||||
fore_bar = 'none_is_null',
|
||||
@@ -144,6 +145,7 @@ style_properties = sorted_dict(
|
||||
italic = None,
|
||||
justify = None,
|
||||
kerning = None,
|
||||
keyboard_focus = None,
|
||||
language = None,
|
||||
layout = None,
|
||||
line_leading = None,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from sdl2 cimport SDL_Surface, SDL_RWops
|
||||
|
||||
cdef extern from "pygame_sdl2/pygame_sdl2.rwobject_api.h":
|
||||
void import_pygame_sdl2__rwobject()
|
||||
SDL_RWops* RWopsFromPython(object obj)
|
||||
|
||||
cdef extern from "pygame_sdl2/pygame_sdl2.surface_api.h":
|
||||
int import_pygame_sdl2__surface()
|
||||
SDL_Surface *PySurface_AsSurface(object)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+108
-108
@@ -23,8 +23,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "pss.h"
|
||||
#include <Python.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Declarations of ffdecode functions. */
|
||||
@@ -37,7 +37,7 @@ int ffpy_refresh_event(struct VideoState *vs);
|
||||
void ffpy_init(int rate, int status);
|
||||
int ffpy_audio_decode(struct VideoState *is, Uint8 *stream, int len);
|
||||
|
||||
|
||||
|
||||
/* The current Python. */
|
||||
PyInterpreterState* interp;
|
||||
PyThreadState* thread = NULL;
|
||||
@@ -47,7 +47,7 @@ static void incref(PyObject *ref) {
|
||||
|
||||
PyEval_AcquireLock();
|
||||
oldstate = PyThreadState_Swap(thread);
|
||||
Py_INCREF(ref);
|
||||
Py_INCREF(ref);
|
||||
PyThreadState_Swap(oldstate);
|
||||
PyEval_ReleaseLock();
|
||||
}
|
||||
@@ -57,7 +57,7 @@ static void decref(PyObject *ref) {
|
||||
|
||||
PyEval_AcquireLock();
|
||||
oldstate = PyThreadState_Swap(thread);
|
||||
Py_DECREF(ref);
|
||||
Py_DECREF(ref);
|
||||
PyThreadState_Swap(oldstate);
|
||||
PyEval_ReleaseLock();
|
||||
}
|
||||
@@ -116,9 +116,9 @@ struct Channel {
|
||||
|
||||
/* Is the playing sample tight? */
|
||||
int playing_tight;
|
||||
|
||||
|
||||
/* The queued up sample. */
|
||||
struct VideoState *queued;
|
||||
struct VideoState *queued;
|
||||
|
||||
/* The name of the queued up sample. */
|
||||
PyObject *queued_name;
|
||||
@@ -128,17 +128,17 @@ struct Channel {
|
||||
|
||||
/* Is the queued sample tight? */
|
||||
int queued_tight;
|
||||
|
||||
|
||||
/* Is this channel paused? */
|
||||
int paused;
|
||||
|
||||
|
||||
/* The volume of the channel. */
|
||||
int volume;
|
||||
|
||||
/* The position (in bytes) that this channel has queued to. */
|
||||
int pos;
|
||||
|
||||
/*
|
||||
/*
|
||||
* The number of bytes for each step of fade.
|
||||
* 0 when no fade is in progress.
|
||||
*/
|
||||
@@ -152,7 +152,7 @@ struct Channel {
|
||||
|
||||
/* The change in fade_vol for each step. */
|
||||
int fade_delta;
|
||||
|
||||
|
||||
/* The number of bytes in which we'll stop. */
|
||||
int stop_bytes;
|
||||
|
||||
@@ -215,7 +215,7 @@ static float interpolate_pan(struct Channel *c) {
|
||||
done = 1.0 * c->pan_done / c->pan_length;
|
||||
|
||||
return c->pan_start + done * (c->pan_end - c->pan_start);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static float interpolate_vol2(struct Channel *c) {
|
||||
@@ -250,7 +250,7 @@ static void start_sample(struct Channel* c, int reset_fade) {
|
||||
c->pos = 0;
|
||||
|
||||
if (reset_fade) {
|
||||
|
||||
|
||||
if (c->playing_fadein == 0) {
|
||||
c->fade_step_len = 0;
|
||||
} else {
|
||||
@@ -268,7 +268,7 @@ static void start_sample(struct Channel* c, int reset_fade) {
|
||||
}
|
||||
|
||||
c->stop_bytes = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_sample(struct VideoState *ss) {
|
||||
@@ -294,7 +294,7 @@ static void mixaudio(Uint8 *dst, Uint8 *src, int length, int volume) {
|
||||
}
|
||||
|
||||
*sdst++ = (short) sound;
|
||||
ssrc++;
|
||||
ssrc++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ static void fade_mixaudio(struct Channel *c,
|
||||
Uint8 *dst, Uint8 *src, int length) {
|
||||
|
||||
while (length) {
|
||||
|
||||
|
||||
// No fade case.
|
||||
if (c->fade_step_len == 0) {
|
||||
mixaudio(dst, src, length, c->volume);
|
||||
@@ -316,14 +316,14 @@ static void fade_mixaudio(struct Channel *c,
|
||||
int l = min(c->fade_step_len - c->fade_off, length);
|
||||
|
||||
mixaudio(dst, src, l, c->fade_vol);
|
||||
|
||||
|
||||
length -= l;
|
||||
dst += l;
|
||||
src += l;
|
||||
c->fade_off += l;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, we have no space left in the current fade step.
|
||||
// Go to the next step.
|
||||
c->fade_off = 0;
|
||||
@@ -333,14 +333,14 @@ static void fade_mixaudio(struct Channel *c,
|
||||
if (c->fade_vol <= 0) {
|
||||
c->fade_vol = 0;
|
||||
}
|
||||
|
||||
|
||||
// Stop on a fadein.
|
||||
if (c->fade_vol >= c->volume) {
|
||||
c->fade_vol = c->volume;
|
||||
c->fade_step_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -365,14 +365,14 @@ static void pan_audio(struct Channel *c, Uint8 *stream, int length) {
|
||||
float vol2;
|
||||
int left = 256;
|
||||
int right = 256;
|
||||
|
||||
|
||||
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
|
||||
if ((i & 0x1f) == 0) {
|
||||
pan = interpolate_pan(c);
|
||||
vol2 = interpolate_vol2(c);
|
||||
|
||||
|
||||
// If nothing to do, skip 32 samples.
|
||||
if (pan == 0.0 && vol2 == 1.0) {
|
||||
i += 31;
|
||||
@@ -402,7 +402,7 @@ static void pan_audio(struct Channel *c, Uint8 *stream, int length) {
|
||||
c->pan_done += 1;
|
||||
c->vol2_done += 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
@@ -410,7 +410,7 @@ static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
|
||||
for (channel = 0; channel < num_channels; channel++) {
|
||||
|
||||
|
||||
|
||||
int mixed = 0;
|
||||
struct Channel *c = &channels[channel];
|
||||
|
||||
@@ -430,10 +430,10 @@ static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
// Decode some amount of data.
|
||||
|
||||
bytes = ffpy_audio_decode(c->playing, buffer, mixleft);
|
||||
|
||||
|
||||
// We have some data in the buffer.
|
||||
if (c->stop_bytes && bytes) {
|
||||
|
||||
|
||||
if (c->stop_bytes != -1)
|
||||
bytes = min(c->stop_bytes, bytes);
|
||||
|
||||
@@ -441,12 +441,12 @@ static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
fade_mixaudio(c, &stream[mixed], buffer, bytes);
|
||||
|
||||
mixed += bytes;
|
||||
|
||||
|
||||
if (c->stop_bytes != -1)
|
||||
c->stop_bytes -= bytes;
|
||||
|
||||
c->pos += bytes;
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -458,14 +458,14 @@ static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
|
||||
int old_tight = c->playing_tight;
|
||||
struct Dying *d;
|
||||
|
||||
|
||||
post_event(c);
|
||||
|
||||
d = malloc(sizeof(struct Dying));
|
||||
d->next = dying;
|
||||
d->stream = c->playing;
|
||||
dying = d;
|
||||
|
||||
|
||||
LOCK_NAME();
|
||||
|
||||
decref(c->playing_name);
|
||||
@@ -474,17 +474,17 @@ static void callback(void *userdata, Uint8 *stream, int length) {
|
||||
c->playing_name = c->queued_name;
|
||||
c->playing_fadein = c->queued_fadein;
|
||||
c->playing_tight = c->queued_tight;
|
||||
|
||||
|
||||
c->queued = NULL;
|
||||
c->queued_name = NULL;
|
||||
c->queued_fadein = 0;
|
||||
c->queued_tight = 0;
|
||||
|
||||
UNLOCK_NAME();
|
||||
|
||||
|
||||
start_sample(c, ! old_tight);
|
||||
|
||||
continue;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,14 +508,14 @@ static int check_channel(int c) {
|
||||
|
||||
if (c >= num_channels) {
|
||||
channels = realloc(channels, sizeof(struct Channel) * (c + 1));
|
||||
|
||||
|
||||
for (i = num_channels; i <= c; i++) {
|
||||
|
||||
|
||||
channels[i].playing = NULL;
|
||||
channels[i].queued = NULL;
|
||||
channels[i].playing_name = NULL;
|
||||
channels[i].queued_name = NULL;
|
||||
channels[i].volume = SDL_MIX_MAXVOLUME;
|
||||
channels[i].volume = SDL_MIX_MAXVOLUME;
|
||||
channels[i].paused = 1;
|
||||
channels[i].event = 0;
|
||||
channels[i].pan_start = 0.0;
|
||||
@@ -530,7 +530,7 @@ static int check_channel(int c) {
|
||||
|
||||
num_channels = c + 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -540,16 +540,16 @@ static int check_channel(int c) {
|
||||
* failure.
|
||||
*/
|
||||
struct VideoState *load_sample(SDL_RWops *rw, const char *ext) {
|
||||
struct VideoState *rv;
|
||||
struct VideoState *rv;
|
||||
rv = ffpy_stream_open(rw, ext);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int fadein, int tight, int paused) {
|
||||
|
||||
BEGIN();
|
||||
|
||||
|
||||
struct Channel *c;
|
||||
|
||||
if (check_channel(channel)) {
|
||||
@@ -558,7 +558,7 @@ void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int f
|
||||
|
||||
c = &channels[channel];
|
||||
ENTER();
|
||||
|
||||
|
||||
LOCK_NAME();
|
||||
|
||||
/* Free playing and queued samples. */
|
||||
@@ -569,7 +569,7 @@ void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int f
|
||||
c->playing_name = NULL;
|
||||
c->playing_tight = 0;
|
||||
}
|
||||
|
||||
|
||||
if (c->queued) {
|
||||
free_sample(c->queued);
|
||||
c->queued = NULL;
|
||||
@@ -579,7 +579,7 @@ void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int f
|
||||
}
|
||||
|
||||
/* Allocate playing sample. */
|
||||
|
||||
|
||||
c->playing = load_sample(rw, ext);
|
||||
|
||||
if (! c->playing) {
|
||||
@@ -594,11 +594,11 @@ void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int f
|
||||
|
||||
c->playing_fadein = fadein;
|
||||
c->playing_tight = tight;
|
||||
|
||||
|
||||
c->paused = paused;
|
||||
start_sample(c, 1);
|
||||
start_sample(c, 1);
|
||||
/* update_pause(); */
|
||||
|
||||
|
||||
UNLOCK_NAME();
|
||||
|
||||
EXIT();
|
||||
@@ -608,7 +608,7 @@ void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int f
|
||||
void PSS_queue(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int fadein, int tight) {
|
||||
|
||||
BEGIN();
|
||||
|
||||
|
||||
struct Channel *c;
|
||||
|
||||
if (check_channel(channel)) {
|
||||
@@ -616,18 +616,18 @@ void PSS_queue(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int
|
||||
}
|
||||
|
||||
c = &channels[channel];
|
||||
|
||||
|
||||
ENTER();
|
||||
|
||||
/* If we're not playing, then we should play instead of queue. */
|
||||
if (!c->playing) {
|
||||
EXIT();
|
||||
PSS_play(channel, rw, ext, name, fadein, tight, 0);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Free queued sample. */
|
||||
|
||||
|
||||
if (c->queued) {
|
||||
free_sample(c->queued);
|
||||
c->queued = NULL;
|
||||
@@ -635,7 +635,7 @@ void PSS_queue(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int
|
||||
c->queued_name = NULL;
|
||||
c->queued_tight = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate queued sample. */
|
||||
c->queued = load_sample(rw, ext);
|
||||
|
||||
@@ -649,11 +649,11 @@ void PSS_queue(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int
|
||||
c->queued_name = name;
|
||||
c->queued_fadein = fadein;
|
||||
c->queued_tight = tight;
|
||||
|
||||
|
||||
EXIT();
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Stops all music from playing, freeing the data used by the
|
||||
@@ -676,7 +676,7 @@ void PSS_stop(int channel) {
|
||||
if (c->playing) {
|
||||
post_event(c);
|
||||
}
|
||||
|
||||
|
||||
/* Free playing and queued samples. */
|
||||
if (c->playing) {
|
||||
free_sample(c->playing);
|
||||
@@ -684,18 +684,18 @@ void PSS_stop(int channel) {
|
||||
decref(c->playing_name);
|
||||
c->playing_name = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (c->queued) {
|
||||
free_sample(c->queued);
|
||||
c->queued = NULL;
|
||||
decref(c->queued_name);
|
||||
c->queued_name = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* update_pause(); */
|
||||
|
||||
UNLOCK_NAME();
|
||||
EXIT();
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
@@ -731,8 +731,8 @@ void PSS_dequeue(int channel, int even_tight) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
EXIT();
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
@@ -757,8 +757,8 @@ int PSS_queue_depth(int channel) {
|
||||
|
||||
if (c->playing) rv++;
|
||||
if (c->queued) rv++;
|
||||
|
||||
EXIT();
|
||||
|
||||
EXIT();
|
||||
error(SUCCESS);
|
||||
|
||||
return rv;
|
||||
@@ -767,7 +767,7 @@ int PSS_queue_depth(int channel) {
|
||||
PyObject *PSS_playing_name(int channel) {
|
||||
BEGIN();
|
||||
PyObject *rv;
|
||||
|
||||
|
||||
struct Channel *c;
|
||||
|
||||
if (check_channel(channel)) {
|
||||
@@ -795,7 +795,7 @@ PyObject *PSS_playing_name(int channel) {
|
||||
ALTEXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -826,7 +826,7 @@ void PSS_fadeout(int channel, int ms) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fade_steps = c->volume;
|
||||
c->fade_delta = -1;
|
||||
c->fade_off = 0;
|
||||
@@ -838,15 +838,15 @@ void PSS_fadeout(int channel, int ms) {
|
||||
} else {
|
||||
c->fade_step_len = 0;
|
||||
}
|
||||
|
||||
|
||||
c->stop_bytes = ms_to_bytes(ms);
|
||||
c->queued_tight = 0;
|
||||
|
||||
if (!c->queued) {
|
||||
c->playing_tight = 0;
|
||||
}
|
||||
|
||||
EXIT();
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
@@ -856,7 +856,7 @@ void PSS_fadeout(int channel, int ms) {
|
||||
*/
|
||||
void PSS_pause(int channel, int pause) {
|
||||
BEGIN();
|
||||
|
||||
|
||||
struct Channel *c;
|
||||
|
||||
if (check_channel(channel)) {
|
||||
@@ -872,13 +872,13 @@ void PSS_pause(int channel, int pause) {
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PSS_unpause_all(void) {
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
BEGIN();
|
||||
|
||||
ENTER();
|
||||
@@ -890,7 +890,7 @@ void PSS_unpause_all(void) {
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -901,7 +901,7 @@ int PSS_get_pos(int channel) {
|
||||
struct Channel *c;
|
||||
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -909,7 +909,7 @@ int PSS_get_pos(int channel) {
|
||||
c = &channels[channel];
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
if (c->playing) {
|
||||
rv = bytes_to_ms(c->pos);
|
||||
} else {
|
||||
@@ -917,7 +917,7 @@ int PSS_get_pos(int channel) {
|
||||
}
|
||||
|
||||
EXIT();
|
||||
|
||||
|
||||
error(SUCCESS);
|
||||
return rv;
|
||||
}
|
||||
@@ -929,7 +929,7 @@ int PSS_get_pos(int channel) {
|
||||
void PSS_set_endevent(int channel, int event) {
|
||||
struct Channel *c;
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return;
|
||||
}
|
||||
@@ -937,12 +937,12 @@ void PSS_set_endevent(int channel, int event) {
|
||||
c = &channels[channel];
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
c->event = event;
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -952,7 +952,7 @@ void PSS_set_endevent(int channel, int event) {
|
||||
void PSS_set_volume(int channel, float volume) {
|
||||
struct Channel *c;
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return;
|
||||
}
|
||||
@@ -960,12 +960,12 @@ void PSS_set_volume(int channel, float volume) {
|
||||
c = &channels[channel];
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
c->volume = (int) (volume * SDL_MIX_MAXVOLUME);
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -973,10 +973,10 @@ void PSS_set_volume(int channel, float volume) {
|
||||
float PSS_get_volume(int channel) {
|
||||
|
||||
float rv;
|
||||
|
||||
|
||||
struct Channel *c;
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return 0.0;
|
||||
}
|
||||
@@ -984,12 +984,12 @@ float PSS_get_volume(int channel) {
|
||||
c = &channels[channel];
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
rv = 1.0 * c->volume / SDL_MIX_MAXVOLUME;
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
error(SUCCESS);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1000,7 +1000,7 @@ float PSS_get_volume(int channel) {
|
||||
void PSS_set_pan(int channel, float pan, float delay) {
|
||||
struct Channel *c;
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return;
|
||||
}
|
||||
@@ -1008,15 +1008,15 @@ void PSS_set_pan(int channel, float pan, float delay) {
|
||||
c = &channels[channel];
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
c->pan_start = interpolate_pan(c);
|
||||
c->pan_end = pan;
|
||||
c->pan_length = (int) (audio_spec.freq * delay);
|
||||
c->pan_done = 0;
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1025,7 +1025,7 @@ void PSS_set_pan(int channel, float pan, float delay) {
|
||||
void PSS_set_secondary_volume(int channel, float vol2, float delay) {
|
||||
struct Channel *c;
|
||||
BEGIN();
|
||||
|
||||
|
||||
if (check_channel(channel)) {
|
||||
return;
|
||||
}
|
||||
@@ -1038,10 +1038,10 @@ void PSS_set_secondary_volume(int channel, float vol2, float delay) {
|
||||
c->vol2_end = vol2;
|
||||
c->vol2_length = (int) (audio_spec.freq * delay);
|
||||
c->vol2_done = 0;
|
||||
|
||||
|
||||
EXIT();
|
||||
|
||||
error(SUCCESS);
|
||||
|
||||
error(SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -1064,12 +1064,12 @@ void PSS_init(int freq, int stereo, int samples, int status) {
|
||||
interp = thread->interp;
|
||||
thread = PyThreadState_New(interp);
|
||||
}
|
||||
|
||||
|
||||
if (!thread) {
|
||||
error(SDL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO)) {
|
||||
error(SDL_ERROR);
|
||||
return;
|
||||
@@ -1090,7 +1090,7 @@ void PSS_init(int freq, int stereo, int samples, int status) {
|
||||
ffpy_init(audio_spec.freq, status);
|
||||
|
||||
SDL_PauseAudio(0);
|
||||
|
||||
|
||||
initialized = 1;
|
||||
|
||||
error(SUCCESS);
|
||||
@@ -1102,7 +1102,7 @@ void PSS_quit() {
|
||||
if (! initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int i;
|
||||
|
||||
ENTER();
|
||||
@@ -1130,14 +1130,14 @@ void PSS_periodic() {
|
||||
}
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
while (dying) {
|
||||
struct Dying *d = dying;
|
||||
ffpy_stream_close(d->stream);
|
||||
dying = d->next;
|
||||
free(d);
|
||||
}
|
||||
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#define PSS_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
void PSS_play(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int fadeout, int tight, int paused);
|
||||
void PSS_queue(int channel, SDL_RWops *rw, const char *ext, PyObject *name, int fadeout, int tight);
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
cdef extern from "pygame/pygame.h":
|
||||
cdef extern from "SDL.h":
|
||||
cdef struct SDL_RWops:
|
||||
pass
|
||||
|
||||
void import_pygame_rwobject()
|
||||
cdef extern from "pygame_sdl2/pygame_sdl2.rwobject_api.h":
|
||||
|
||||
void import_pygame_sdl2__rwobject()
|
||||
SDL_RWops* RWopsFromPythonThreaded(object obj)
|
||||
|
||||
cdef extern from "pss.h":
|
||||
@@ -187,4 +189,4 @@ def check_version(version):
|
||||
if version < 2 or version > 4:
|
||||
raise Exception("pysdlsound version mismatch.")
|
||||
|
||||
import_pygame_rwobject()
|
||||
import_pygame_sdl2__rwobject()
|
||||
|
||||
+4
-3
@@ -2,9 +2,10 @@
|
||||
#define RENPY_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
void core_init(void);
|
||||
void subpixel_init(void);
|
||||
|
||||
void save_png_core(PyObject *pysurf, SDL_RWops *file, int compress);
|
||||
|
||||
@@ -62,7 +63,7 @@ void alphamunge_core(PyObject *pysrc,
|
||||
int src_aoff, // alpha offset.
|
||||
int dst_aoff, // alpha offset.
|
||||
char *amap);
|
||||
|
||||
|
||||
/* int stretch_core(PyObject *pysrc, */
|
||||
/* PyObject *pydst, */
|
||||
/* int x, */
|
||||
@@ -114,4 +115,4 @@ int subpixel32(
|
||||
float xoffset, float yoffset, int ashift);
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -65,7 +65,7 @@ else:
|
||||
|
||||
include("zlib.h")
|
||||
include("png.h")
|
||||
include("SDL.h", directory="SDL")
|
||||
include("SDL.h", directory="SDL2")
|
||||
include("ft2build.h")
|
||||
include("freetype/freetype.h", directory="freetype2", optional=True) or include("freetype.h", directory="freetype2")
|
||||
include("libavutil/avstring.h")
|
||||
@@ -74,7 +74,7 @@ include("libavcodec/avcodec.h")
|
||||
include("libswscale/swscale.h")
|
||||
include("GL/glew.h")
|
||||
|
||||
library("SDL")
|
||||
library("SDL2")
|
||||
library("png")
|
||||
library("avformat")
|
||||
library("avcodec")
|
||||
@@ -91,7 +91,7 @@ has_angle = windows and library("EGL", optional=True) and library("GLESv2", opti
|
||||
if android:
|
||||
sdl = [ 'sdl', 'GLESv2', 'log' ]
|
||||
else:
|
||||
sdl = [ 'SDL' ]
|
||||
sdl = [ 'SDL2' ]
|
||||
|
||||
if has_fribidi:
|
||||
try:
|
||||
|
||||
+41
-35
@@ -7,15 +7,21 @@
|
||||
*/
|
||||
|
||||
#include "renpy.h"
|
||||
#include <pygame/pygame.h>
|
||||
#include <SDL.h>
|
||||
#include <pygame_sdl2/pygame_sdl2.surface_api.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
void subpixel_init() {
|
||||
import_pygame_sdl2__surface();
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define GCC_MMX 1
|
||||
#include "mmx.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* MMX Register assignments (between applications of the blitter core).
|
||||
*
|
||||
* mm0 - new row 0
|
||||
@@ -33,7 +39,7 @@
|
||||
* This is the basic algorithm that does the subpixel blit
|
||||
* interpolation.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/* mm2 = destination; */
|
||||
|
||||
/* unpack mm0; */
|
||||
@@ -83,8 +89,8 @@
|
||||
#define MMX_EXPAND() \
|
||||
pxor_r2r(mm2, mm2); \
|
||||
punpcklbw_r2r(mm2, mm4); \
|
||||
punpcklbw_r2r(mm2, mm5);
|
||||
|
||||
punpcklbw_r2r(mm2, mm5);
|
||||
|
||||
|
||||
// This expects the two old pixels to be arranged like:
|
||||
// mm4 mm0
|
||||
@@ -140,7 +146,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
float xoffset, float yoffset, int ashift) {
|
||||
SDL_Surface *src;
|
||||
SDL_Surface *dst;
|
||||
|
||||
|
||||
int srcpitch, dstpitch;
|
||||
int srcw, srch;
|
||||
int dstw, dsth;
|
||||
@@ -148,7 +154,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
unsigned char *dstpixels;
|
||||
|
||||
int xfrac, yfrac;
|
||||
int xo, yo;
|
||||
int xo, yo;
|
||||
int sx, sy;
|
||||
|
||||
int draw_finalx;
|
||||
@@ -158,7 +164,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
|
||||
unsigned int pixel;
|
||||
unsigned int blankpixel;
|
||||
|
||||
|
||||
unsigned char *s0;
|
||||
unsigned char *s1;
|
||||
unsigned char *d;
|
||||
@@ -170,12 +176,12 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
if (!SDL_HasMMX()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
src = PySurface_AsSurface(pysrc);
|
||||
dst = PySurface_AsSurface(pydst);
|
||||
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
|
||||
srcpixels = (unsigned char *) src->pixels;
|
||||
dstpixels = (unsigned char *) dst->pixels;
|
||||
srcpitch = src->pitch;
|
||||
@@ -186,7 +192,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
dsth = dst->h;
|
||||
|
||||
inverted_alpha_mask = ~(0xff << ashift);
|
||||
|
||||
|
||||
// Due to mmx.
|
||||
ashift *= 2;
|
||||
|
||||
@@ -216,7 +222,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
if (sx >= srcw - 1 || sy >= srch - 1) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
// Figure out how many pixels we need to draw on each line.
|
||||
normal_pixels = min(srcw - sx - 1, dstw - xo);
|
||||
|
||||
@@ -236,7 +242,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
punpckldq_r2r(mm7, mm7);
|
||||
|
||||
movd_m2r(ashift, mm3);
|
||||
|
||||
|
||||
if (xo >= dstw) {
|
||||
goto done;
|
||||
}
|
||||
@@ -244,27 +250,27 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
// Draw the first line, when sy == -1.
|
||||
|
||||
if (sy == -1) {
|
||||
|
||||
|
||||
if (yo >= dsth) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
s1 = srcpixels + sx * 4;
|
||||
|
||||
|
||||
if (sx < 0) {
|
||||
pixel = (* (unsigned int *) (s1 + 4)) & inverted_alpha_mask;
|
||||
pixel = (* (unsigned int *) (s1 + 4)) & inverted_alpha_mask;
|
||||
} else {
|
||||
pixel = * (unsigned int *) s1;
|
||||
}
|
||||
|
||||
blankpixel = pixel & inverted_alpha_mask;
|
||||
|
||||
|
||||
movd_m2r(blankpixel, mm4);
|
||||
movd_m2r(pixel, mm5);
|
||||
|
||||
MMX_EXPAND();
|
||||
s1 += 4;
|
||||
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
dend = d + normal_pixels * 4;
|
||||
|
||||
@@ -272,7 +278,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
pixel = * (unsigned int *) s1;
|
||||
blankpixel = pixel & inverted_alpha_mask;
|
||||
movd_m2r(blankpixel, mm0);
|
||||
movd_m2r(pixel, mm1);
|
||||
movd_m2r(pixel, mm1);
|
||||
MMX_INTERP(* (unsigned int *) d);
|
||||
d += 4;
|
||||
s1 += 4;
|
||||
@@ -300,7 +306,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
|
||||
s0 = srcpixels + sx * 4 + (srcpitch * sy);
|
||||
s1 = srcpixels + sx * 4 + (srcpitch * (sy + 1));
|
||||
|
||||
|
||||
if (sx < 0) {
|
||||
blankpixel = (* (unsigned int *) (s0 + 4)) & inverted_alpha_mask;
|
||||
movd_m2r(blankpixel, mm4);
|
||||
@@ -314,20 +320,20 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
}
|
||||
|
||||
MMX_EXPAND();
|
||||
|
||||
|
||||
s0 += 4;
|
||||
s1 += 4;
|
||||
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
dend = d + normal_pixels * 4;
|
||||
|
||||
unsigned char *dp = d;
|
||||
|
||||
|
||||
while (d != dend) {
|
||||
movd_m2r(* (unsigned int *) s0, mm0);
|
||||
movd_m2r(* (unsigned int *) s1, mm1);
|
||||
movd_m2r(* (unsigned int *) s0, mm0);
|
||||
movd_m2r(* (unsigned int *) s1, mm1);
|
||||
MMX_INTERP(* (unsigned int *) d);
|
||||
|
||||
|
||||
d += 4;
|
||||
s0 += 4;
|
||||
s1 += 4;
|
||||
@@ -350,7 +356,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
}
|
||||
|
||||
// The final part, where we handle the bottom line of the source surface.
|
||||
|
||||
|
||||
if (yo >= dsth) {
|
||||
goto done;
|
||||
}
|
||||
@@ -360,29 +366,29 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
if (sx < 0) {
|
||||
pixel = * (unsigned int *) (s0 + 4);
|
||||
blankpixel = pixel & inverted_alpha_mask;
|
||||
|
||||
|
||||
movd_m2r(blankpixel, mm4);
|
||||
movd_m2r(blankpixel, mm5);
|
||||
} else {
|
||||
pixel = * (unsigned int *) s0;
|
||||
blankpixel = pixel & inverted_alpha_mask;
|
||||
|
||||
|
||||
movd_m2r(pixel, mm4);
|
||||
movd_m2r(blankpixel, mm5);
|
||||
}
|
||||
|
||||
MMX_EXPAND();
|
||||
|
||||
|
||||
s0 += 4;
|
||||
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
dend = d + normal_pixels * 4;
|
||||
|
||||
while (d != dend) {
|
||||
pixel = * (unsigned int *) s0;
|
||||
blankpixel = pixel & inverted_alpha_mask;
|
||||
|
||||
movd_m2r(pixel, mm0);
|
||||
|
||||
movd_m2r(pixel, mm0);
|
||||
movd_m2r(blankpixel, mm1);
|
||||
MMX_INTERP(* (unsigned int *) d);
|
||||
d += 4;
|
||||
@@ -395,7 +401,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
MMX_INTERP(* (unsigned int *) d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
done:
|
||||
|
||||
// Reset the MMX unit and call it a night.
|
||||
@@ -403,7 +409,7 @@ done:
|
||||
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,18 @@ def path_to_common(renpy_base):
|
||||
def path_to_saves(gamedir):
|
||||
import renpy #@UnresolvedImport
|
||||
|
||||
# Makes sure the permissions are right on the save directory.
|
||||
def test_writable(d):
|
||||
try:
|
||||
fn = os.path.join(d, "test.txt")
|
||||
open(fn, "w").close()
|
||||
open(fn, "r").close()
|
||||
os.unlink(fn)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
# Android.
|
||||
if renpy.android:
|
||||
paths = [
|
||||
@@ -50,7 +62,7 @@ def path_to_saves(gamedir):
|
||||
]
|
||||
|
||||
for rv in paths:
|
||||
if os.path.isdir(rv):
|
||||
if os.path.isdir(rv) and test_writable(rv):
|
||||
break
|
||||
|
||||
print "Using savedir", rv
|
||||
@@ -98,7 +110,6 @@ def path_to_saves(gamedir):
|
||||
# the launcher, usually.)
|
||||
def path_to_renpy_base():
|
||||
renpy_base = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
renpy_base = os.environ.get('RENPY_BASE', renpy_base)
|
||||
renpy_base = os.path.abspath(renpy_base)
|
||||
|
||||
return renpy_base
|
||||
|
||||
+10
-5
@@ -40,7 +40,7 @@ except ImportError:
|
||||
vc_version = 0
|
||||
|
||||
# The tuple giving the version number.
|
||||
version_tuple = (6, 18, 0, vc_version)
|
||||
version_tuple = (6, 18, 3, vc_version)
|
||||
|
||||
# The name of this version.
|
||||
version_name = "... through shared popular culture."
|
||||
@@ -240,6 +240,8 @@ def import_all():
|
||||
# Adds in the Ren'Py loader.
|
||||
import renpy.loader
|
||||
|
||||
import renpy.pyanalysis
|
||||
|
||||
import renpy.ast
|
||||
import renpy.atl
|
||||
import renpy.curry
|
||||
@@ -318,17 +320,20 @@ def import_all():
|
||||
import renpy.ui
|
||||
import renpy.screenlang
|
||||
|
||||
import renpy.sl2 # @UnresolvedImport
|
||||
import renpy.sl2
|
||||
update_path(renpy.sl2)
|
||||
|
||||
import renpy.sl2.pyutil # @UnresolvedImport
|
||||
import renpy.sl2.slparser # @UnresolvedImport
|
||||
import renpy.sl2.sldisplayables # @UnresolvedImport
|
||||
import renpy.sl2.slast
|
||||
import renpy.sl2.slparser
|
||||
import renpy.sl2.sldisplayables
|
||||
|
||||
import renpy.lint
|
||||
import renpy.warp
|
||||
|
||||
import renpy.editor
|
||||
|
||||
import renpy.memory
|
||||
|
||||
import renpy.exports
|
||||
import renpy.character # depends on exports. @UnresolvedImport
|
||||
|
||||
|
||||
+55
-14
@@ -439,6 +439,14 @@ class Node(object):
|
||||
|
||||
raise Exception("Not Implemented")
|
||||
|
||||
def analyze(self):
|
||||
"""
|
||||
Called on all code after the init phase, to analyze it.
|
||||
"""
|
||||
|
||||
# Does nothing by default.
|
||||
return
|
||||
|
||||
def say_menu_with(expression, callback):
|
||||
"""
|
||||
This handles the with clause of a say or menu statement.
|
||||
@@ -470,7 +478,14 @@ def eval_who(who, fast=None):
|
||||
fast = bool(re.match(renpy.parser.word_regexp + "$", who))
|
||||
|
||||
if fast:
|
||||
rv = renpy.python.store_dicts['store'].get(who, None)
|
||||
|
||||
if 'store.character' in renpy.python.store_dicts:
|
||||
rv = renpy.python.store_dicts['store.character'].get(who, None)
|
||||
else:
|
||||
rv = None
|
||||
|
||||
if rv is None:
|
||||
rv = renpy.python.store_dicts['store'].get(who, None)
|
||||
|
||||
if rv is None:
|
||||
raise Exception("Sayer '%s' is not defined." % who.encode("utf-8"))
|
||||
@@ -907,6 +922,9 @@ class Transform(Node):
|
||||
renpy.exports.pure(self.varname)
|
||||
setattr(renpy.store, self.varname, trans)
|
||||
|
||||
def analyze(self):
|
||||
self.atl.mark_constant()
|
||||
|
||||
|
||||
def predict_imspec(imspec, scene=False, atl=None):
|
||||
"""
|
||||
@@ -990,6 +1008,7 @@ def show_imspec(imspec, atl=None):
|
||||
behind=behind,
|
||||
atl=atl)
|
||||
|
||||
|
||||
class Show(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1055,6 +1074,10 @@ class ShowLayer(Node):
|
||||
def predict(self):
|
||||
return [ self.next ]
|
||||
|
||||
def analyze(self):
|
||||
if self.atl is not None:
|
||||
self.atl.mark_constant()
|
||||
|
||||
|
||||
class Scene(Node):
|
||||
|
||||
@@ -1103,6 +1126,10 @@ class Scene(Node):
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
def analyze(self):
|
||||
if self.atl is not None:
|
||||
self.atl.mark_constant()
|
||||
|
||||
|
||||
class Hide(Node):
|
||||
|
||||
@@ -1256,10 +1283,13 @@ class Call(Node):
|
||||
renpy.store._kwargs = kwargs
|
||||
|
||||
def predict(self):
|
||||
|
||||
label = self.label
|
||||
|
||||
if self.expression:
|
||||
return [ ]
|
||||
else:
|
||||
return [ renpy.game.script.lookup(self.label) ]
|
||||
label = renpy.python.py_eval(label)
|
||||
|
||||
return [ renpy.game.context().predict_call(label, self.next.name) ]
|
||||
|
||||
def scry(self):
|
||||
rv = Node.scry(self)
|
||||
@@ -1301,11 +1331,8 @@ class Return(Node):
|
||||
next_node(renpy.game.context().lookup_return(pop=True))
|
||||
|
||||
def predict(self):
|
||||
site = renpy.game.context().lookup_return(pop=False)
|
||||
if site:
|
||||
return [ site ]
|
||||
else:
|
||||
return [ ]
|
||||
|
||||
return [ renpy.game.context().predict_return() ]
|
||||
|
||||
def scry(self):
|
||||
rv = Node.scry(self)
|
||||
@@ -1655,9 +1682,14 @@ class Define(Node):
|
||||
__slots__ = [
|
||||
'varname',
|
||||
'code',
|
||||
'store',
|
||||
]
|
||||
|
||||
def __init__(self, loc, name, expr):
|
||||
def __setstate__(self, state):
|
||||
self.store = 'store'
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
def __init__(self, loc, store, name, expr):
|
||||
"""
|
||||
@param name: The name of the image being defined.
|
||||
|
||||
@@ -1667,11 +1699,15 @@ class Define(Node):
|
||||
|
||||
super(Define, self).__init__(loc)
|
||||
|
||||
self.store = store
|
||||
self.varname = name
|
||||
self.code = PyCode(expr, loc=loc, mode='eval')
|
||||
|
||||
def diff_info(self):
|
||||
return (Define, tuple(self.varname))
|
||||
return (Define, self.store, self.varname)
|
||||
|
||||
def early_execute(self):
|
||||
renpy.python.create_store(self.store)
|
||||
|
||||
def execute(self):
|
||||
|
||||
@@ -1679,9 +1715,14 @@ class Define(Node):
|
||||
statement_name("define")
|
||||
|
||||
value = renpy.python.py_eval_bytecode(self.code.bytecode)
|
||||
renpy.dump.definitions.append((self.varname, self.filename, self.linenumber))
|
||||
renpy.exports.pure(self.varname)
|
||||
renpy.python.store_dicts["store"][self.varname] = value
|
||||
|
||||
if self.store == 'store':
|
||||
renpy.exports.pure(self.varname)
|
||||
renpy.dump.definitions.append((self.varname, self.filename, self.linenumber))
|
||||
else:
|
||||
renpy.dump.definitions.append((self.store[6:] + "." + self.varname, self.filename, self.linenumber))
|
||||
|
||||
renpy.python.store_dicts[self.store][self.varname] = value
|
||||
|
||||
|
||||
class Screen(Node):
|
||||
|
||||
+191
-21
@@ -20,6 +20,8 @@
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import renpy.display
|
||||
import renpy.pyanalysis
|
||||
|
||||
import random
|
||||
|
||||
def compiling(loc):
|
||||
@@ -85,6 +87,7 @@ PROPERTIES = {
|
||||
"angle" : float,
|
||||
"radius" : float,
|
||||
"crop" : (float, float, float, float),
|
||||
"crop_relative" : bool,
|
||||
"size" : (int, int),
|
||||
"corner1" : (float, float),
|
||||
"corner2" : (float, float),
|
||||
@@ -179,6 +182,23 @@ def interpolate_spline(t, spline):
|
||||
|
||||
return correct_type(rv, spline[-1], position)
|
||||
|
||||
# A list of atl transforms that may need to be compile.
|
||||
compile_queue = [ ]
|
||||
|
||||
def compile_all():
|
||||
"""
|
||||
Called after the init phase is finished and transforms are compiled,
|
||||
to compile all transforms.
|
||||
"""
|
||||
|
||||
global compile_queue
|
||||
|
||||
for i in compile_queue:
|
||||
if i.atl.constant == GLOBAL_CONST:
|
||||
i.compile()
|
||||
|
||||
compile_queue = [ ]
|
||||
|
||||
|
||||
# This is the context used when compiling an ATL statement. It stores the
|
||||
# scopes that are used to evaluate the various expressions in the statement,
|
||||
@@ -204,6 +224,10 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
# Compatibility with older saves.
|
||||
parameters = renpy.ast.ParameterInfo([ ], [ ], None, None)
|
||||
parent_transform = None
|
||||
atl_st_offset = 0
|
||||
|
||||
nosave = [ 'parent_transform' ]
|
||||
|
||||
def __init__(self, atl, context, parameters):
|
||||
|
||||
@@ -248,20 +272,38 @@ class ATLTransformBase(renpy.object.Object):
|
||||
# The child, without any transformations.
|
||||
self.raw_child = None
|
||||
|
||||
# The parent transform that was called to create this transform.
|
||||
self.parent_transform = None
|
||||
|
||||
# The offset between st and when this ATL block first executed.
|
||||
self.atl_st_offset = 0
|
||||
|
||||
if renpy.game.context().init_phase:
|
||||
compile_queue.append(self)
|
||||
|
||||
def take_execution_state(self, t):
|
||||
"""
|
||||
Updates self to begin executing from the same point as t. This
|
||||
requires that t.atl is self.atl.
|
||||
"""
|
||||
|
||||
if t.atl is not self.atl:
|
||||
return
|
||||
|
||||
if t.context != self.context:
|
||||
return
|
||||
|
||||
super(ATLTransformBase, self).take_execution_state(t)
|
||||
|
||||
self.atl_st_offset = None
|
||||
|
||||
if not isinstance(t, ATLTransformBase):
|
||||
return
|
||||
elif t.atl is not self.atl:
|
||||
return
|
||||
|
||||
# Important to do it this way, so we use __eq__. The exception handling
|
||||
# optimistically assumes that uncomparable objects are the same.
|
||||
try:
|
||||
if not (t.context == self.context):
|
||||
return
|
||||
except:
|
||||
pass
|
||||
|
||||
self.done = t.done
|
||||
self.block = t.block
|
||||
self.atl_state = t.atl_state
|
||||
@@ -274,12 +316,13 @@ class ATLTransformBase(renpy.object.Object):
|
||||
self.st_offset = t.st_offset
|
||||
self.at_offset = t.at_offset
|
||||
|
||||
self.atl_st_offset = t.atl_st_offset
|
||||
|
||||
if self.child is renpy.display.motion.null:
|
||||
self.child = t.child
|
||||
self.raw_child = t.raw_child
|
||||
|
||||
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
|
||||
context = self.context.context.copy()
|
||||
@@ -329,7 +372,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
child = renpy.display.motion.get_null()
|
||||
|
||||
# Create a new ATL Transform.
|
||||
parameters = renpy.ast.ParameterInfo({}, positional, None, None)
|
||||
parameters = renpy.ast.ParameterInfo({ }, positional, None, None)
|
||||
|
||||
rv = renpy.display.motion.ATLTransform(
|
||||
atl=self.atl,
|
||||
@@ -338,6 +381,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
context=context,
|
||||
parameters=parameters)
|
||||
|
||||
rv.parent_transform = self
|
||||
rv.take_state(self)
|
||||
|
||||
return rv
|
||||
@@ -349,8 +393,23 @@ class ATLTransformBase(renpy.object.Object):
|
||||
properties.
|
||||
"""
|
||||
|
||||
if self.parameters.positional and self.parameters.positional[0][1] is None:
|
||||
raise Exception("Cannot compile ATL Transform, as it's missing positional parameter %s." % self.parameters.positional[0])
|
||||
constant = (self.atl.constant == GLOBAL_CONST)
|
||||
|
||||
if not constant:
|
||||
for p in self.parameters.positional:
|
||||
if p not in self.context.context:
|
||||
raise Exception("Cannot compile ATL Transform at %s:%d, as it's missing positional parameter %s." % (
|
||||
self.atl.loc[0],
|
||||
self.atl.loc[1],
|
||||
self.parameters.positional[0],
|
||||
))
|
||||
|
||||
if constant and self.parent_transform:
|
||||
if self.parent_transform.block:
|
||||
self.block = self.parent_transform.block
|
||||
self.properties = self.parent_transform.properties
|
||||
self.parent_transform = None
|
||||
return
|
||||
|
||||
old_exception_info = renpy.game.exception_info
|
||||
|
||||
@@ -366,6 +425,11 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
renpy.game.exception_info = old_exception_info
|
||||
|
||||
if constant and self.parent_transform:
|
||||
self.parent_transform.block = self.block
|
||||
self.parent_transform.properties = self.properties
|
||||
self.parent_transform = None
|
||||
|
||||
|
||||
def execute(self, trans, st, at):
|
||||
|
||||
@@ -397,17 +461,18 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
old_exception_info = renpy.game.exception_info
|
||||
|
||||
if (self.atl_st_offset is None) or (st - self.atl_st_offset) < 0:
|
||||
self.atl_st_offset = st
|
||||
|
||||
if self.atl.animation:
|
||||
timebase = at
|
||||
else:
|
||||
timebase = st
|
||||
timebase = st - self.atl_st_offset
|
||||
|
||||
action, arg, pause = self.block.execute(trans, timebase, self.atl_state, event)
|
||||
|
||||
renpy.game.exception_info = old_exception_info
|
||||
|
||||
# print "Executing", self, self.state, self.xpos, self.ypos
|
||||
|
||||
if action == "continue":
|
||||
self.atl_state = arg
|
||||
else:
|
||||
@@ -424,10 +489,15 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
return self.children + self.block.visit()
|
||||
|
||||
# This is used in mark_constant to analyze expressions for constness.
|
||||
is_constant_expr = renpy.pyanalysis.Analysis().is_constant_expr
|
||||
GLOBAL_CONST = renpy.pyanalysis.GLOBAL_CONST
|
||||
|
||||
# The base class for raw ATL statements.
|
||||
class RawStatement(renpy.object.Object):
|
||||
|
||||
constant = None
|
||||
|
||||
def __init__(self, loc):
|
||||
super(RawStatement, self).__init__()
|
||||
self.loc = loc
|
||||
@@ -441,6 +511,14 @@ class RawStatement(renpy.object.Object):
|
||||
def predict(self, ctx):
|
||||
return
|
||||
|
||||
def mark_constant(self):
|
||||
"""
|
||||
Sets self.constant to true if all expressions used in this statement
|
||||
and its children are constant.
|
||||
"""
|
||||
|
||||
self.constant = 0
|
||||
|
||||
# The base class for compiled ATL Statements.
|
||||
class Statement(renpy.object.Object):
|
||||
|
||||
@@ -506,6 +584,16 @@ class RawBlock(RawStatement):
|
||||
for i in self.statements:
|
||||
i.predict(ctx)
|
||||
|
||||
def mark_constant(self):
|
||||
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
for i in self.statements:
|
||||
i.mark_constant()
|
||||
constant = min(constant, i.constant)
|
||||
|
||||
self.constant = constant
|
||||
|
||||
|
||||
# A compiled ATL block.
|
||||
class Block(Statement):
|
||||
@@ -760,6 +848,27 @@ class RawMultipurpose(RawStatement):
|
||||
|
||||
return Interpolation(self.loc, warper, duration, properties, self.revolution, circles, splines)
|
||||
|
||||
def mark_constant(self):
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
constant = min(constant, is_constant_expr(self.warp_function))
|
||||
constant = min(constant, is_constant_expr(self.duration))
|
||||
constant = min(constant, is_constant_expr(self.circles))
|
||||
|
||||
for _name, expr in self.properties:
|
||||
constant = min(constant, is_constant_expr(expr))
|
||||
|
||||
for _name, exprs in self.splines:
|
||||
for expr in exprs:
|
||||
constant = min(constant, is_constant_expr(expr))
|
||||
|
||||
for expr, withexpr in self.expressions:
|
||||
constant = min(constant, is_constant_expr(expr))
|
||||
constant = min(constant, is_constant_expr(withexpr))
|
||||
|
||||
self.constant = constant
|
||||
|
||||
|
||||
def predict(self, ctx):
|
||||
|
||||
for i, _j in self.expressions:
|
||||
@@ -792,6 +901,9 @@ class RawContainsExpr(RawStatement):
|
||||
child = ctx.eval(self.expression)
|
||||
return Child(self.loc, child, None)
|
||||
|
||||
def mark_constant(self):
|
||||
self.constant = is_constant_expr(self.expression)
|
||||
|
||||
|
||||
# This allows us to have multiple children, inside a Fixed.
|
||||
class RawChild(RawStatement):
|
||||
@@ -810,6 +922,16 @@ class RawChild(RawStatement):
|
||||
|
||||
return Child(self.loc, box, None)
|
||||
|
||||
def mark_constant(self):
|
||||
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
for i in self.children:
|
||||
i.mark_constant()
|
||||
constant = min(constant, i.constant)
|
||||
|
||||
self.constant = constant
|
||||
|
||||
|
||||
# This changes the child of this statement, optionally with a transition.
|
||||
class Child(Statement):
|
||||
@@ -996,6 +1118,9 @@ class RawRepeat(RawStatement):
|
||||
|
||||
return Repeat(self.loc, repeats)
|
||||
|
||||
def mark_constant(self):
|
||||
self.constant = is_constant_expr(self.repeats)
|
||||
|
||||
class Repeat(Statement):
|
||||
|
||||
def __init__(self, loc, repeats):
|
||||
@@ -1024,6 +1149,14 @@ class RawParallel(RawStatement):
|
||||
for i in self.blocks:
|
||||
i.predict(ctx)
|
||||
|
||||
def mark_constant(self):
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
for i in self.blocks:
|
||||
i.mark_constant()
|
||||
constant = min(constant, i.constant)
|
||||
|
||||
self.constant = constant
|
||||
|
||||
class Parallel(Statement):
|
||||
|
||||
@@ -1087,6 +1220,15 @@ class RawChoice(RawStatement):
|
||||
for _i, j in self.choices:
|
||||
j.predict(ctx)
|
||||
|
||||
def mark_constant(self):
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
for _chance, block in self.choices:
|
||||
block.mark_constant()
|
||||
constant = min(constant, block.constant)
|
||||
|
||||
self.constant = constant
|
||||
|
||||
class Choice(Statement):
|
||||
|
||||
def __init__(self, loc, choices):
|
||||
@@ -1141,6 +1283,9 @@ class RawTime(RawStatement):
|
||||
compiling(self.loc)
|
||||
return Time(self.loc, ctx.eval(self.time))
|
||||
|
||||
def mark_constant(self):
|
||||
self.constant = is_constant_expr(self.time)
|
||||
|
||||
class Time(Statement):
|
||||
|
||||
def __init__(self, loc, time):
|
||||
@@ -1156,10 +1301,13 @@ class Time(Statement):
|
||||
|
||||
class RawOn(RawStatement):
|
||||
|
||||
def __init__(self, loc, name, block):
|
||||
def __init__(self, loc, names, block):
|
||||
super(RawOn, self).__init__(loc)
|
||||
|
||||
self.handlers = { name : block }
|
||||
self.handlers = { }
|
||||
|
||||
for i in names:
|
||||
self.handlers[i] = block
|
||||
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
|
||||
@@ -1176,6 +1324,16 @@ class RawOn(RawStatement):
|
||||
for i in self.handlers.itervalues():
|
||||
i.predict(ctx)
|
||||
|
||||
def mark_constant(self):
|
||||
constant = GLOBAL_CONST
|
||||
|
||||
for block in self.handlers.itervalues():
|
||||
block.mark_constant()
|
||||
constant = min(constant, block.constant)
|
||||
|
||||
self.constant = constant
|
||||
|
||||
|
||||
class On(Statement):
|
||||
|
||||
def __init__(self, loc, handlers):
|
||||
@@ -1197,14 +1355,14 @@ class On(Statement):
|
||||
# handle it.
|
||||
if event in self.handlers:
|
||||
|
||||
# Do not allow people to abort the hide handler with another
|
||||
# event.
|
||||
if name != "hide":
|
||||
# Do not allow people to abort the hide or replaced event.
|
||||
lock_event = (name == "hide" and trans.hide_request) or (name == "replaced" and trans.replaced_request)
|
||||
|
||||
if not lock_event:
|
||||
name = event
|
||||
start = st
|
||||
cstate = None
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
# If we don't have a handler, return until we change event.
|
||||
@@ -1266,6 +1424,8 @@ class RawEvent(RawStatement):
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
return Event(self.loc, self.name)
|
||||
|
||||
def mark_constant(self):
|
||||
self.constant = GLOBAL_CONST
|
||||
|
||||
class Event(Statement):
|
||||
|
||||
@@ -1289,6 +1449,8 @@ class RawFunction(RawStatement):
|
||||
compiling(self.loc)
|
||||
return Function(self.loc, ctx.eval(self.expr))
|
||||
|
||||
def mark_constant(self):
|
||||
self.constant = is_constant_expr(self.expr)
|
||||
|
||||
class Function(Statement):
|
||||
|
||||
@@ -1374,14 +1536,22 @@ def parse_atl(l):
|
||||
|
||||
elif l.keyword('on'):
|
||||
|
||||
name = l.require(l.word)
|
||||
names = [ l.require(l.word) ]
|
||||
|
||||
while l.match(','):
|
||||
name = l.word()
|
||||
|
||||
if name is None:
|
||||
break
|
||||
|
||||
names.append(name)
|
||||
|
||||
l.require(':')
|
||||
l.expect_eol()
|
||||
l.expect_block('on')
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(RawOn(loc, name, block))
|
||||
statements.append(RawOn(loc, names, block))
|
||||
|
||||
elif l.keyword('time'):
|
||||
time = l.require(l.simple_expression)
|
||||
|
||||
+10
-7
@@ -23,12 +23,6 @@
|
||||
|
||||
import renpy.audio
|
||||
|
||||
# A list of music channels.
|
||||
music_channels = [ ]
|
||||
|
||||
# A list of channels for which set_music has been called, either way.
|
||||
music_set = [ ]
|
||||
|
||||
from renpy.audio.audio import get_channel, get_serial
|
||||
|
||||
# Part of the public api:
|
||||
@@ -256,6 +250,16 @@ def set_music(channel, flag, default=False):
|
||||
c.default_loop = flag
|
||||
c.default_loop_set = True
|
||||
|
||||
|
||||
def is_music(channel):
|
||||
"""
|
||||
Returns true if "channel" will loop by default.
|
||||
"""
|
||||
|
||||
c = get_channel(channel)
|
||||
return c.default_loop
|
||||
|
||||
|
||||
def get_delay(time, channel="music"):
|
||||
"""
|
||||
Returns the number of seconds left until the given time in the
|
||||
@@ -307,7 +311,6 @@ def is_playing(channel="music"):
|
||||
|
||||
return (get_playing(channel=channel) is not None)
|
||||
|
||||
|
||||
def set_volume(volume, delay=0, channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
@@ -182,6 +182,10 @@ def bootstrap(renpy_base):
|
||||
else:
|
||||
basedir = renpy_base
|
||||
|
||||
if not os.path.exists(basedir):
|
||||
sys.stderr.write("Base directory %r does not exist. Giving up.\n" % (basedir,))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
gamedirs = [ name ]
|
||||
game_name = name
|
||||
@@ -221,6 +225,8 @@ def bootstrap(renpy_base):
|
||||
if renpy.macintosh:
|
||||
os.startfile = mac_start
|
||||
|
||||
import pygame_sdl2
|
||||
pygame_sdl2.import_as_pygame()
|
||||
|
||||
# Check that we have installed pygame properly. This also deals with
|
||||
# weird cases on Windows and Linux where we can't import modules. (On
|
||||
|
||||
+6
-1
@@ -404,7 +404,7 @@ def display_say(
|
||||
|
||||
# Figure out which pause we're on. (Or set the pause to None in
|
||||
# order to put us in all-at-once mode.)
|
||||
if not interact:
|
||||
if not interact or renpy.game.preferences.self_voicing:
|
||||
all_at_once = True
|
||||
|
||||
dtt = DialogueTextTags(what)
|
||||
@@ -476,6 +476,8 @@ def display_say(
|
||||
what_text.slow = slow
|
||||
what_text.slow_done = slow_done
|
||||
|
||||
what_text.update()
|
||||
|
||||
for c in callback:
|
||||
c("show_done", interact=interact, type=type, **cb_args)
|
||||
|
||||
@@ -760,6 +762,9 @@ class ADVCharacter(object):
|
||||
if not (self.condition is None or renpy.python.py_eval(self.condition)):
|
||||
return True
|
||||
|
||||
if not isinstance(what, basestring):
|
||||
raise Exception("Character expects its what argument to be a string, got %r." % (what,))
|
||||
|
||||
self.resolve_say_attributes(False)
|
||||
|
||||
old_side_image_attributes = renpy.store._side_image_attributes
|
||||
|
||||
@@ -35,27 +35,48 @@ init -1500 python:
|
||||
The channel to play the sound on.
|
||||
`file`
|
||||
The file to play.
|
||||
`selected`
|
||||
If True, buttons using this action will be marked as selected
|
||||
if the file is playing on the channel. If False, this action
|
||||
will not cause the button to start playing. If None, the button
|
||||
is marked selected if the channel is a music channel, and not
|
||||
otherwise.
|
||||
|
||||
Any keyword arguments are passed to :func:`renpy.music.play`
|
||||
Any other keyword arguments are passed to :func:`renpy.music.play`.
|
||||
"""
|
||||
|
||||
equality_fields = ["channel", "file", "kwargs"]
|
||||
equality_fields = ["channel", "file", "kwargs", "can_be_selected" ]
|
||||
|
||||
def __init__(self, channel, file, **kwargs):
|
||||
can_be_selected = False
|
||||
|
||||
def __init__(self, channel, file, selected=None, **kwargs):
|
||||
self.channel = channel
|
||||
self.file = file
|
||||
self.kwargs = kwargs
|
||||
self.selected = self.get_selected()
|
||||
|
||||
if selected is None:
|
||||
selected = renpy.music.is_music(channel)
|
||||
|
||||
self.can_be_selected = selected
|
||||
self.get_selected()
|
||||
|
||||
def __call__(self):
|
||||
renpy.music.play(self.file, channel=self.channel, **self.kwargs)
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
return renpy.music.get_playing(self.channel) == self.file
|
||||
if not self.can_be_selected:
|
||||
self.selected = False
|
||||
return False
|
||||
|
||||
self.selected = (renpy.music.get_playing(self.channel) == self.file)
|
||||
return self.selected
|
||||
|
||||
def periodic(self, st):
|
||||
if self.selected != self.get_selected():
|
||||
if not self.can_be_selected:
|
||||
return None
|
||||
|
||||
if self.selected != (renpy.music.get_playing(self.channel) == self.file):
|
||||
renpy.restart_interaction()
|
||||
|
||||
return .1
|
||||
|
||||
@@ -84,8 +84,9 @@ init -1600 python:
|
||||
|
||||
return self.dict[self.key] == self.value
|
||||
|
||||
|
||||
@renpy.pure
|
||||
def SetScreenVariable(name, value):
|
||||
class SetScreenVariable(Action, FieldEquality):
|
||||
"""
|
||||
:doc: data_action
|
||||
|
||||
@@ -93,11 +94,34 @@ init -1600 python:
|
||||
be set to `value`.
|
||||
"""
|
||||
|
||||
cs = renpy.current_screen()
|
||||
if cs is not None:
|
||||
return SetDict(cs.scope, name, value)
|
||||
else:
|
||||
return None
|
||||
identity_fields = [ "name", "value" ]
|
||||
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def __call__(self):
|
||||
|
||||
cs = renpy.current_screen()
|
||||
|
||||
if cs is None:
|
||||
return
|
||||
|
||||
cs.scope[self.name] = self.value
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
|
||||
cs = renpy.current_screen()
|
||||
|
||||
if cs is None:
|
||||
return False
|
||||
|
||||
if self.name not in cs.scope:
|
||||
return False
|
||||
|
||||
return cs.scope[self.name] == self.value
|
||||
|
||||
|
||||
@renpy.pure
|
||||
class ToggleField(Action, FieldEquality):
|
||||
@@ -162,6 +186,8 @@ init -1600 python:
|
||||
|
||||
return ToggleField(store, variable, true_value=true_value, false_value=false_value)
|
||||
|
||||
|
||||
|
||||
@renpy.pure
|
||||
class ToggleDict(Action, FieldEquality):
|
||||
"""
|
||||
@@ -202,6 +228,9 @@ init -1600 python:
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
if self.key not in self.dict:
|
||||
return False
|
||||
|
||||
rv = self.dict[self.key]
|
||||
|
||||
if self.true_value is not None:
|
||||
@@ -209,8 +238,10 @@ init -1600 python:
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
@renpy.pure
|
||||
def ToggleScreenVariable(name, true_value=None, false_value=None):
|
||||
class ToggleScreenVariable(Action, FieldEquality):
|
||||
"""
|
||||
:doc: data_action
|
||||
|
||||
@@ -222,10 +253,48 @@ init -1600 python:
|
||||
If not None, then this is the false value we use.
|
||||
"""
|
||||
|
||||
cs = renpy.current_screen()
|
||||
identity_fields = [ "name", "true_value", "false_value" ]
|
||||
|
||||
if cs is not None:
|
||||
return ToggleDict(cs.scope, name, true_value=true_value, false_value=None)
|
||||
else:
|
||||
return None
|
||||
def __init__(self, name, true_value=None, false_value=None):
|
||||
self.name = name
|
||||
self.true_value = true_value
|
||||
self.false_value = false_value
|
||||
|
||||
def __call__(self):
|
||||
cs = renpy.current_screen()
|
||||
|
||||
if cs is None:
|
||||
return
|
||||
|
||||
value = cs.scope[self.name]
|
||||
|
||||
if self.true_value is not None:
|
||||
value = (value == self.true_value)
|
||||
|
||||
value = not value
|
||||
|
||||
if self.true_value is not None:
|
||||
if value:
|
||||
value = self.true_value
|
||||
else:
|
||||
value = self.false_value
|
||||
|
||||
cs.scope[self.name] = value
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
cs = renpy.current_screen()
|
||||
|
||||
if cs is None:
|
||||
return False
|
||||
|
||||
if self.name not in cs.scope:
|
||||
return False
|
||||
|
||||
rv = cs.scope[self.name]
|
||||
|
||||
if self.true_value is not None:
|
||||
rv = (rv == self.true_value)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
@@ -320,7 +320,7 @@ init -1500 python:
|
||||
|
||||
if not main_menu:
|
||||
if self.confirm:
|
||||
if config.autosave_on_quit:
|
||||
if config.autosave_on_quit and not fn.startswith("auto-"):
|
||||
renpy.loadsave.force_autosave()
|
||||
layout.yesno_screen(layout.LOADING, FileLoad(self.name, False, self.page))
|
||||
return
|
||||
|
||||
@@ -124,7 +124,7 @@ init -1500 python:
|
||||
@renpy.pure
|
||||
class HideInterface(Action, DictEquality):
|
||||
"""
|
||||
:doc other_action
|
||||
:doc: other_action
|
||||
|
||||
Causes the interface to be hidden until the user clicks.
|
||||
"""
|
||||
@@ -207,7 +207,7 @@ init -1500 python:
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
return renpy.roll_forward_info()
|
||||
return renpy.exports.roll_forward_core()
|
||||
|
||||
def get_sensitive(self):
|
||||
return renpy.roll_forward_info() is not None
|
||||
|
||||
+17
-6
@@ -24,6 +24,8 @@ init -1500 python in iap:
|
||||
from store import persistent, Action
|
||||
import time
|
||||
|
||||
background = "black"
|
||||
|
||||
class Product(object):
|
||||
"""
|
||||
A data object representing a product.
|
||||
@@ -105,6 +107,7 @@ init -1500 python in iap:
|
||||
|
||||
while True:
|
||||
rv = self.devicePurchase.checkPurchaseResult()
|
||||
|
||||
if rv:
|
||||
break
|
||||
|
||||
@@ -121,7 +124,6 @@ init -1500 python in iap:
|
||||
|
||||
def purchase(self, p, interact=True):
|
||||
identifier = self.identifier(p)
|
||||
|
||||
self.devicePurchase.beginPurchase(identifier)
|
||||
return self.wait_for_result(interact=interact)
|
||||
|
||||
@@ -176,6 +178,15 @@ init -1500 python in iap:
|
||||
p = Product(product, identifier, google, amazon)
|
||||
products[product] = p
|
||||
|
||||
def with_background(f, *args, **kwargs):
|
||||
"""
|
||||
Displays the background, then invokes `f`.
|
||||
"""
|
||||
|
||||
renpy.scene()
|
||||
renpy.show(background)
|
||||
return f(*args, **kwargs)
|
||||
|
||||
def restore(interact=True):
|
||||
"""
|
||||
:doc: iap
|
||||
@@ -200,7 +211,7 @@ init -1500 python in iap:
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
restore(False)
|
||||
renpy.invoke_in_new_context(with_background, restore)
|
||||
|
||||
def get_sensitive(self):
|
||||
return get_store_name()
|
||||
@@ -212,7 +223,7 @@ init -1500 python in iap:
|
||||
|
||||
return p
|
||||
|
||||
def purchase(product, interact=False):
|
||||
def purchase(product, interact=True):
|
||||
"""
|
||||
:doc: iap
|
||||
|
||||
@@ -247,7 +258,7 @@ init -1500 python in iap:
|
||||
self.product = product
|
||||
|
||||
def __call__(self):
|
||||
purchase(self.product, interact=False)
|
||||
renpy.invoke_in_new_context(with_background, purchase, self.product)
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_sensitive(self):
|
||||
@@ -321,8 +332,8 @@ init -1500 python in iap:
|
||||
else:
|
||||
backend = NoneBackend()
|
||||
|
||||
# If there are any missing products, restore purchases.
|
||||
if missing_products():
|
||||
# Restore purchases.
|
||||
if products:
|
||||
restore(False)
|
||||
|
||||
init 1500 python in iap:
|
||||
|
||||
+46
-14
@@ -34,7 +34,7 @@ init -1700 python:
|
||||
if self is o:
|
||||
return True
|
||||
|
||||
if type(self) is type(o):
|
||||
if _type(self) is _type(o):
|
||||
return (self.__dict__ == o.__dict__)
|
||||
|
||||
return False
|
||||
@@ -53,7 +53,7 @@ init -1700 python:
|
||||
if self is o:
|
||||
return True
|
||||
|
||||
if type(self) is not type(o):
|
||||
if _type(self) is not _type(o):
|
||||
return False
|
||||
|
||||
for k in self.equality_fields:
|
||||
@@ -92,12 +92,9 @@ init -1700 python:
|
||||
|
||||
config.empty_window = _default_empty_window
|
||||
|
||||
style.skip_indicator = Style(style.default, heavy=True, help='The skip indicator.')
|
||||
style.skip_indicator.xpos = 10
|
||||
style.skip_indicator.ypos = 10
|
||||
|
||||
|
||||
init -1700 python:
|
||||
##########################################################################
|
||||
# Extend
|
||||
|
||||
config.extend_interjection = "{fast}"
|
||||
|
||||
@@ -122,9 +119,26 @@ init -1700 python:
|
||||
extend.record_say = False
|
||||
|
||||
|
||||
init -1700 python:
|
||||
##########################################################################
|
||||
# Self-voicing
|
||||
|
||||
def skip_indicator():
|
||||
def sv(what, interact=True):
|
||||
"""
|
||||
Uses the narrator to speak `what` iff self-voicing is enabled.
|
||||
"""
|
||||
|
||||
if _preferences.self_voicing:
|
||||
return narrator(what, interact=interact)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Skip indicator
|
||||
|
||||
style.skip_indicator = Style(style.default, heavy=True, help='The skip indicator.')
|
||||
style.skip_indicator.xpos = 10
|
||||
style.skip_indicator.ypos = 10
|
||||
|
||||
def _skip_indicator():
|
||||
|
||||
### skip_indicator default
|
||||
# (text) The style and placement of the skip indicator.
|
||||
@@ -147,10 +161,30 @@ init -1700 python:
|
||||
|
||||
ui.add(renpy.easy.displayable(config.skip_indicator))
|
||||
|
||||
config.overlay_functions.append(skip_indicator)
|
||||
config.overlay_functions.append(_skip_indicator)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Predictions
|
||||
|
||||
# A list of labels we predict at start time.
|
||||
config.predict_start_labels = [ "start" ]
|
||||
|
||||
# Prediction of statements.
|
||||
def _predict_statements(current):
|
||||
|
||||
if main_menu:
|
||||
rv = list(config.predict_start_labels)
|
||||
rv.append(current)
|
||||
return rv
|
||||
|
||||
return [ current ]
|
||||
|
||||
config.predict_statements_callback = _predict_statements
|
||||
|
||||
|
||||
# Prediction of screens.
|
||||
def predict():
|
||||
def _predict_screens():
|
||||
|
||||
s = _game_menu_screen
|
||||
|
||||
@@ -167,10 +201,8 @@ init -1700 python:
|
||||
renpy.predict_screen(s)
|
||||
return
|
||||
|
||||
config.predict_callbacks.append(_predict_screens)
|
||||
|
||||
config.predict_callbacks.append(predict)
|
||||
|
||||
init -1700 python:
|
||||
|
||||
##########################################################################
|
||||
# Side Images
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
init -1500 python:
|
||||
|
||||
class Placeholder(renpy.Displayable):
|
||||
"""
|
||||
:doc: placeholder
|
||||
|
||||
This displayable can be used to display a placeholder character or
|
||||
background.
|
||||
"""
|
||||
|
||||
def after_setstate(self):
|
||||
self.child = None
|
||||
|
||||
def __init__(self, base=None, full=False, flip=None, **properties):
|
||||
"""
|
||||
`base`
|
||||
The type of image to display. This should be one of:
|
||||
|
||||
'bg'
|
||||
To display a background placeholder. This currently
|
||||
fills the screen with a light-gray, and displays
|
||||
the image name at the top of the screen.
|
||||
|
||||
'boy'
|
||||
Displays a male-identified placeholder with the image
|
||||
name on his chest.
|
||||
|
||||
'girl'
|
||||
Displays a female-identified placeholder with the image
|
||||
name on her chest.
|
||||
|
||||
None
|
||||
Attempts to automatically determine the type of image
|
||||
to use. If the image name begins with "bg", "cg", or
|
||||
"event", uses 'bg'.
|
||||
|
||||
Otherwise, contacts a web service to guess gender from
|
||||
the character's name, and uses that. (The 'girl' placeholder
|
||||
is used when the service can't guess.)
|
||||
|
||||
The webservice will only be contacted when config.developer
|
||||
is True.
|
||||
|
||||
`full`
|
||||
If true, a full-body sprite is used. Otherwise, a 3/4 sprite
|
||||
is used.
|
||||
|
||||
`flip`
|
||||
If true, the sprite is flipped horizontally.
|
||||
"""
|
||||
|
||||
|
||||
super(Placeholder, self).__init__(**properties)
|
||||
|
||||
self.base = base
|
||||
self.flip = flip
|
||||
self.full = full
|
||||
|
||||
# A list of name components.
|
||||
self.name = [ ]
|
||||
|
||||
# The child of this placeholder, if known.
|
||||
self.child = None
|
||||
|
||||
def guess_base(self):
|
||||
"""
|
||||
Tries to guess a base image to use based on the name of
|
||||
the image.
|
||||
"""
|
||||
|
||||
if not self.name:
|
||||
return 'girl'
|
||||
|
||||
tag = self.name[0]
|
||||
|
||||
if tag in ( "bg", "cg", "event" ):
|
||||
return "bg"
|
||||
|
||||
if not config.developer:
|
||||
return "girl"
|
||||
|
||||
if persistent._placeholder_gender is None:
|
||||
persistent._placeholder_gender = { }
|
||||
|
||||
if tag in persistent._placeholder_gender:
|
||||
return persistent._placeholder_gender[tag]
|
||||
|
||||
try:
|
||||
import urllib2
|
||||
import json
|
||||
|
||||
u = urllib2.urlopen("http://api.genderize.io/?name=" + tag.encode("utf-8"), timeout=3)
|
||||
data = json.loads(u.read())
|
||||
|
||||
if data.get("gender", "") == "male":
|
||||
rv = "boy"
|
||||
else:
|
||||
rv = "girl"
|
||||
except:
|
||||
rv = "girl"
|
||||
|
||||
persistent._placeholder_gender[tag] = rv
|
||||
|
||||
return rv
|
||||
|
||||
def get_child(self):
|
||||
"""
|
||||
Gets the child image to use.
|
||||
"""
|
||||
|
||||
if self.child:
|
||||
return self.child
|
||||
|
||||
# Determine the base.
|
||||
base = self.base
|
||||
|
||||
if base is None:
|
||||
base = self.guess_base()
|
||||
|
||||
# Bg bases.
|
||||
if base == "bg":
|
||||
rv = Fixed(
|
||||
Solid("#aaa"),
|
||||
Text(" ".join(self.name), style="_default", color="#333333", text_align=0.5, xalign=0.5, ypos=5),
|
||||
)
|
||||
|
||||
self.child = rv
|
||||
return rv
|
||||
|
||||
# Find the character image to use.
|
||||
if base == "boy":
|
||||
image = Image("_placeholder/boy.png")
|
||||
textpos = (187, 500)
|
||||
size = (380, 1800)
|
||||
else:
|
||||
image = Image("_placeholder/girl.png")
|
||||
textpos = (182, 540)
|
||||
size = (411, 1800)
|
||||
|
||||
# Get the portion of the image to show.
|
||||
if not self.full:
|
||||
size = (size[0], 1080)
|
||||
|
||||
# Scale to screen height.
|
||||
zoom = 1.0 * config.screen_height / size[1]
|
||||
crop = (0, 0) + size
|
||||
size = (int(size[0] * zoom), int(size[1] * zoom))
|
||||
textpos = (int(textpos[0] * zoom), int(textpos[1] * zoom))
|
||||
|
||||
# Flip as necessary.
|
||||
if self.flip:
|
||||
xzoom = -1
|
||||
textpos = (size[0] - textpos[0], textpos[1])
|
||||
else:
|
||||
xzoom = 1
|
||||
|
||||
text = "\n".join(self.name)
|
||||
|
||||
# Figure out the child.
|
||||
rv = Fixed(
|
||||
Transform(image, crop=crop, size=size, xzoom=xzoom),
|
||||
Text(text, pos=textpos, xanchor=0.5, yanchor=0.5, style="_default", color="#aaa", text_align=0.5),
|
||||
xysize=size,
|
||||
)
|
||||
|
||||
self.child = rv
|
||||
return rv
|
||||
|
||||
def parameterize(self, name, parameters):
|
||||
|
||||
rv = Placeholder(self.base, self.full, self.flip)
|
||||
rv.name = list(name) + list(parameters)
|
||||
|
||||
return rv
|
||||
|
||||
def visit(self):
|
||||
return [ self.get_child() ]
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
child = self.get_child()
|
||||
return renpy.render(child, width, height, st, at)
|
||||
@@ -352,3 +352,28 @@ init -1500 python:
|
||||
rv.alt = name + " [text]"
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def __show_self_voicing():
|
||||
has_screen = renpy.get_screen("_self_voicing")
|
||||
|
||||
if _preferences.self_voicing and not has_screen:
|
||||
renpy.show_screen("_self_voicing")
|
||||
elif not _preferences.self_voicing and has_screen:
|
||||
renpy.hide_screen("_self_voicing")
|
||||
|
||||
config.interact_callbacks.append(__show_self_voicing)
|
||||
|
||||
init -1500:
|
||||
|
||||
# The screen that we use to indicate that self-voicing is enabled.
|
||||
screen _self_voicing():
|
||||
zorder 1500
|
||||
|
||||
text _("Self-voicing enabled. Press 'v' to disable."):
|
||||
alt ""
|
||||
|
||||
xpos 10
|
||||
ypos 35
|
||||
color "#fff"
|
||||
outlines [ (1, "#0008", 0, 0)]
|
||||
|
||||
@@ -63,7 +63,7 @@ init -1500 python:
|
||||
|
||||
def init_values(self, sizes):
|
||||
def to_abs_(value, size):
|
||||
if type(value) == float:
|
||||
if isinstance(value, float):
|
||||
return value * size
|
||||
else:
|
||||
return value
|
||||
|
||||
@@ -137,8 +137,10 @@ label _start:
|
||||
call _gl_test
|
||||
call _load_reload_game from _call__load_reload_game_1
|
||||
|
||||
if not _restart and config.auto_load and renpy.can_load(config.auto_load):
|
||||
$ renpy.load(config.auto_load)
|
||||
python hide:
|
||||
auto_load = renpy.os.environ.get("RENPY_AUTO_LOAD", config.auto_load)
|
||||
if not _restart and auto_load and renpy.can_load(auto_load):
|
||||
renpy.load(auto_load)
|
||||
|
||||
if config.start_scene_black:
|
||||
scene black
|
||||
@@ -153,7 +155,6 @@ label _start:
|
||||
|
||||
$ _old_game_menu_screen = _game_menu_screen
|
||||
$ _game_menu_screen = None
|
||||
$ renpy.start_predict("main_menu")
|
||||
|
||||
if renpy.has_label("splashscreen") and (not _restart) and (not renpy.os.environ.get("RENPY_SKIP_SPLASHSCREEN", None)):
|
||||
call expression "splashscreen" from _call_splashscreen_1
|
||||
|
||||
@@ -203,6 +203,7 @@ init -1800:
|
||||
# Button properties
|
||||
focus_mask None
|
||||
focus_rect None
|
||||
keyboard_focus True
|
||||
|
||||
# Bar properties
|
||||
fore_bar Null()
|
||||
|
||||
+106
-6
@@ -21,7 +21,7 @@
|
||||
|
||||
# This code applies an update.
|
||||
init -1500 python in updater:
|
||||
from store import renpy, config, Action, DictEquality
|
||||
from store import renpy, config, Action, DictEquality, persistent
|
||||
import store.build as build
|
||||
|
||||
import tarfile
|
||||
@@ -47,6 +47,14 @@ init -1500 python in updater:
|
||||
|
||||
from renpy.exports import fsencode
|
||||
|
||||
# A map from update URL to the last version found at that URL.
|
||||
if persistent._update_version is None:
|
||||
persistent._update_version = { }
|
||||
|
||||
# A map from update URL to the time we last checked that URL.
|
||||
if persistent._update_last_checked is None:
|
||||
persistent._update_last_checked = { }
|
||||
|
||||
# A file containing deferred update commands, one per line. Right now,
|
||||
# there are two commands:
|
||||
# R <path>
|
||||
@@ -202,7 +210,7 @@ init -1500 python in updater:
|
||||
# The update was cancelled.
|
||||
CANCELLED = "CANCELLED"
|
||||
|
||||
def __init__(self, url, base, force=False, public_key=None, simulate=None, add=[], restart=True):
|
||||
def __init__(self, url, base=None, force=False, public_key=None, simulate=None, add=[], restart=True, check_only=False):
|
||||
"""
|
||||
Takes the same arguments as update().
|
||||
"""
|
||||
@@ -236,11 +244,15 @@ init -1500 python in updater:
|
||||
# Force the update?
|
||||
self.force = force
|
||||
|
||||
# Packages to add during the update.
|
||||
self.add = add
|
||||
|
||||
# Do we need to restart Ren'Py at the end?
|
||||
self.restart = restart
|
||||
|
||||
# Packages to add during the update.
|
||||
self.add = add
|
||||
# If true, we check for an update, and update persistent._update_version
|
||||
# as appropriate.
|
||||
self.check_only = check_only
|
||||
|
||||
# The base path of the game that we're updating, and the path to the update
|
||||
# directory underneath it.
|
||||
@@ -327,7 +339,7 @@ init -1500 python in updater:
|
||||
self.log.flush()
|
||||
|
||||
except Exception as e:
|
||||
self.message = type(e).__name__ + ": " + unicode(e)
|
||||
self.message = _type(e).__name__ + ": " + unicode(e)
|
||||
self.can_cancel = True
|
||||
self.can_proceed = False
|
||||
self.state = self.ERROR
|
||||
@@ -359,6 +371,14 @@ init -1500 python in updater:
|
||||
self.can_cancel = False
|
||||
self.can_proceed = True
|
||||
self.state = self.UPDATE_NOT_AVAILABLE
|
||||
persistent._update_version[self.url] = None
|
||||
renpy.restart_interaction()
|
||||
return
|
||||
|
||||
persistent._update_version[self.url] = pretty_version
|
||||
|
||||
if self.check_only:
|
||||
renpy.restart_interaction()
|
||||
return
|
||||
|
||||
if not self.add:
|
||||
@@ -370,6 +390,8 @@ init -1500 python in updater:
|
||||
self.state = self.UPDATE_AVAILABLE
|
||||
self.version = pretty_version
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
while True:
|
||||
if self.cancelled or self.proceeded:
|
||||
break
|
||||
@@ -384,6 +406,7 @@ init -1500 python in updater:
|
||||
|
||||
# Perform the update.
|
||||
self.new_state = dict(self.current_state)
|
||||
renpy.restart_interaction()
|
||||
|
||||
self.progress = 0.0
|
||||
self.state = self.PREPARING
|
||||
@@ -393,6 +416,7 @@ init -1500 python in updater:
|
||||
|
||||
self.progress = 0.0
|
||||
self.state = self.DOWNLOADING
|
||||
renpy.restart_interaction()
|
||||
|
||||
for i in self.modules:
|
||||
self.download(i)
|
||||
@@ -402,12 +426,14 @@ init -1500 python in updater:
|
||||
self.can_cancel = False
|
||||
self.progress = 0.0
|
||||
self.state = self.UNPACKING
|
||||
renpy.restart_interaction()
|
||||
|
||||
for i in self.modules:
|
||||
self.unpack(i)
|
||||
|
||||
self.progress = None
|
||||
self.state = self.FINISHING
|
||||
renpy.restart_interaction()
|
||||
|
||||
self.move_files()
|
||||
self.delete_obsolete()
|
||||
@@ -419,11 +445,15 @@ init -1500 python in updater:
|
||||
self.can_proceed = True
|
||||
self.can_cancel = False
|
||||
|
||||
persistent._update_version[self.url] = None
|
||||
|
||||
if self.restart:
|
||||
self.state = self.DONE
|
||||
else:
|
||||
self.state = self.DONE_NO_RESTART
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
return
|
||||
|
||||
def simulation(self):
|
||||
@@ -451,6 +481,14 @@ init -1500 python in updater:
|
||||
self.can_cancel = False
|
||||
self.can_proceed = True
|
||||
self.state = self.UPDATE_NOT_AVAILABLE
|
||||
persistent._update_version[self.url] = None
|
||||
return
|
||||
|
||||
pretty_version = build.version or build.directory_name
|
||||
persistent._update_version[self.url] = pretty_version
|
||||
|
||||
if self.check_only:
|
||||
renpy.restart_interaction()
|
||||
return
|
||||
|
||||
# Confirm with the user that the update is available.
|
||||
@@ -458,7 +496,7 @@ init -1500 python in updater:
|
||||
self.can_cancel = True
|
||||
self.can_proceed = True
|
||||
self.state = self.UPDATE_AVAILABLE
|
||||
self.version = build.version or build.directory_name
|
||||
self.version = pretty_version
|
||||
|
||||
while True:
|
||||
if self.cancelled or self.proceeded:
|
||||
@@ -473,22 +511,26 @@ init -1500 python in updater:
|
||||
|
||||
self.progress = 0.0
|
||||
self.state = self.PREPARING
|
||||
renpy.restart_interaction()
|
||||
|
||||
simulate_progress()
|
||||
|
||||
self.progress = 0.0
|
||||
self.state = self.DOWNLOADING
|
||||
renpy.restart_interaction()
|
||||
|
||||
simulate_progress()
|
||||
|
||||
self.can_cancel = False
|
||||
self.progress = 0.0
|
||||
self.state = self.UNPACKING
|
||||
renpy.restart_interaction()
|
||||
|
||||
simulate_progress()
|
||||
|
||||
self.progress = None
|
||||
self.state = self.FINISHING
|
||||
renpy.restart_interaction()
|
||||
|
||||
time.sleep(1.5)
|
||||
|
||||
@@ -497,11 +539,15 @@ init -1500 python in updater:
|
||||
self.can_proceed = True
|
||||
self.can_cancel = False
|
||||
|
||||
persistent._update_version[self.url] = None
|
||||
|
||||
if self.restart:
|
||||
self.state = self.DONE
|
||||
else:
|
||||
self.state = self.DONE_NO_RESTART
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
return
|
||||
|
||||
def proceed(self):
|
||||
@@ -1106,6 +1152,7 @@ init -1500 python in updater:
|
||||
|
||||
installed_packages_cache = None
|
||||
|
||||
|
||||
def get_installed_packages(base=None):
|
||||
"""
|
||||
:doc: updater
|
||||
@@ -1137,6 +1184,7 @@ init -1500 python in updater:
|
||||
installed_packages_cache = rv
|
||||
return rv
|
||||
|
||||
|
||||
def can_update(base=None):
|
||||
"""
|
||||
:doc: updater
|
||||
@@ -1144,6 +1192,10 @@ init -1500 python in updater:
|
||||
Returns true if it's possible that an update can succeed. Returns false
|
||||
if updating is totally impossible. (For example, if the update directory
|
||||
was deleted.)
|
||||
|
||||
|
||||
Note that this does not determine if an update is actually available.
|
||||
To do that, use :func:`updater.UpdateVersion`.
|
||||
"""
|
||||
|
||||
if rsa is None:
|
||||
@@ -1151,6 +1203,7 @@ init -1500 python in updater:
|
||||
|
||||
return not not get_installed_packages(base)
|
||||
|
||||
|
||||
def update(url, base=None, force=False, public_key=None, simulate=None, add=[], restart=True):
|
||||
"""
|
||||
:doc: updater
|
||||
@@ -1196,6 +1249,7 @@ init -1500 python in updater:
|
||||
ui.timer(.1, repeat=True, action=renpy.restart_interaction)
|
||||
renpy.call_screen("updater", u=u)
|
||||
|
||||
|
||||
@renpy.pure
|
||||
class Update(Action, DictEquality):
|
||||
"""
|
||||
@@ -1212,6 +1266,52 @@ init -1500 python in updater:
|
||||
def __call__(self):
|
||||
renpy.invoke_in_new_context(update, *self.args, **self.kwargs)
|
||||
|
||||
|
||||
# A list of URLs that we've checked for the update version.
|
||||
checked = set()
|
||||
|
||||
def UpdateVersion(url, check_interval=3600*6, simulate=None, **kwargs):
|
||||
"""
|
||||
:doc: updater
|
||||
|
||||
This function contacts the server at `url`, and determines if there is
|
||||
a newer version of software available at that url. If there is, this
|
||||
function returns the new version. Otherwise, it returns None.
|
||||
|
||||
Since contacting the server can take some time, this function launches
|
||||
a thread in the background, and immediately returns the version from
|
||||
the last time the server was contacted, or None if the server has never
|
||||
been contacted. The background thread will restart the current interaction
|
||||
once the server has been contacted, which will cause screens that call
|
||||
this function to update.
|
||||
|
||||
Each url will be contacted at most once per Ren'Py session, and not
|
||||
more than once every `check_interval` seconds. When the server is not
|
||||
contacted, cached data will be returned.
|
||||
|
||||
Additional keyword arguments (including `simulate`) are passed to the
|
||||
update mechanism as if they were given to :func:`updater.update`.
|
||||
"""
|
||||
|
||||
if not can_update() and not simulate:
|
||||
return None
|
||||
|
||||
check = True
|
||||
|
||||
if url in checked:
|
||||
check = False
|
||||
|
||||
if time.time() < persistent._update_last_checked.get(url, 0) + check_interval:
|
||||
check = False
|
||||
|
||||
if check:
|
||||
checked.add(url)
|
||||
persistent._update_last_checked[url] = time.time()
|
||||
Updater(url, check_only=True, simulate=simulate, **kwargs)
|
||||
|
||||
return persistent._update_version.get(url, None)
|
||||
|
||||
|
||||
def update_command():
|
||||
import time
|
||||
|
||||
|
||||
@@ -245,38 +245,14 @@ label _theme_test:
|
||||
return
|
||||
|
||||
|
||||
# Not used any more, but may be in save files.
|
||||
init -1050 python:
|
||||
config.missing_background = "black"
|
||||
|
||||
style _missing_frame is _frame:
|
||||
xalign 0.5
|
||||
yalign 0.0
|
||||
background "#0004"
|
||||
xpadding 5
|
||||
ypadding 5
|
||||
|
||||
style _missing_text is _text:
|
||||
color "#fff"
|
||||
xalign 0.5
|
||||
|
||||
# Not used any more, but may be in save files.
|
||||
screen _missing_images:
|
||||
zorder -1050
|
||||
$ missing = renpy.context().__missing
|
||||
|
||||
if missing:
|
||||
|
||||
frame:
|
||||
style "_missing_frame"
|
||||
|
||||
has vbox
|
||||
|
||||
text _("{b}Missing Images{/b}"):
|
||||
style "_missing_text"
|
||||
|
||||
for what in sorted(missing.values()):
|
||||
|
||||
text "[what!q]":
|
||||
style "_missing_text"
|
||||
pass
|
||||
|
||||
init 1050 python:
|
||||
|
||||
@@ -287,54 +263,38 @@ init 1050 python:
|
||||
# blank the screen.
|
||||
__missing_scene = False
|
||||
|
||||
# This returns the __missing dictionary from the current
|
||||
# context object.
|
||||
def __missing():
|
||||
try:
|
||||
return renpy.context().__missing
|
||||
except AttributeError:
|
||||
rv = dict()
|
||||
renpy.context().__missing = rv
|
||||
return rv
|
||||
|
||||
def __missing_show_callback(name, what, layer):
|
||||
global __missing_scene
|
||||
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
if __missing_scene:
|
||||
renpy.show(name, what=config.missing_background)
|
||||
__missing_scene = False
|
||||
|
||||
what = " ".join(what)
|
||||
__missing()[name[0]] = what
|
||||
return True
|
||||
__missing_scene = False
|
||||
return Placeholder("bg").parameterize((), what)
|
||||
else:
|
||||
return Placeholder().parameterize((), what)
|
||||
|
||||
def __missing_hide_callback(name, layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = False
|
||||
__missing().pop(name[0], None)
|
||||
return True
|
||||
|
||||
def __missing_scene_callback(layer):
|
||||
|
||||
global __missing_scene
|
||||
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = True
|
||||
__missing().clear()
|
||||
|
||||
return True
|
||||
|
||||
config.missing_scene = __missing_scene_callback
|
||||
config.missing_show = __missing_show_callback
|
||||
config.missing_hide = __missing_hide_callback
|
||||
|
||||
config.start_callbacks.append(Show("_missing_images"))
|
||||
|
||||
|
||||
init -1050 python:
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ style _default:
|
||||
# Button properties
|
||||
focus_mask None
|
||||
focus_rect None
|
||||
keyboard_focus True
|
||||
|
||||
# Bar properties
|
||||
fore_bar Null()
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
+10
-3
@@ -91,17 +91,17 @@ savedir = None
|
||||
|
||||
# The number of screens worth of images that are allowed to
|
||||
# live in the image cache at once.
|
||||
image_cache_size = 8
|
||||
image_cache_size = 16
|
||||
|
||||
# The number of statements we will analyze when doing predictive
|
||||
# loading. Please note that this is a total number of statements in a
|
||||
# BFS along all paths, rather than the depth along any particular
|
||||
# path. The current node is counted in this number.
|
||||
predict_statements = 16
|
||||
predict_statements = 32
|
||||
|
||||
# Causes the contents of the image cache to be printed to stdout when
|
||||
# it changes.
|
||||
debug_image_cache = False
|
||||
debug_image_cache = ("RENPY_DEBUG_IMAGE_CACHE" in os.environ)
|
||||
|
||||
# Should we allow skipping at all?
|
||||
allow_skipping = True
|
||||
@@ -509,6 +509,9 @@ raw_tracebacks = ("RENPY_RAW_TRACEBACKS" in os.environ)
|
||||
# A function to process texts which should be spoken
|
||||
tts_function = renpy.display.tts.default_tts_function
|
||||
|
||||
# Channels that stop voice playback.
|
||||
tts_voice_channels = [ "voice" ]
|
||||
|
||||
# The number of copies of each screen to keep in the screen cache.
|
||||
screen_cache_size = 4
|
||||
|
||||
@@ -531,6 +534,10 @@ emphasize_audio_time = 0.5
|
||||
# Should we transition screens, or always use their new states.
|
||||
transition_screens = True
|
||||
|
||||
# A function that given the current statement identifier, returns a list
|
||||
# of statement identifiers that should be predicted.
|
||||
predict_statements_callback = None
|
||||
|
||||
del renpy
|
||||
del os
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ Action = renpy.ui.Action
|
||||
BarValue = renpy.ui.BarValue
|
||||
|
||||
# NOTE: When exporting something from here, decide if we need to add it to
|
||||
# renpy.sl2.pyutil.pure_functions.
|
||||
# renpy.pyanalysis.pure_functions.
|
||||
|
||||
Style = renpy.style.Style # @UndefinedVariable
|
||||
|
||||
|
||||
@@ -23,37 +23,37 @@
|
||||
import renpy
|
||||
import math
|
||||
from renpy.display.render cimport Render, Matrix2D, render
|
||||
from renpy.display.core import absolute
|
||||
|
||||
|
||||
################################################################################
|
||||
# Surface copying
|
||||
################################################################################
|
||||
|
||||
from pygame cimport *
|
||||
|
||||
def nogil_copy(src, dest):
|
||||
"""
|
||||
Does a gil-less blit of src to dest, with minimal locking.
|
||||
"""
|
||||
|
||||
cdef SDL_Surface *src_surf
|
||||
cdef SDL_Surface *dst_surf
|
||||
|
||||
src_surf = PySurface_AsSurface(src)
|
||||
dest_surf = PySurface_AsSurface(dest)
|
||||
|
||||
old_alpha = src_surf.flags & SDL_SRCALPHA
|
||||
|
||||
if old_alpha:
|
||||
SDL_SetAlpha(src_surf, 0, 255)
|
||||
|
||||
with nogil:
|
||||
SDL_BlitSurface(src_surf, NULL, dest_surf, NULL)
|
||||
|
||||
if old_alpha:
|
||||
SDL_SetAlpha(src_surf, SDL_SRCALPHA, 255)
|
||||
|
||||
dest.blit(src, (0, 0))
|
||||
|
||||
# cdef SDL_Surface *src_surf
|
||||
# cdef SDL_Surface *dst_surf
|
||||
#
|
||||
# src_surf = PySurface_AsSurface(src)
|
||||
# dest_surf = PySurface_AsSurface(dest)
|
||||
#
|
||||
# old_alpha = src_surf.flags & SDL_SRCALPHA
|
||||
#
|
||||
# if old_alpha:
|
||||
# SDL_SetSurfaceAlpha(src_surf, 0, 255)
|
||||
#
|
||||
# with nogil:
|
||||
# SDL_BlitSurface(src_surf, NULL, dest_surf, NULL)
|
||||
#
|
||||
# if old_alpha:
|
||||
# SDL_SetAlpha(src_surf, SDL_SRCALPHA, 255)
|
||||
|
||||
################################################################################
|
||||
# Transform render function
|
||||
@@ -141,6 +141,22 @@ def transform_render(self, widtho, heighto, st, at):
|
||||
|
||||
if crop is not None:
|
||||
|
||||
if state.crop_relative:
|
||||
x, y, w, h = crop
|
||||
|
||||
def relative(n, base, limit):
|
||||
if isinstance(n, (int, absolute)):
|
||||
return n
|
||||
else:
|
||||
return min(int(n * base), limit)
|
||||
|
||||
x = relative(x, width, width)
|
||||
y = relative(y, height, height)
|
||||
w = relative(w, width, width - x)
|
||||
h = relative(h, height, height - y)
|
||||
|
||||
crop = (x, y, w, h)
|
||||
|
||||
negative_xo, negative_yo, width, height = crop
|
||||
|
||||
if state.rotate:
|
||||
|
||||
@@ -394,14 +394,9 @@ class RollForward(renpy.display.layout.Null):
|
||||
super(RollForward, self).__init__(**properties)
|
||||
self.value = value
|
||||
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if map_event(ev, "rollforward"):
|
||||
renpy.game.interface.suppress_transition = True
|
||||
renpy.game.after_rollback = True
|
||||
renpy.game.log.rolled_forward = True
|
||||
return self.value
|
||||
return renpy.exports.roll_forward_core(self.value)
|
||||
|
||||
|
||||
class PauseBehavior(renpy.display.layout.Null):
|
||||
@@ -617,7 +612,6 @@ class Button(renpy.display.layout.Window):
|
||||
mask = rv
|
||||
elif mask is not None:
|
||||
try:
|
||||
mask = renpy.easy.displayable(mask)
|
||||
mask = renpy.display.render.render(mask, rv.width, rv.height, st, at)
|
||||
except:
|
||||
if callable(mask):
|
||||
@@ -1658,6 +1652,9 @@ class Timer(renpy.display.layout.Null):
|
||||
|
||||
class MouseArea(renpy.display.core.Displayable):
|
||||
|
||||
# The offset between st and at.
|
||||
at_st_offset = 0
|
||||
|
||||
def __init__(self, hovered=None, unhovered=None, replaces=None, **properties):
|
||||
super(MouseArea, self).__init__(**properties)
|
||||
|
||||
@@ -1674,16 +1671,20 @@ class MouseArea(renpy.display.core.Displayable):
|
||||
self.width = 0
|
||||
self.height = 0
|
||||
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
self.at_st_offset = at - st
|
||||
|
||||
return Render(width, height)
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
if self.style.focus_mask is not None:
|
||||
crend = renpy.display.render.render(self.style.focus_mask, self.width, self.height, st, self.at_st_offset + st)
|
||||
is_hovered = crend.is_pixel_opaque(x, y)
|
||||
elif 0 <= x < self.width and 0 <= y < self.height:
|
||||
is_hovered = True
|
||||
else:
|
||||
is_hovered = False
|
||||
@@ -1698,3 +1699,31 @@ class MouseArea(renpy.display.core.Displayable):
|
||||
|
||||
run_unhovered(self.hovered)
|
||||
run(self.unhovered)
|
||||
|
||||
class OnEvent(renpy.display.core.Displayable):
|
||||
"""
|
||||
This is a displayable that runs an action in response to a transform
|
||||
event. It's used to implement the screen language on statement.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, event, action=[ ]):
|
||||
"""
|
||||
`event`
|
||||
A string giving the event name.
|
||||
|
||||
`action`
|
||||
An action or list of actions that are run when the event occurs.
|
||||
"""
|
||||
|
||||
super(OnEvent, self).__init__()
|
||||
|
||||
self.event_name = event
|
||||
self.action = action
|
||||
|
||||
def set_transform_event(self, event):
|
||||
if event == self.event_name:
|
||||
run(self.action)
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
return renpy.display.render.Render(0, 0)
|
||||
|
||||
@@ -184,6 +184,9 @@ class Displayable(renpy.object.Object):
|
||||
# to.) If None, it is itself.
|
||||
_main = None
|
||||
|
||||
# A list of the children that make up this composite displayable.
|
||||
_composite_parts = [ ]
|
||||
|
||||
# The location the displayable was created at, if known.
|
||||
_location = None
|
||||
|
||||
@@ -415,6 +418,7 @@ class Displayable(renpy.object.Object):
|
||||
return
|
||||
|
||||
self.transform_event = event
|
||||
|
||||
if self.transform_event_responder:
|
||||
renpy.display.render.redraw(self, 0)
|
||||
|
||||
|
||||
+48
-13
@@ -25,7 +25,7 @@
|
||||
import renpy.display
|
||||
from renpy.display.render import render, Render, redraw
|
||||
from renpy.display.core import absolute
|
||||
from renpy.display.behavior import map_event, run
|
||||
from renpy.display.behavior import map_event, run, run_unhovered
|
||||
|
||||
import pygame
|
||||
|
||||
@@ -153,6 +153,9 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
|
||||
focusable = True
|
||||
|
||||
drag_group = None
|
||||
old_position = None
|
||||
|
||||
def __init__(self,
|
||||
d=None,
|
||||
drag_name=None,
|
||||
@@ -169,7 +172,7 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
replaces=None,
|
||||
**properties):
|
||||
|
||||
super(Drag, self).__init__(self, **properties)
|
||||
super(Drag, self).__init__(**properties)
|
||||
|
||||
self.drag_name = drag_name
|
||||
self.draggable = draggable
|
||||
@@ -200,6 +203,8 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
self.w = None
|
||||
self.h = None
|
||||
|
||||
self.old_position = None
|
||||
|
||||
# The width and height of our parent.
|
||||
self.parent_width = None
|
||||
self.parent_height = None
|
||||
@@ -242,6 +247,13 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
self.target_x = replaces.target_x
|
||||
self.target_y = replaces.target_y
|
||||
self.target_at = replaces.target_at
|
||||
self.grab_x = replaces.grab_x
|
||||
self.grab_y = replaces.grab_y
|
||||
self.last_x = replaces.last_x
|
||||
self.last_y = replaces.last_y
|
||||
self.old_position = replaces.old_position
|
||||
self.drag_moved = replaces.drag_moved
|
||||
self.last_drop = replaces.last_drop
|
||||
|
||||
if d is not None:
|
||||
self.add(d)
|
||||
@@ -267,7 +279,7 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
self.drag_group.positions[self.drag_name] = (x, y)
|
||||
self.drag_group.positions[self.drag_name] = (x, y, self.old_position)
|
||||
|
||||
redraw(self, 0)
|
||||
|
||||
@@ -325,6 +337,7 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
super(Drag, self).unfocus(default)
|
||||
|
||||
if not default:
|
||||
run_unhovered(self.hovered)
|
||||
run(self.unhovered)
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
@@ -345,17 +358,39 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
self.w = cw
|
||||
self.h = ch
|
||||
|
||||
position = (self.style.xpos, self.style.ypos, self.style.xanchor, self.style.yanchor, self.style.xoffset, self.style.yoffset)
|
||||
|
||||
# If we don't have a position, then look for it in a drag group.
|
||||
if (self.x is None) and (self.drag_group is not None) and (self.drag_name is not None):
|
||||
if self.drag_name in self.drag_group.positions:
|
||||
self.x, self.y = self.drag_group.positions[self.drag_name]
|
||||
dgp = self.drag_group.positions[self.drag_name]
|
||||
if len(dgp) == 3:
|
||||
self.x, self.y, self.old_position = dgp
|
||||
else:
|
||||
self.x, self.y = dgp
|
||||
self.old_position = position
|
||||
|
||||
if self.old_position != position:
|
||||
place = True
|
||||
elif self.x is None:
|
||||
place = True
|
||||
else:
|
||||
place = False
|
||||
|
||||
# If we don't have a position, run the placement code and use
|
||||
# that to compute our placement.
|
||||
if self.x is None:
|
||||
self.x, self.y = self.place(None, 0, 0, width, height, rv)
|
||||
self.x = int(self.x)
|
||||
self.y = int(self.y)
|
||||
if place:
|
||||
# This is required to get get_placement to work properly.
|
||||
self.x = None
|
||||
|
||||
place_x, place_y = self.place(None, 0, 0, width, height, rv)
|
||||
|
||||
self.x = int(place_x)
|
||||
self.y = int(place_y)
|
||||
|
||||
self.target_x = None
|
||||
|
||||
self.old_position = position
|
||||
|
||||
if self.target_x is None:
|
||||
self.target_x = self.x
|
||||
@@ -405,8 +440,8 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
# return self.child.event(ev, x, y, st)
|
||||
|
||||
# Mouse, in parent-relative coordinates.
|
||||
par_x = self.last_x + x
|
||||
par_y = self.last_y + y
|
||||
par_x = int(self.last_x + x)
|
||||
par_y = int(self.last_y + y)
|
||||
|
||||
grabbed = (renpy.display.focus.get_grab() is self)
|
||||
|
||||
@@ -472,15 +507,15 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
if self.drag_moved:
|
||||
for i, xo, yo in joined_offsets:
|
||||
|
||||
new_x = par_x - self.grab_x + xo
|
||||
new_y = par_y - self.grab_y + yo
|
||||
new_x = int(par_x - self.grab_x + xo)
|
||||
new_y = int(par_y - self.grab_y + yo)
|
||||
new_x = max(new_x, 0)
|
||||
new_x = min(new_x, int(i.parent_width - i.w))
|
||||
new_y = max(new_y, 0)
|
||||
new_y = min(new_y, int(i.parent_height - i.h))
|
||||
|
||||
if i.drag_group is not None and i.drag_name is not None:
|
||||
i.drag_group.positions[i.drag_name] = (new_x, new_y)
|
||||
i.drag_group.positions[i.drag_name] = (new_x, new_y, self.old_position)
|
||||
|
||||
i.x = new_x
|
||||
i.y = new_y
|
||||
|
||||
+24
-11
@@ -128,15 +128,15 @@ def focus_coordinates():
|
||||
return None, None, None, None
|
||||
|
||||
|
||||
# This is called before each interaction. It's purpose is to choose
|
||||
# the widget that is focused, and to mark it as focused and all of
|
||||
# the other widgets as unfocused.
|
||||
|
||||
# The new grab widget. (The one that replaced the old grab widget at the start
|
||||
# of the interaction.)
|
||||
new_grab = None
|
||||
# A map from id(displayable) to the displayable that replaces it.
|
||||
replaced_by = { }
|
||||
|
||||
def before_interact(roots):
|
||||
"""
|
||||
Called before each interaction to choose the focused and grabbed
|
||||
displayables.
|
||||
"""
|
||||
|
||||
|
||||
global new_grab
|
||||
global grab
|
||||
@@ -160,13 +160,17 @@ def before_interact(roots):
|
||||
|
||||
f.full_focus_name = n, serial
|
||||
|
||||
if (f is grab) and (new_grab is None):
|
||||
new_grab = f
|
||||
replaced_by[id(f)] = f
|
||||
|
||||
|
||||
# We assume id(None) is not in replaced_by.
|
||||
replaced_by.pop(None, None)
|
||||
|
||||
# If there's something with the same full name as the current widget,
|
||||
# it becomes the new current widget.
|
||||
|
||||
current = get_focused()
|
||||
current = replaced_by.get(id(current), current)
|
||||
|
||||
if current is not None:
|
||||
current_name = current.full_focus_name
|
||||
@@ -199,8 +203,11 @@ def before_interact(roots):
|
||||
if current:
|
||||
current.focus(default=True)
|
||||
|
||||
grab = new_grab
|
||||
new_grab = None
|
||||
# Update the grab.
|
||||
grab = replaced_by.get(id(grab), None)
|
||||
|
||||
# Clear replaced_by.
|
||||
replaced_by.clear()
|
||||
|
||||
# This changes the focus to be the widget contained inside the new
|
||||
# focus object.
|
||||
@@ -394,6 +401,9 @@ def focus_nearest(from_x0, from_y0, from_x1, from_y1,
|
||||
if f is from_focus:
|
||||
continue
|
||||
|
||||
if not f.widget.style.keyboard_focus:
|
||||
continue
|
||||
|
||||
if f.x is None:
|
||||
placeless = f
|
||||
continue
|
||||
@@ -442,6 +452,9 @@ def focus_ordered(delta):
|
||||
if f.arg is not None:
|
||||
continue
|
||||
|
||||
if not f.widget.style.keyboard_focus:
|
||||
continue
|
||||
|
||||
if f.widget is current:
|
||||
current_index = index
|
||||
|
||||
|
||||
+47
-26
@@ -356,16 +356,14 @@ class Grid(Container):
|
||||
else:
|
||||
raise Exception("Grid overfull.")
|
||||
|
||||
# If necessary, transpose the grid (kinda hacky, but it works here.)
|
||||
if self.transpose:
|
||||
self.transpose = False
|
||||
|
||||
old_children = self.children[:]
|
||||
|
||||
for y in range(0, rows):
|
||||
for x in range(0, cols):
|
||||
self.children[x + y * cols] = old_children[ y + x * rows ]
|
||||
children = [ ]
|
||||
for y in range(rows):
|
||||
for x in range(cols):
|
||||
children.append(self.children[y + x * rows])
|
||||
|
||||
else:
|
||||
children = self.children
|
||||
|
||||
# Now, start the actual rendering.
|
||||
|
||||
@@ -377,7 +375,7 @@ class Grid(Container):
|
||||
if self.style.yfill:
|
||||
renheight = (height - (rows - 1) * padding) / rows
|
||||
|
||||
renders = [ render(i, renwidth, renheight, st, at) for i in self.children ]
|
||||
renders = [ render(i, renwidth, renheight, st, at) for i in children ]
|
||||
sizes = [ i.get_size() for i in renders ]
|
||||
|
||||
cwidth = 0
|
||||
@@ -398,19 +396,27 @@ class Grid(Container):
|
||||
|
||||
rv = renpy.display.render.Render(width, height)
|
||||
|
||||
self.offsets = [ ]
|
||||
offsets = [ ]
|
||||
|
||||
for y in range(0, rows):
|
||||
for x in range(0, cols):
|
||||
|
||||
child = self.children[ x + y * cols ]
|
||||
child = children[ x + y * cols ]
|
||||
surf = renders[x + y * cols]
|
||||
|
||||
xpos = x * (cwidth + padding)
|
||||
ypos = y * (cheight + padding)
|
||||
|
||||
offset = child.place(rv, xpos, ypos, cwidth, cheight, surf)
|
||||
self.offsets.append(offset)
|
||||
offsets.append(offset)
|
||||
|
||||
if self.transpose:
|
||||
self.offsets = [ ]
|
||||
for x in range(cols):
|
||||
for y in range(rows):
|
||||
self.offsets.append(offsets[y * cols + x])
|
||||
else:
|
||||
self.offsets = offsets
|
||||
|
||||
return rv
|
||||
|
||||
@@ -874,9 +880,8 @@ class SizeGroup(renpy.object.Object):
|
||||
maxwidth = 0
|
||||
|
||||
for i in self.members:
|
||||
rend = renpy.display.render.render(i, width, height, st, at)
|
||||
rend = i.render(width, height, st, at)
|
||||
maxwidth = max(rend.width, maxwidth)
|
||||
renpy.display.render.invalidate(i)
|
||||
|
||||
self._width = maxwidth
|
||||
self.computing_width = False
|
||||
@@ -1093,12 +1098,16 @@ class DynamicDisplayable(renpy.display.core.Displayable):
|
||||
return renpy.display.render.render(self.child, w, h, st, at)
|
||||
|
||||
def predict_one(self):
|
||||
if not self.predict_function:
|
||||
return
|
||||
try:
|
||||
if self.predict_function:
|
||||
child = self.predict_function(*self.args, **self.kwargs)
|
||||
else:
|
||||
child, _ = self.function(0, 0, *self.args, **self.kwargs)
|
||||
|
||||
for i in self.predict_function(*self.args, **self.kwargs):
|
||||
if i is not None:
|
||||
renpy.display.predict.displayable(i)
|
||||
if child is not None:
|
||||
renpy.display.predict.displayable(child)
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_placement(self):
|
||||
if not self.child:
|
||||
@@ -1450,9 +1459,7 @@ class Viewport(Container):
|
||||
self.xadjustment.change(self.xadjustment.value + duration * self.edge_xspeed)
|
||||
self.yadjustment.change(self.yadjustment.value + duration * self.edge_yspeed)
|
||||
|
||||
self.check_edge_redraw()
|
||||
|
||||
self.edge_last_st = st
|
||||
self.check_edge_redraw(st)
|
||||
|
||||
cxo = -int(self.xadjustment.value)
|
||||
cyo = -int(self.yadjustment.value)
|
||||
@@ -1464,7 +1471,7 @@ class Viewport(Container):
|
||||
|
||||
return rv
|
||||
|
||||
def check_edge_redraw(self):
|
||||
def check_edge_redraw(self, st):
|
||||
redraw = False
|
||||
|
||||
if (self.edge_xspeed > 0) and (self.xadjustment.value < self.xadjustment.range):
|
||||
@@ -1479,6 +1486,9 @@ class Viewport(Container):
|
||||
|
||||
if redraw:
|
||||
renpy.display.render.redraw(self, 0)
|
||||
self.edge_last_st = st
|
||||
else:
|
||||
self.edge_last_st = None
|
||||
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
@@ -1559,9 +1569,7 @@ class Viewport(Container):
|
||||
self.edge_yspeed = self.edge_speed * self.edge_function(yspeed)
|
||||
|
||||
if xspeed or yspeed:
|
||||
self.check_edge_redraw()
|
||||
if self.edge_last_st is None:
|
||||
self.edge_last_st = st
|
||||
self.check_edge_redraw(st)
|
||||
else:
|
||||
self.edge_last_st = None
|
||||
|
||||
@@ -1603,13 +1611,26 @@ class Side(Container):
|
||||
if isinstance(positions, basestring):
|
||||
positions = positions.split()
|
||||
|
||||
seen = set()
|
||||
|
||||
for i in positions:
|
||||
if not i in Side.possible_positions:
|
||||
raise Exception("Side used with impossible position '%s'." % (i,))
|
||||
|
||||
if i in seen:
|
||||
raise Exception("Side used with duplicate position '%s'." % (i,))
|
||||
|
||||
seen.add(i)
|
||||
|
||||
self.positions = tuple(positions)
|
||||
self.sized = False
|
||||
|
||||
def add(self, d):
|
||||
if len(self.children) >= len(self.positions):
|
||||
raise Exception("Side has been given too many arguments.")
|
||||
|
||||
super(Side, self).add(d)
|
||||
|
||||
def _clear(self):
|
||||
super(Side, self)._clear()
|
||||
self.sized = False
|
||||
|
||||
+102
-84
@@ -89,16 +89,15 @@ class TransformState(renpy.object.Object):
|
||||
nearest = False
|
||||
xoffset = None
|
||||
yoffset = None
|
||||
default_xpos = None
|
||||
default_ypos = None
|
||||
default_xanchor = None
|
||||
default_yanchor = None
|
||||
default_xoffset = None
|
||||
default_yoffset = None
|
||||
inherited_xpos = None
|
||||
inherited_ypos = None
|
||||
inherited_xanchor = None
|
||||
inherited_yanchor = None
|
||||
transform_anchor = False
|
||||
additive = 0.0
|
||||
debug = None
|
||||
events = True
|
||||
crop_relative = False
|
||||
|
||||
def __init__(self): # W0231
|
||||
self.alpha = 1
|
||||
@@ -126,6 +125,7 @@ class TransformState(renpy.object.Object):
|
||||
self.subpixel = False
|
||||
|
||||
self.crop = None
|
||||
self.crop_relative = False
|
||||
self.corner1 = None
|
||||
self.corner2 = None
|
||||
self.size = None
|
||||
@@ -141,12 +141,16 @@ class TransformState(renpy.object.Object):
|
||||
# - renpy.atl.PROPERTIES
|
||||
# - Proxies in Transform
|
||||
|
||||
# Default values for various properties, taken from our
|
||||
# parent.
|
||||
self.default_xpos = None
|
||||
self.default_ypos = None
|
||||
self.default_xanchor = None
|
||||
self.default_yanchor = None
|
||||
|
||||
# An xpos (etc) inherited from our child overrides an xpos inherited
|
||||
# from an old transform, but not an xpos set in the current transform.
|
||||
#
|
||||
# inherited_xpos stores the inherited_xpos, which is overridden by the
|
||||
# xpos, if not None.
|
||||
self.inherited_xpos = None
|
||||
self.inherited_ypos = None
|
||||
self.inherited_xanchor = None
|
||||
self.inherited_yanchor = None
|
||||
|
||||
def take_state(self, ts):
|
||||
|
||||
@@ -165,9 +169,8 @@ class TransformState(renpy.object.Object):
|
||||
self.xanchoraround = ts.xanchoraround
|
||||
self.yanchoraround = ts.yanchoraround
|
||||
|
||||
self.subpixel = ts.subpixel
|
||||
|
||||
self.crop = ts.crop
|
||||
self.crop_relative = ts.crop_relative
|
||||
self.corner1 = ts.corner1
|
||||
self.corner2 = ts.corner2
|
||||
self.size = ts.size
|
||||
@@ -177,13 +180,17 @@ class TransformState(renpy.object.Object):
|
||||
|
||||
# Take the computed position properties, not the
|
||||
# raw ones.
|
||||
(self.default_xpos,
|
||||
self.default_ypos,
|
||||
self.default_xanchor,
|
||||
self.default_yanchor,
|
||||
self.xoffset,
|
||||
self.yoffset,
|
||||
self.subpixel) = ts.get_placement()
|
||||
(self.inherited_xpos,
|
||||
self.inherited_ypos,
|
||||
self.inherited_xanchor,
|
||||
self.inherited_yanchor,
|
||||
_,
|
||||
_,
|
||||
_) = ts.get_placement()
|
||||
|
||||
self.xoffset = ts.xoffset
|
||||
self.yoffset = ts.yoffset
|
||||
self.subpixel = ts.subpixel
|
||||
|
||||
# Returns a dict, with p -> (old, new) where p is a property that
|
||||
# has changed between this object and the new object.
|
||||
@@ -195,14 +202,14 @@ class TransformState(renpy.object.Object):
|
||||
if new != old:
|
||||
rv[prop] = (old, new)
|
||||
|
||||
def diff4(prop, new, default_new, old, default_old):
|
||||
def diff4(prop, new, inherited_new, old, inherited_old):
|
||||
if new is None:
|
||||
new_value = default_new
|
||||
new_value = inherited_new
|
||||
else:
|
||||
new_value = new
|
||||
|
||||
if old is None:
|
||||
old_value = default_old
|
||||
old_value = inherited_old
|
||||
else:
|
||||
old_value = old
|
||||
|
||||
@@ -227,17 +234,18 @@ class TransformState(renpy.object.Object):
|
||||
diff2("subpixel", newts.subpixel, self.subpixel)
|
||||
|
||||
diff2("crop", newts.crop, self.crop)
|
||||
diff2("crop_relative", newts.crop_relative, self.crop_relative)
|
||||
diff2("corner1", newts.corner1, self.corner1)
|
||||
diff2("corner2", newts.corner2, self.corner2)
|
||||
diff2("size", newts.size, self.size)
|
||||
|
||||
diff4("xpos", newts.xpos, newts.default_xpos, self.xpos, self.default_xpos)
|
||||
diff4("xpos", newts.xpos, newts.inherited_xpos, self.xpos, self.inherited_xpos)
|
||||
|
||||
diff4("xanchor", newts.xanchor, newts.default_xanchor, self.xanchor, self.default_xanchor)
|
||||
diff4("xanchor", newts.xanchor, newts.inherited_xanchor, self.xanchor, self.inherited_xanchor)
|
||||
diff2("xoffset", newts.xoffset, self.xoffset)
|
||||
|
||||
diff4("ypos", newts.ypos, newts.default_ypos, self.ypos, self.default_ypos)
|
||||
diff4("yanchor", newts.yanchor, newts.default_yanchor, self.yanchor, self.default_yanchor)
|
||||
diff4("ypos", newts.ypos, newts.inherited_ypos, self.ypos, self.inherited_ypos)
|
||||
diff4("yanchor", newts.yanchor, newts.inherited_yanchor, self.yanchor, self.inherited_yanchor)
|
||||
diff2("yoffset", newts.yoffset, self.yoffset)
|
||||
|
||||
diff2("debug", newts.debug, self.debug)
|
||||
@@ -248,10 +256,10 @@ class TransformState(renpy.object.Object):
|
||||
def get_placement(self, cxoffset=0, cyoffset=0):
|
||||
|
||||
return (
|
||||
first_not_none(self.xpos, self.default_xpos),
|
||||
first_not_none(self.ypos, self.default_ypos),
|
||||
first_not_none(self.xanchor, self.default_xanchor),
|
||||
first_not_none(self.yanchor, self.default_yanchor),
|
||||
first_not_none(self.xpos, self.inherited_xpos),
|
||||
first_not_none(self.ypos, self.inherited_ypos),
|
||||
first_not_none(self.xanchor, self.inherited_xanchor),
|
||||
first_not_none(self.yanchor, self.inherited_yanchor),
|
||||
self.xoffset + cxoffset,
|
||||
self.yoffset + cyoffset,
|
||||
self.subpixel,
|
||||
@@ -291,20 +299,20 @@ class TransformState(renpy.object.Object):
|
||||
alignaround = property(get_around, set_alignaround)
|
||||
|
||||
def get_angle(self):
|
||||
xpos = first_not_none(self.xpos, self.default_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.default_ypos, 0)
|
||||
xpos = first_not_none(self.xpos, self.inherited_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.inherited_ypos, 0)
|
||||
angle, _radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
|
||||
return angle
|
||||
|
||||
def get_radius(self):
|
||||
xpos = first_not_none(self.xpos, self.default_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.default_ypos, 0)
|
||||
xpos = first_not_none(self.xpos, self.inherited_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.inherited_ypos, 0)
|
||||
_angle, radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
|
||||
return radius
|
||||
|
||||
def set_angle(self, value):
|
||||
xpos = first_not_none(self.xpos, self.default_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.default_ypos, 0)
|
||||
xpos = first_not_none(self.xpos, self.inherited_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.inherited_ypos, 0)
|
||||
_angle, radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
|
||||
angle = value
|
||||
self.xpos, self.ypos = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
|
||||
@@ -313,8 +321,8 @@ class TransformState(renpy.object.Object):
|
||||
self.xanchor, self.yanchor = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
|
||||
|
||||
def set_radius(self, value):
|
||||
xpos = first_not_none(self.xpos, self.default_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.default_ypos, 0)
|
||||
xpos = first_not_none(self.xpos, self.inherited_xpos, 0)
|
||||
ypos = first_not_none(self.ypos, self.inherited_ypos, 0)
|
||||
angle, _radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
|
||||
radius = value
|
||||
self.xpos, self.ypos = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
|
||||
@@ -431,6 +439,7 @@ class Transform(Container):
|
||||
align = Proxy("align")
|
||||
|
||||
crop = Proxy("crop")
|
||||
crop_relative = Proxy("crop_relative")
|
||||
corner1 = Proxy("corner1")
|
||||
corner2 = Proxy("corner2")
|
||||
size = Proxy("size")
|
||||
@@ -527,54 +536,43 @@ class Transform(Container):
|
||||
|
||||
self.state = TransformState()
|
||||
|
||||
self.arguments = None
|
||||
|
||||
if kwargs:
|
||||
|
||||
if function is None:
|
||||
# A map from prefix -> (prop -> value)
|
||||
self.arguments = { }
|
||||
|
||||
# We are complex if we have arguments with non-empty prefixes.
|
||||
has_prefixes = False
|
||||
# Fill self.arguments with a
|
||||
for k, v in kwargs.iteritems():
|
||||
|
||||
# A map from prefix -> (prop -> value)
|
||||
self.arguments = { }
|
||||
prefix = ""
|
||||
prop = k
|
||||
|
||||
# Fill self.arguments with a
|
||||
for k, v in kwargs.iteritems():
|
||||
while True:
|
||||
|
||||
prefix = ""
|
||||
prop = k
|
||||
if prop in renpy.atl.PROPERTIES and (not prefix or prefix in Transform.DEFAULT_ARGUMENTS):
|
||||
|
||||
while True:
|
||||
if prefix not in self.arguments:
|
||||
self.arguments[prefix] = { }
|
||||
|
||||
if prop in renpy.atl.PROPERTIES and (not prefix or prefix in Transform.DEFAULT_ARGUMENTS):
|
||||
self.arguments[prefix][prop] = v
|
||||
break
|
||||
|
||||
if prefix not in self.arguments:
|
||||
self.arguments[prefix] = { }
|
||||
new_prefix, _, prop = prop.partition("_")
|
||||
|
||||
self.arguments[prefix][prop] = v
|
||||
if not prop:
|
||||
raise Exception("Unknown transform property: %r" % k)
|
||||
|
||||
if prefix:
|
||||
has_prefixes = True
|
||||
if prefix:
|
||||
prefix = prefix + "_" + new_prefix
|
||||
else:
|
||||
prefix = new_prefix
|
||||
|
||||
break
|
||||
if "" in self.arguments:
|
||||
for k, v in self.arguments[""].iteritems():
|
||||
setattr(self.state, k, v)
|
||||
|
||||
new_prefix, _, prop = prop.partition("_")
|
||||
|
||||
if not prop:
|
||||
raise Exception("Unknown transform property: %r" % k)
|
||||
|
||||
if prefix:
|
||||
prefix = prefix + "_" + new_prefix
|
||||
else:
|
||||
prefix = new_prefix
|
||||
|
||||
if not has_prefixes:
|
||||
self.arguments = None
|
||||
|
||||
# Apply keyword arguments to self.state.
|
||||
for prop, value in kwargs.iteritems():
|
||||
setattr(self.state, prop, value)
|
||||
else:
|
||||
self.arguments = None
|
||||
|
||||
# This is the matrix transforming our coordinates into child coordinates.
|
||||
self.forward = None
|
||||
@@ -646,6 +644,9 @@ class Transform(Container):
|
||||
Takes the transformation state from object t into this object.
|
||||
"""
|
||||
|
||||
if not isinstance(t, Transform):
|
||||
return
|
||||
|
||||
self.state.take_state(t.state)
|
||||
|
||||
# The arguments will be applied when the default function is
|
||||
@@ -658,6 +659,9 @@ class Transform(Container):
|
||||
overridden by renpy.atl.TransformBase.
|
||||
"""
|
||||
|
||||
if not isinstance(t, Transform):
|
||||
return
|
||||
|
||||
self.hide_request = t.hide_request
|
||||
self.replaced_request = t.replaced_request
|
||||
|
||||
@@ -699,6 +703,16 @@ class Transform(Container):
|
||||
if not self.child:
|
||||
return None
|
||||
|
||||
# Prevent time from ticking backwards, as can happen if we replace a
|
||||
# transform but keep its state.
|
||||
if st + self.st_offset <= self.st:
|
||||
self.st_offset = self.st - st
|
||||
if at + self.at_offset <= self.at:
|
||||
self.at_offset = self.at - at
|
||||
|
||||
self.st = st = st + self.st_offset
|
||||
self.at = at = at + self.at_offset
|
||||
|
||||
if not (self.hide_request or self.replaced_request):
|
||||
d = self.copy()
|
||||
else:
|
||||
@@ -748,15 +762,19 @@ class Transform(Container):
|
||||
This updates the state to that at self.st, self.at.
|
||||
"""
|
||||
|
||||
self.hide_response = True
|
||||
self.replaced_response = True
|
||||
|
||||
# If we have to, call the function that updates this transform.
|
||||
if self.arguments is not None:
|
||||
self.default_function(self, self.st, self.at)
|
||||
|
||||
if self.function is not None:
|
||||
fr = self.function(self, self.st, self.at)
|
||||
else:
|
||||
fr = self.default_function(self, self.st, self.at)
|
||||
|
||||
# Order a redraw, if necessary.
|
||||
if fr is not None:
|
||||
renpy.display.render.redraw(self, fr)
|
||||
# Order a redraw, if necessary.
|
||||
if fr is not None:
|
||||
renpy.display.render.redraw(self, fr)
|
||||
|
||||
state = self.state
|
||||
|
||||
@@ -769,13 +787,13 @@ class Transform(Container):
|
||||
pos = child.get_placement()
|
||||
|
||||
if pos[0] is not None:
|
||||
state.default_xpos = pos[0]
|
||||
state.inherited_xpos = pos[0]
|
||||
if pos[2] is not None:
|
||||
state.default_xanchor = pos[2]
|
||||
state.inherited_xanchor = pos[2]
|
||||
if pos[1] is not None:
|
||||
state.default_ypos = pos[1]
|
||||
state.inherited_ypos = pos[1]
|
||||
if pos[3] is not None:
|
||||
state.default_yanchor = pos[3]
|
||||
state.inherited_yanchor = pos[3]
|
||||
|
||||
state.subpixel |= pos[6]
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
|
||||
import sys
|
||||
import pygame
|
||||
import threading
|
||||
import renpy.display
|
||||
|
||||
|
||||
# Sample surfaces, with and without alpha.
|
||||
sample_alpha = None
|
||||
sample_noalpha = None
|
||||
@@ -125,8 +127,26 @@ copy_surface_unscaled = copy_surface
|
||||
|
||||
# Wrapper around image loading.
|
||||
|
||||
# Formats we can load reentrantly.
|
||||
safe_formats = { "png", "jpg", "jpeg" }
|
||||
|
||||
# Lock used for loading unsafe formats.
|
||||
image_load_lock = threading.RLock()
|
||||
|
||||
def load_image(f, filename):
|
||||
surf = pygame.image.load(f, renpy.exports.fsencode(filename))
|
||||
global count
|
||||
|
||||
_basename, _dot, ext = filename.rpartition('.')
|
||||
|
||||
if ext.lower() in safe_formats:
|
||||
surf = pygame.image.load(f, renpy.exports.fsencode(filename))
|
||||
else:
|
||||
|
||||
# Non-whitelisted formats may not be able to load in a reentrant
|
||||
# fashion.
|
||||
with image_load_lock:
|
||||
surf = pygame.image.load(f, renpy.exports.fsencode(filename))
|
||||
|
||||
rv = copy_surface_unscaled(surf)
|
||||
return rv
|
||||
|
||||
|
||||
+15
-18
@@ -91,6 +91,9 @@ def check_at_shutdown():
|
||||
raise Exception("%d Renders are alive at shutdown. This is probably a memory leak bug in Ren'Py." % count)
|
||||
|
||||
|
||||
# The number of things being rendered at the moment.
|
||||
cdef int rendering
|
||||
rendering = 0
|
||||
|
||||
cpdef render(d, object widtho, object heighto, double st, double at):
|
||||
"""
|
||||
@@ -113,6 +116,8 @@ cpdef render(d, object widtho, object heighto, double st, double at):
|
||||
once they have been retrieved.
|
||||
"""
|
||||
|
||||
global rendering
|
||||
|
||||
cdef float width, height
|
||||
cdef float orig_width, orig_height
|
||||
cdef tuple orig_wh, wh
|
||||
@@ -164,7 +169,11 @@ cpdef render(d, object widtho, object heighto, double st, double at):
|
||||
else:
|
||||
wh = orig_wh
|
||||
|
||||
rv = d.render(widtho, heighto, st, at)
|
||||
try:
|
||||
rendering += 1
|
||||
rv = d.render(widtho, heighto, st, at)
|
||||
finally:
|
||||
rendering -= 1
|
||||
|
||||
rv.render_of.append(d)
|
||||
|
||||
@@ -179,27 +188,14 @@ cpdef render(d, object widtho, object heighto, double st, double at):
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# This is true if something has been invalidated, and a redraw needs
|
||||
# to occur. It's automatically cleared to False at the end of each
|
||||
# redraw.
|
||||
invalidated = False
|
||||
|
||||
def invalidate(d):
|
||||
"""
|
||||
Removes d from the render cache. If we're not in a redraw, triggers
|
||||
a redraw to start.
|
||||
"""
|
||||
|
||||
global invalidated
|
||||
|
||||
id_d = id(d)
|
||||
|
||||
if id_d in render_cache:
|
||||
for v in render_cache[id_d].values():
|
||||
v.kill_cache()
|
||||
|
||||
invalidated = True
|
||||
if not rendering:
|
||||
redraw(d, 0)
|
||||
|
||||
|
||||
def process_redraws():
|
||||
@@ -213,7 +209,7 @@ def process_redraws():
|
||||
redraw_queue.sort()
|
||||
|
||||
now = renpy.display.core.get_time()
|
||||
rv = invalidated
|
||||
rv = False
|
||||
|
||||
new_redraw_queue = [ ]
|
||||
seen = set()
|
||||
@@ -770,6 +766,7 @@ cdef class Render:
|
||||
rv.operation = self.operation
|
||||
rv.operation_alpha = self.operation_alpha
|
||||
rv.operation_complete = self.operation_complete
|
||||
rv.nearest = self.nearest
|
||||
|
||||
return rv
|
||||
|
||||
@@ -826,7 +823,7 @@ cdef class Render:
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Retained for compatibility.
|
||||
Retained for compatibility, but does not need to be called.
|
||||
"""
|
||||
|
||||
def add_focus(self, d, arg=None, x=0, y=0, w=None, h=None, mx=None, my=None, mask=None):
|
||||
|
||||
+50
-24
@@ -33,12 +33,14 @@ profile_log = renpy.log.open("profile_screen", developer=True, append=False, flu
|
||||
profile = { }
|
||||
|
||||
class ScreenProfile(renpy.object.Object):
|
||||
"""
|
||||
:doc: profile_screen
|
||||
:name: renpy.profile_screen
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, predict=False, show=False, update=False, request=False, time=False, debug=False, const=False):
|
||||
"""
|
||||
:doc: profile_screen
|
||||
:name: renpy.profile_screen
|
||||
|
||||
Requests screen profiling for the screen named `name`, which
|
||||
must be a string.
|
||||
|
||||
@@ -263,9 +265,10 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
class is responsible for managing the display of a screen.
|
||||
"""
|
||||
|
||||
nosave = [ 'screen', 'child', 'children', 'transforms', 'widgets', 'old_widgets', 'hidden_widgets', 'old_transforms', 'cache', 'profile', 'phase' ]
|
||||
nosave = [ 'screen', 'child', 'children', 'transforms', 'widgets', 'old_widgets', 'hidden_widgets', 'old_transforms', 'cache', 'profile', 'phase', 'use_cache' ]
|
||||
|
||||
restarting = False
|
||||
hiding = False
|
||||
|
||||
def after_setstate(self):
|
||||
self.screen = get_screen_variant(self.screen_name[0])
|
||||
@@ -278,6 +281,7 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
self.hidden_widgets = { }
|
||||
self.cache = { }
|
||||
self.phase = UPDATE
|
||||
self.use_cache = { }
|
||||
|
||||
self.profile = profile.get(self.screen_name, None)
|
||||
|
||||
@@ -331,6 +335,14 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
else:
|
||||
self.transforms = { }
|
||||
|
||||
# A map from a (screen name, id) pair to cache. This is for use
|
||||
# statements with the id parameter.
|
||||
if old_screen is not None:
|
||||
self.use_cache = old_screen.use_cache
|
||||
else:
|
||||
self.use_cache = { }
|
||||
|
||||
|
||||
# What widgets and transforms were the last time this screen was
|
||||
# updated. Used to communicate with the ui module, and only
|
||||
# valid during an update - not used at other times.
|
||||
@@ -349,8 +361,9 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
# A dict-set of widgets (by id) that have been hidden from us.
|
||||
self.hidden_widgets = { }
|
||||
|
||||
# Are we restarting?
|
||||
# Are we restarting or hiding?
|
||||
self.restarting = False
|
||||
self.hiding = False
|
||||
|
||||
# Modal and zorder.
|
||||
self.modal = renpy.python.py_eval(self.screen.modal, locals=self.scope)
|
||||
@@ -406,6 +419,9 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
hid = self
|
||||
else:
|
||||
|
||||
updated_screens.discard(self)
|
||||
self.update()
|
||||
|
||||
if self.screen is None:
|
||||
return None
|
||||
|
||||
@@ -417,8 +433,8 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
|
||||
hid = self.copy()
|
||||
|
||||
hid.current_transform_event = kind
|
||||
hid.update()
|
||||
for i in self.child.children:
|
||||
i.set_transform_event(kind)
|
||||
|
||||
hid.phase = HIDE
|
||||
|
||||
@@ -511,10 +527,6 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
if self.profile.debug:
|
||||
debug = True
|
||||
|
||||
# Update _current_screen
|
||||
global _current_screen
|
||||
old_screen = _current_screen
|
||||
_current_screen = self
|
||||
|
||||
# Cycle widgets and transforms.
|
||||
self.old_widgets = self.widgets
|
||||
@@ -522,24 +534,31 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
self.widgets = { }
|
||||
self.transforms = { }
|
||||
|
||||
# Render the child.
|
||||
# Update _current_screen and renpy.ui.screen.
|
||||
global _current_screen
|
||||
old_screen = _current_screen
|
||||
_current_screen = self
|
||||
|
||||
old_ui_screen = renpy.ui.screen
|
||||
renpy.ui.screen = self
|
||||
|
||||
renpy.ui.detached()
|
||||
self.child = renpy.ui.fixed(focus="_screen_" + "_".join(self.screen_name))
|
||||
self.children = [ self.child ]
|
||||
# Evaluate the screen.
|
||||
try:
|
||||
renpy.ui.detached()
|
||||
self.child = renpy.ui.fixed(focus="_screen_" + "_".join(self.screen_name))
|
||||
self.children = [ self.child ]
|
||||
|
||||
self.scope["_scope"] = self.scope
|
||||
self.scope["_name"] = 0
|
||||
self.scope["_debug"] = debug
|
||||
self.scope["_scope"] = self.scope
|
||||
self.scope["_name"] = 0
|
||||
self.scope["_debug"] = debug
|
||||
|
||||
self.screen.function(**self.scope)
|
||||
self.screen.function(**self.scope)
|
||||
|
||||
renpy.ui.close()
|
||||
renpy.ui.close()
|
||||
|
||||
renpy.ui.screen = old_ui_screen
|
||||
_current_screen = old_screen
|
||||
finally:
|
||||
renpy.ui.screen = old_ui_screen
|
||||
_current_screen = old_screen
|
||||
|
||||
# Finish up.
|
||||
self.old_widgets = None
|
||||
@@ -794,8 +813,15 @@ def show_screen(_screen_name, *_args, **kwargs):
|
||||
scope.update(kwargs)
|
||||
|
||||
d = ScreenDisplayable(screen, _tag, _layer, _widget_properties, scope)
|
||||
d.cache = cache_get(screen, _args, kwargs)
|
||||
d.phase = SHOW
|
||||
|
||||
old_d = get_screen(name, _layer)
|
||||
|
||||
if old_d and old_d.cache:
|
||||
d.cache = old_d.cache
|
||||
d.phase = UPDATE
|
||||
else:
|
||||
d.cache = cache_get(screen, _args, kwargs)
|
||||
d.phase = SHOW
|
||||
|
||||
renpy.exports.show(name, tag=_tag, what=d, layer=_layer, zorder=d.zorder, transient=_transient, munge_name=False)
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@ class SWDraw(object):
|
||||
if self.mouse_location:
|
||||
updates.append(self.hide_mouse())
|
||||
|
||||
if tex and pos and renpy.game.interface.focused: # @UndefinedVariable
|
||||
if tex and pos and renpy.game.interface.mouse_focused: # @UndefinedVariable
|
||||
updates.append(self.show_mouse(pos, info))
|
||||
|
||||
return updates
|
||||
|
||||
+11
-2
@@ -21,7 +21,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import renpy
|
||||
import renpy.audio
|
||||
import subprocess
|
||||
|
||||
class TTSRoot(Exception):
|
||||
@@ -76,6 +76,7 @@ def default_tts_function(s):
|
||||
process = subprocess.Popen([ "say", renpy.exports.fsencode(s) ])
|
||||
elif renpy.windows:
|
||||
say_vbs = os.path.join(os.path.dirname(sys.executable), "say.vbs")
|
||||
s = s.replace('"', "")
|
||||
process = subprocess.Popen([ "wscript", renpy.exports.fsencode(say_vbs), renpy.exports.fsencode(s) ])
|
||||
|
||||
|
||||
@@ -86,7 +87,10 @@ def tts(s):
|
||||
|
||||
global queue
|
||||
|
||||
renpy.config.tts_function(s)
|
||||
try:
|
||||
renpy.config.tts_function(s)
|
||||
except:
|
||||
pass
|
||||
|
||||
queue = [ ]
|
||||
|
||||
@@ -136,6 +140,11 @@ def displayable(d):
|
||||
old_self_voicing = self_voicing
|
||||
prefix = renpy.translation.translate_string("Self-voicing enabled. ")
|
||||
|
||||
|
||||
for i in renpy.config.tts_voice_channels:
|
||||
if not prefix and renpy.audio.music.get_playing(i):
|
||||
return
|
||||
|
||||
if d is None:
|
||||
d = root
|
||||
|
||||
|
||||
+79
-12
@@ -388,10 +388,11 @@ class Context(renpy.object.Object):
|
||||
if node is None:
|
||||
|
||||
if renpy.config.developer:
|
||||
raise Exception("Could not find return label %r." % self.return_stack[-1])
|
||||
raise Exception("Could not find return label {!r}.".format(self.return_stack[-1]))
|
||||
|
||||
self.return_stack.pop()
|
||||
self.call_location_stack.pop()
|
||||
self.pop_dynamic()
|
||||
|
||||
continue
|
||||
|
||||
@@ -422,6 +423,39 @@ class Context(renpy.object.Object):
|
||||
|
||||
return rv
|
||||
|
||||
def predict_call(self, label, return_site):
|
||||
"""
|
||||
This is called by the prediction code to indicate that a call to
|
||||
`label` will occur.
|
||||
|
||||
`return_site`
|
||||
The name of the return site to push on the predicted return
|
||||
stack.
|
||||
|
||||
Returns the node corresponding to `label`
|
||||
"""
|
||||
|
||||
self.predict_return_stack = list(self.predict_return_stack)
|
||||
self.predict_return_stack.append(return_site)
|
||||
|
||||
return renpy.game.script.lookup(label)
|
||||
|
||||
|
||||
def predict_return(self):
|
||||
"""
|
||||
This predicts that a return will occur.
|
||||
|
||||
It returns the node we predict will be returned to.
|
||||
"""
|
||||
|
||||
if not self.predict_return_stack:
|
||||
return None
|
||||
|
||||
self.predict_return_stack = list(self.predict_return_stack)
|
||||
label = self.predict_return_stack.pop()
|
||||
|
||||
return renpy.game.script.lookup(label)
|
||||
|
||||
def predict(self):
|
||||
"""
|
||||
Performs image prediction, calling the given callback with each
|
||||
@@ -432,31 +466,48 @@ class Context(renpy.object.Object):
|
||||
if not self.current:
|
||||
return
|
||||
|
||||
if renpy.config.predict_statements_callback is None:
|
||||
return
|
||||
|
||||
old_images = self.images
|
||||
|
||||
nodes = [ (renpy.game.script.lookup(self.current), self.images) ]
|
||||
node_set = set()
|
||||
# A worklist of (node, images, return_stack) tuples.
|
||||
nodes = [ ]
|
||||
|
||||
# The set of nodes we've seen. (We only consider each node once.)
|
||||
seen = set()
|
||||
|
||||
# Find the roots.
|
||||
for label in renpy.config.predict_statements_callback(self.current):
|
||||
node = renpy.game.script.lookup(label)
|
||||
|
||||
if node in seen:
|
||||
continue
|
||||
|
||||
nodes.append((node, self.images, self.return_stack))
|
||||
seen.add(node)
|
||||
|
||||
# Predict statements.
|
||||
for i in range(0, renpy.config.predict_statements):
|
||||
|
||||
if i >= len(nodes):
|
||||
break
|
||||
|
||||
node, images = nodes[i]
|
||||
node, images, return_stack = nodes[i]
|
||||
|
||||
self.images = renpy.display.image.ShownImageInfo(images)
|
||||
|
||||
# Ignore exceptions in prediction, so long as
|
||||
# prediction is not needed.
|
||||
self.predict_return_stack = return_stack
|
||||
|
||||
try:
|
||||
|
||||
for n in node.predict():
|
||||
if n is None:
|
||||
continue
|
||||
|
||||
if n not in node_set:
|
||||
nodes.append((n, self.images))
|
||||
node_set.add(n)
|
||||
if n not in seen:
|
||||
nodes.append((n, self.images, self.predict_return_stack))
|
||||
seen.add(n)
|
||||
|
||||
except:
|
||||
|
||||
if renpy.config.debug_image_cache:
|
||||
@@ -466,9 +517,8 @@ class Context(renpy.object.Object):
|
||||
traceback.print_exc()
|
||||
print "While predicting images."
|
||||
|
||||
# We accept that sometimes prediction won't work.
|
||||
|
||||
self.images = old_images
|
||||
self.predict_return_stack = None
|
||||
|
||||
yield True
|
||||
|
||||
@@ -509,6 +559,23 @@ class Context(renpy.object.Object):
|
||||
|
||||
renpy.exports.rollback(force, checkpoints)
|
||||
|
||||
def get_return_stack(self):
|
||||
return list(self.return_stack)
|
||||
|
||||
def set_return_stack(self, return_stack):
|
||||
self.return_stack = list(return_stack)
|
||||
|
||||
while len(self.call_location_stack) > len(self.return_stack):
|
||||
self.call_location_stack.pop()
|
||||
|
||||
d = self.dynamic_stack.pop()
|
||||
d.update(self.dynamic_stack[-1])
|
||||
self.dynamic_stack[-1] = d
|
||||
|
||||
while len(self.call_location_stack) < len(self.return_stack):
|
||||
self.call_location_stack.append("unknown location")
|
||||
self.dynamic_stack.append({})
|
||||
|
||||
|
||||
def run_context(top):
|
||||
"""
|
||||
|
||||
+114
-6
@@ -30,7 +30,7 @@ _file = file
|
||||
import renpy.display
|
||||
import renpy.audio
|
||||
|
||||
from renpy.sl2.pyutil import const, pure, not_const
|
||||
from renpy.pyanalysis import const, pure, not_const
|
||||
|
||||
def renpy_pure(fn):
|
||||
"""
|
||||
@@ -55,7 +55,7 @@ from renpy.display.behavior import map_event, queue_event, clear_keymap_cache
|
||||
|
||||
from renpy.display.minigame import Minigame
|
||||
from renpy.display.screen import define_screen, show_screen, hide_screen, use_screen, current_screen
|
||||
from renpy.display.screen import has_screen, get_screen, get_widget, ScreenProfile as profile_screen
|
||||
from renpy.display.screen import has_screen, get_screen, get_widget, ScreenProfile as profile_screen
|
||||
from renpy.display.focus import focus_coordinates
|
||||
from renpy.display.predict import screen as predict_screen
|
||||
from renpy.display.image import image_exists
|
||||
@@ -84,6 +84,8 @@ import renpy.audio.music as music
|
||||
from renpy.statements import register as register_statement
|
||||
from renpy.text.extras import check_text_tags
|
||||
|
||||
from renpy.memory import profile_memory, diff_memory, profile_rollback
|
||||
|
||||
renpy_pure("ParameterizedText")
|
||||
renpy_pure("Keymap")
|
||||
renpy_pure("has_screen")
|
||||
@@ -96,6 +98,7 @@ renpy_pure("check_text_tags")
|
||||
|
||||
import time
|
||||
import sys
|
||||
import threading
|
||||
|
||||
def public_api():
|
||||
"""
|
||||
@@ -135,6 +138,7 @@ def public_api():
|
||||
map_event, queue_event, clear_keymap_cache
|
||||
const, pure, not_const
|
||||
image_exists
|
||||
profile_memory, diff_memory
|
||||
|
||||
del public_api
|
||||
|
||||
@@ -153,6 +157,26 @@ def roll_forward_info():
|
||||
return renpy.game.log.forward_info()
|
||||
|
||||
|
||||
def roll_forward_core(value=None):
|
||||
"""
|
||||
:undocumented:
|
||||
|
||||
To cause a roll_forward to occur, return the value of this function
|
||||
from an event handler.
|
||||
"""
|
||||
|
||||
if value is None:
|
||||
value = roll_forward_info()
|
||||
if value is None:
|
||||
return
|
||||
|
||||
renpy.game.interface.suppress_transition = True
|
||||
renpy.game.after_rollback = True
|
||||
renpy.game.log.rolled_forward = True
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def in_rollback():
|
||||
"""
|
||||
:doc: rollback
|
||||
@@ -461,7 +485,11 @@ def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behin
|
||||
base = img = renpy.display.image.ImageReference(what, style='image_placement')
|
||||
|
||||
if not base.find_target() and renpy.config.missing_show:
|
||||
if renpy.config.missing_show(name, what, layer):
|
||||
result = renpy.config.missing_show(name, what, layer)
|
||||
|
||||
if isinstance(result, renpy.display.core.Displayable):
|
||||
base = img = result
|
||||
elif result:
|
||||
return
|
||||
|
||||
for i in at_list:
|
||||
@@ -476,7 +504,6 @@ def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behin
|
||||
if tag and munge_name:
|
||||
name = (tag,) + name[1:]
|
||||
|
||||
|
||||
if renpy.config.missing_hide:
|
||||
renpy.config.missing_hide(name, layer)
|
||||
|
||||
@@ -1271,8 +1298,11 @@ def has_label(name):
|
||||
"""
|
||||
:doc: label
|
||||
|
||||
Returns true if name is a valid label in the program, or false
|
||||
otherwise.
|
||||
Returns true if `name` is a valid label the program, or false otherwise.
|
||||
|
||||
`name`
|
||||
Should be a string to check for the existence of a label. It can
|
||||
also be an opaque tuple giving the name of a non-label statement.
|
||||
"""
|
||||
|
||||
return renpy.game.script.has_label(name)
|
||||
@@ -2014,6 +2044,8 @@ def load_string(s, filename="<string>"):
|
||||
|
||||
renpy.config.locked = old_locked
|
||||
|
||||
renpy.game.script.analyze()
|
||||
|
||||
return stmts[0].name
|
||||
|
||||
finally:
|
||||
@@ -2708,3 +2740,79 @@ def substitute(s, scope=None, translate=True):
|
||||
"""
|
||||
|
||||
return renpy.substitutions.substitute(s, scope=scope, translate=translate)[0]
|
||||
|
||||
|
||||
def munge(name, filename=None):
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Munges `name`, which must begin with __.
|
||||
|
||||
`filename`
|
||||
The filename the name is munged into. If None, the name is munged
|
||||
into the filename containing the call to this function.
|
||||
"""
|
||||
|
||||
if filename is None:
|
||||
filename = sys._getframe(1).f_code.co_filename
|
||||
|
||||
if not name.startswith("__"):
|
||||
return name
|
||||
|
||||
if name.endswith("__"):
|
||||
return name
|
||||
|
||||
return renpy.parser.munge_filename(filename) + name[2:]
|
||||
|
||||
|
||||
def get_return_stack():
|
||||
"""
|
||||
:doc: label
|
||||
|
||||
Returns a list giving the current return stack. The return stack is a
|
||||
list of statement names.
|
||||
|
||||
The statement names will be strings (for labels), or opaque tuples (for
|
||||
non-label statements).
|
||||
"""
|
||||
|
||||
return renpy.game.context().get_return_stack()
|
||||
|
||||
def set_return_stack(stack):
|
||||
"""
|
||||
:doc: label
|
||||
|
||||
Sets the current return stack. The return stack is a list of statement
|
||||
names.
|
||||
|
||||
Statement names may be strings (for labels) or opaque tuples (for
|
||||
non-label statements).
|
||||
"""
|
||||
|
||||
renpy.game.context().set_return_stack(stack)
|
||||
|
||||
def invoke_in_thread(fn, *args, **kwargs):
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Invokes the function `fn` in a background thread, passing it the
|
||||
provided arguments and keyword arguments. Restarts the interaction
|
||||
once the thread returns.
|
||||
|
||||
This function creates a daemon thread, which will be automatically
|
||||
stopped when Ren'Py is shutting down.
|
||||
"""
|
||||
|
||||
def run():
|
||||
try:
|
||||
fn(*args, **kwargs)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
restart_interaction()
|
||||
|
||||
t = threading.Thread(target=run)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
|
||||
+5
-1
@@ -24,9 +24,12 @@
|
||||
DEF ANGLE = False
|
||||
|
||||
from libc.stdlib cimport malloc, free
|
||||
from pygame cimport *
|
||||
from sdl2 cimport *
|
||||
from gl cimport *
|
||||
|
||||
from pygame_sdl2 cimport *
|
||||
import_pygame_sdl2__surface()
|
||||
|
||||
import renpy
|
||||
import pygame
|
||||
import os
|
||||
@@ -40,6 +43,7 @@ cimport gltexture
|
||||
import gltexture
|
||||
import glblacklist
|
||||
|
||||
|
||||
cdef extern from "glcompat.h":
|
||||
GLenum glewInit()
|
||||
GLubyte *glewGetErrorString(GLenum)
|
||||
|
||||
+10
-2
@@ -25,7 +25,10 @@ DEF ANGLE = False
|
||||
|
||||
from gl cimport *
|
||||
from gldraw cimport *
|
||||
from pygame cimport *
|
||||
|
||||
from sdl2 cimport *
|
||||
from pygame_sdl2 cimport *
|
||||
import_pygame_sdl2__surface()
|
||||
|
||||
from cpython.string cimport PyString_FromStringAndSize
|
||||
from libc.stdlib cimport calloc, free
|
||||
@@ -485,6 +488,9 @@ class Texture(TextureCore):
|
||||
the __del__ method is called.
|
||||
"""
|
||||
|
||||
def __sizeof__(self):
|
||||
return TextureCore.__sizeof__(self) + self.width * self.height * 4
|
||||
|
||||
def __getstate__(self):
|
||||
if renpy.config.developer:
|
||||
raise Exception("Can't pickle a texture.")
|
||||
@@ -1109,7 +1115,9 @@ def premultiply(
|
||||
cdef unsigned char *out = rv
|
||||
|
||||
# The pixels in the source image.
|
||||
cdef unsigned char *pixels, *pixels_end
|
||||
cdef unsigned char *pixels
|
||||
cdef unsigned char *pixels_end
|
||||
|
||||
cdef SDL_Surface *surf
|
||||
|
||||
# Pointer to the current pixel.
|
||||
|
||||
@@ -224,6 +224,13 @@ class SubFile(object):
|
||||
|
||||
self.f.seek(self.base)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, _type, value, tb):
|
||||
self.close()
|
||||
return False
|
||||
|
||||
def read(self, length=None):
|
||||
|
||||
maxlength = self.length - self.offset
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user