Compare commits
490 Commits
6.16
...
6.16.2.490
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b18174c8c | |||
| e50f3147a9 | |||
| 145b33bd3d | |||
| edc5b84082 | |||
| d99c52614c | |||
| 39e626cca3 | |||
| cf848e8d2f | |||
| 0a6f6ae8d3 | |||
| fde580d67d | |||
| dde4c3fee3 | |||
| 461d1a2ef5 | |||
| 28ccb37b58 | |||
| e36908d9e5 | |||
| 63c94e7987 | |||
| 41767642f4 | |||
| e33987183a | |||
| 32c4029b4b | |||
| fec8125ae3 | |||
| c368a70d0b | |||
| 70a3a3c454 | |||
| 17d4933ff6 | |||
| 774cb588d1 | |||
| 1e68f0e583 | |||
| e911f5a2d0 | |||
| abd473a384 | |||
| 43143e69eb | |||
| 43f6c19b1e | |||
| 2e97d84c5b | |||
| 6132dde743 | |||
| 613f7c0511 | |||
| 572c829179 | |||
| 533b969d5c | |||
| 177b0c0bde | |||
| dde25cfcc7 | |||
| 85e86fe406 | |||
| abaf4056dd | |||
| 32a0e92b69 | |||
| 7d4a1d7532 | |||
| 9031bf8100 | |||
| 8c4b21ad62 | |||
| 8e21344356 | |||
| b3620191d8 | |||
| 8ecdef81c9 | |||
| 43db399352 | |||
| 798dd075ba | |||
| 6794e5fa36 | |||
| 799716565c | |||
| de15d2045f | |||
| 219767251c | |||
| 5272af0b06 | |||
| 2325691fcb | |||
| 2f072f4a26 | |||
| 09d682cd23 | |||
| b38551eef8 | |||
| 79cf7df614 | |||
| e2eecee1d8 | |||
| 2d51144c43 | |||
| d4565981b1 | |||
| e0ffeeea2a | |||
| a8e83dc58c | |||
| ea6666185a | |||
| efe70fad93 | |||
| f4fec843e1 | |||
| fadbe0e226 | |||
| 69068c8720 | |||
| f7960006cc | |||
| fb214d9ab8 | |||
| d5d68632e7 | |||
| b5ec036687 | |||
| 3e1a5c18a9 | |||
| b480580399 | |||
| 2822624e85 | |||
| 205019a769 | |||
| 3d935e164d | |||
| 915fc5d6d8 | |||
| 3b60108c7a | |||
| c624331af5 | |||
| 1e096ec479 | |||
| d9ba99962c | |||
| 6e3cd02fdc | |||
| 98520d6d74 | |||
| 5085b1300b | |||
| 88275fa716 | |||
| ce752343ca | |||
| f74fb6ab29 | |||
| 7b185e022a | |||
| f9523a63f3 | |||
| 524d9a77a2 | |||
| 7362261469 | |||
| f95ff022d4 | |||
| 25661cf69e | |||
| c2cb614750 | |||
| e326c8d66e | |||
| 030edbd5d8 | |||
| 4bab0874b7 | |||
| 26b5b3a315 | |||
| bc94ee0cfa | |||
| a7aba0642b | |||
| 956b9aff4a | |||
| 25bea3444f | |||
| 71ea4caeb9 | |||
| 9d354bfcf9 | |||
| b548b851ce | |||
| 6d2faf0d02 | |||
| 154c9f9d4a | |||
| 579701cd30 | |||
| aacbd640e0 | |||
| 01e8296661 | |||
| 32f2fc8126 | |||
| 076e342f65 | |||
| b186a703e2 | |||
| c9bfd1e377 | |||
| 3365a073cb | |||
| 33e615bbf2 | |||
| a1adafa600 | |||
| 153d435571 | |||
| 6a8ad2e80c | |||
| 1395aba079 | |||
| 54e89492f3 | |||
| a69bb2edfa | |||
| b4b5a5fa59 | |||
| 389f3de5f4 | |||
| d457b345d7 | |||
| ace21dca93 | |||
| 6d72e96bc2 | |||
| f4f6cd1215 | |||
| 7de6e764a5 | |||
| 4c9a56de23 | |||
| e54a18e4ad | |||
| 4183e60fc7 | |||
| b25d19509c | |||
| d6c1444432 | |||
| edd1222e0e | |||
| c0106e8bee | |||
| 99be725ede | |||
| b0d04c3eac | |||
| b463732c42 | |||
| 5827121db5 | |||
| 7994a28363 | |||
| f6a9cb92b2 | |||
| 446a6a640f | |||
| 570a85e472 | |||
| f1f6c84758 | |||
| 3acf232631 | |||
| 0a2a2b35fe | |||
| 0eedc523bb | |||
| 5f59f4e126 | |||
| 9d6f1e5110 | |||
| fc653f265c | |||
| 0f32739675 | |||
| a333bcdc44 | |||
| 3c3be23f1f | |||
| 6b91fb9847 | |||
| 2219e4aebf | |||
| 97b9c02aa8 | |||
| 864c959b4d | |||
| 1a873b2d6a | |||
| e3d20823ae | |||
| 069b679e7d | |||
| 82b28baf87 | |||
| ffc150e569 | |||
| 7bb1b85b66 | |||
| 827f597e07 | |||
| b3f5e0c964 | |||
| 3dec76ecf4 | |||
| 897caf7abc | |||
| 0cac58e4a0 | |||
| cce422709b | |||
| b4d68fdb85 | |||
| 1acf4e1243 | |||
| bb53094f66 | |||
| 3d840f5c6d | |||
| db332a1f0f | |||
| 443a9001f5 | |||
| b7f9ad1808 | |||
| 5aa7658cdf | |||
| 5dd2fae7a9 | |||
| 3a5e571aea | |||
| 5ee03ed977 | |||
| 6710463318 | |||
| 893d36d4a3 | |||
| 8f8b7e1fd9 | |||
| e46c78fb36 | |||
| 5fd25efe0b | |||
| 4d2f567bc4 | |||
| 0aa5016758 | |||
| aac6291147 | |||
| 3cd4c18d6a | |||
| fe4bad7c11 | |||
| 251dbb2dee | |||
| 2ed6b14dc2 | |||
| a5162ac666 | |||
| 2a0adb3dbf | |||
| 7edfe2cca8 | |||
| 757ecb37b4 | |||
| 0ebcd4a7f3 | |||
| ef1e6b0676 | |||
| db94d03b64 | |||
| 87b994b67a | |||
| e5064f0794 | |||
| 6751172cfe | |||
| 6c0d7802d9 | |||
| ab7fd52fbd | |||
| c6cb66dc61 | |||
| 4b5ff75412 | |||
| 6dd5724be1 | |||
| 32f3bbb67d | |||
| 51cca16196 | |||
| 1fa87f753e | |||
| 48cc2ae4cf | |||
| e463c886cc | |||
| 2efb7058f8 | |||
| 1c582ab21a | |||
| 4f30e7ac85 | |||
| 0e223e4c7a | |||
| b431d32825 | |||
| 8f41a8be99 | |||
| e9b260aae9 | |||
| 2505af9985 | |||
| 18fff449f3 | |||
| cc437eb47c | |||
| 14cd7e71b4 | |||
| 03499adffc | |||
| c738e39268 | |||
| 922af0d651 | |||
| bfe91ab358 | |||
| 0cfe13e214 | |||
| 1246258f73 | |||
| 9655ef6a0d | |||
| 3fde29fecd | |||
| 04d5f374ef | |||
| acf0207f12 | |||
| 2ebc6fb26e | |||
| 1c1c70e951 | |||
| 3ff3054f5d | |||
| eee003c184 | |||
| 661a884566 | |||
| e35860c235 | |||
| abfbebe996 | |||
| 075555c294 | |||
| 30eb973810 | |||
| e60d332de6 | |||
| 835fe5db03 | |||
| 9705ff7837 | |||
| 56aea76e25 | |||
| f90ce46577 | |||
| 5355f87e1d | |||
| fd3d21229b | |||
| 1c819fec4d | |||
| 1256909852 | |||
| cf933f2b37 | |||
| f3031a3cab | |||
| ddf5e82bd5 | |||
| 95184394a4 | |||
| 8fbea7d329 | |||
| 7fd9de354f | |||
| 70f5d97aef | |||
| 1e8813e668 | |||
| b07403855c | |||
| 3ca12ea1d6 | |||
| 5ce0347e54 | |||
| ec2104d656 | |||
| e686b1228a | |||
| 2667268f0d | |||
| d3e5341c2d | |||
| 878aae6686 | |||
| 2df74bb052 | |||
| 66f73ab014 | |||
| 8b7ccada49 | |||
| 27845de14b | |||
| d59b550e04 | |||
| 4f26fd98a0 | |||
| e3fe09a1ae | |||
| 657b072ffa | |||
| def9865849 | |||
| 98cff70eaf | |||
| 0c4eb467fe | |||
| 3e6ed73769 | |||
| 6c29701b0d | |||
| 273dbf780e | |||
| 35831b0ba7 | |||
| 275f56a384 | |||
| dbb6551d20 | |||
| 6d74eecc5c | |||
| eae4fd3f1b | |||
| 687b3ad1cd | |||
| def04ec41c | |||
| cdbc67f3d5 | |||
| 2fd4f04bd8 | |||
| 2edbd375fd | |||
| d685c3963a | |||
| 4218e2d950 | |||
| f96a6eee04 | |||
| 12650ae9f7 | |||
| 9dee75e243 | |||
| e9a2579a64 | |||
| 7ca20972af | |||
| 3b6c187ad1 | |||
| c4e50aa700 | |||
| 4736b75cc7 | |||
| 775a007a41 | |||
| ae64c83d01 | |||
| 723622b7f5 | |||
| 7903ee1235 | |||
| da6629c210 | |||
| a994adfed7 | |||
| 66fc4eb85e | |||
| 04d4a113ac | |||
| fd6417bc3c | |||
| 74eee18415 | |||
| d5d27062d7 | |||
| 4983e581ba | |||
| ab37f35cf8 | |||
| 4a4fbb9b3f | |||
| 9b2617e48c | |||
| 80c2d4cee2 | |||
| 6255511d02 | |||
| e61ccaa6c8 | |||
| a2f31d5798 | |||
| 29f22d1e79 | |||
| fe78160055 | |||
| ba5d433dd1 | |||
| 3516bfc3c5 | |||
| 17fa9b6a14 | |||
| d0a8ab1976 | |||
| 051ca25fe7 | |||
| 3e097905e3 | |||
| d516731d24 | |||
| 2ddd430484 | |||
| 099c8a53d3 | |||
| dcbf0d05e5 | |||
| dd70a48e3f | |||
| fe954a9e33 | |||
| 5f5791a8e3 | |||
| 1c90ce4dea | |||
| 8bbd3a0000 | |||
| 72e430ef49 | |||
| 1c017a7589 | |||
| b9836c3eaa | |||
| 479f45f46f | |||
| e3204944f6 | |||
| debcd2043b | |||
| b57ceed621 | |||
| e6e0e80527 | |||
| 3c0b350a4f | |||
| b9a065d48a | |||
| c00e5abf80 | |||
| 2b3e06bf6d | |||
| 293b165aef | |||
| 3dbbb3129c | |||
| 7b5378fcf1 | |||
| 0e9d90e761 | |||
| d6acab6bd4 | |||
| b6096f6e95 | |||
| 84f2da4a27 | |||
| 3f6dfcb08e | |||
| f68e38b011 | |||
| 7bb92310b5 | |||
| ebab397625 | |||
| 776c0c2eb0 | |||
| c4bf9c07ca | |||
| 8d8703bec6 | |||
| cdfb2a162e | |||
| 842116e037 | |||
| 12403dab26 | |||
| 0dcb0e9fad | |||
| 450740318c | |||
| 455940abda | |||
| 38e2d1aaa9 | |||
| 8b640426a2 | |||
| 19a8c5512e | |||
| 9c50bce587 | |||
| 3f06c505ce | |||
| 04e5b93f91 | |||
| 052ed5c8e3 | |||
| 881a1a684f | |||
| 5bb41aa035 | |||
| 62c69c8357 | |||
| 93c4da6216 | |||
| 40cedc59cb | |||
| 3e44420023 | |||
| 16aacb8fef | |||
| 96a6d8cf3f | |||
| 4e2d68bb4a | |||
| b3c96949d9 | |||
| ac421dd971 | |||
| 97d7cf4f91 | |||
| cdfe0a5e9a | |||
| 170286d6ce | |||
| 5efa00294c | |||
| 1b47b4b420 | |||
| 2868b5c12e | |||
| 4cd7fbf7be | |||
| 1ed8555b4e | |||
| a7655a6809 | |||
| cd64333364 | |||
| 4de7b7c504 | |||
| df4634bb6a | |||
| fa338784d9 | |||
| ca501350e1 | |||
| db597d3a2b | |||
| 49b3ba9e34 | |||
| d7bdbe0420 | |||
| 86f9c2e0fb | |||
| c7d4b3e45a | |||
| 1bbe821474 | |||
| f9d46b15c8 | |||
| 8d80e6399a | |||
| e2ec6a57ff | |||
| 661466df50 | |||
| 2d45112fc4 | |||
| bf4b6c6dcd | |||
| 170aa7fd79 | |||
| 825ad67c6e | |||
| cfd2c66ea4 | |||
| 323258443f | |||
| e7c45601de | |||
| 61a18e8a0d | |||
| 2c5b292888 | |||
| 8a7538338f | |||
| c088bd776e | |||
| 7a2232ee46 | |||
| d52067a8d2 | |||
| 821344d0f2 | |||
| 2536f989c7 | |||
| 828cb7dc3b | |||
| eac8b86fcf | |||
| ef13f95cc2 | |||
| 3fa528cca1 | |||
| 585d2185bc | |||
| 817c43ed75 | |||
| ba75191d37 | |||
| df8dfa0ddb | |||
| 093269ebcd | |||
| 556ab591f9 | |||
| a91727c886 | |||
| ff567918b1 | |||
| e4f16f0d4e | |||
| 98f3488520 | |||
| ac7830ff50 | |||
| 12d60b81b8 | |||
| 8744787348 | |||
| fb37b423bd | |||
| 5e171a3ac9 | |||
| f8ffb1641f | |||
| eb86123a47 | |||
| cd1e6e7766 | |||
| 2fa5056ffd | |||
| ebe6b092a7 | |||
| 78a37292cc | |||
| 749a83d28b | |||
| 91a8aa22b7 | |||
| f7084cc07b | |||
| fa900941d5 | |||
| 4da5cea54c | |||
| d83ab22d45 | |||
| c1229f65a1 | |||
| 8b8bf8d6aa | |||
| 08200cb5e8 | |||
| bce5bb7d14 | |||
| f07fed4804 | |||
| 8112bd6af4 | |||
| e0443512e6 | |||
| cbfe972ace | |||
| e078700af9 | |||
| 0c74863be9 | |||
| 2779280b83 | |||
| 176c86a73e | |||
| 694c2d9e85 | |||
| 7fd7dba118 | |||
| b998b4c967 | |||
| 206eb4d2cb | |||
| bbee178ff9 | |||
| 67775552b5 | |||
| 54f02890cb | |||
| b7bce5efd2 | |||
| 8f13c8e37a | |||
| eccc452d80 | |||
| 7a1c36f8db | |||
| 654095786e | |||
| 73d36d34c8 | |||
| 4126b0574a | |||
| e2bc9aa6d0 | |||
| 670721ac52 | |||
| e195ea5221 | |||
| ea1ebb4bba | |||
| 6a60039aac | |||
| 96485ec8d0 | |||
| 2b9621e7cf | |||
| 747bf2c3c1 |
+5
-6
@@ -14,8 +14,10 @@ cache
|
||||
log.txt
|
||||
errors.txt
|
||||
traceback.txt
|
||||
|
||||
styles.txt
|
||||
|
||||
/android
|
||||
/build
|
||||
/dist
|
||||
/dists
|
||||
@@ -23,12 +25,8 @@ styles.txt
|
||||
/jedit
|
||||
/lint.txt
|
||||
/renpy.code
|
||||
/testing*
|
||||
/*testing*
|
||||
/screenshot*
|
||||
/Microsoft.VC90.CRT.manifest
|
||||
/console.exe
|
||||
/msvcr90.dll
|
||||
/python27.dll
|
||||
/renpy.exe
|
||||
/lib
|
||||
/lib.old
|
||||
@@ -38,7 +36,7 @@ styles.txt
|
||||
/.project
|
||||
/.settings
|
||||
/LICENSE.txt
|
||||
/template/README.html
|
||||
/templates/english/README.html
|
||||
/the_question/README.html
|
||||
/tutorial/README.html
|
||||
/renpy/angle/*.pyx
|
||||
@@ -52,3 +50,4 @@ styles.txt
|
||||
dl
|
||||
renpy/vc_version.py
|
||||
.externalToolBuilders
|
||||
rapt-*
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from renpy import version_tuple #@UnresolvedImport
|
||||
|
||||
@@ -31,7 +32,26 @@ elif args.experimental:
|
||||
else:
|
||||
links = [ ]
|
||||
tag = False
|
||||
|
||||
|
||||
|
||||
def check_dirty():
|
||||
if args.no_tag:
|
||||
return
|
||||
|
||||
if subprocess.check_call([ "git", "diff", "--quiet", "HEAD" ]):
|
||||
print "Directory not checked in: {}".format(os.getcwd())
|
||||
sys.exit(1)
|
||||
|
||||
os.chdir("/home/tom/ab/renpy")
|
||||
check_dirty()
|
||||
|
||||
os.chdir("/home/tom/ab/renpy/android")
|
||||
check_dirty()
|
||||
subprocess.check_call([ "./add_renpy.sh", short_version ])
|
||||
|
||||
if not args.no_tag:
|
||||
subprocess.check_call([ "git", "tag", "-a", "rapt-" + version, "-m", "Tagging RAPT release." ])
|
||||
|
||||
os.chdir("/home/tom/ab/renpy/dl")
|
||||
|
||||
for i in links:
|
||||
@@ -41,7 +61,7 @@ for i in links:
|
||||
|
||||
os.chdir("/home/tom/ab/renpy")
|
||||
|
||||
if tag and not args.no_tag:
|
||||
if tag and not args.no_tag:
|
||||
cmd = [ "git", "tag", "-a", version, "-m", "Ren'Py " + version ]
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
+3
-4
@@ -1,16 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOT="$(dirname $(readlink -f $0))"
|
||||
ROOT="$(dirname $(python -c "import os;print(os.path.realpath('$0'))"))"
|
||||
|
||||
ln -s "$ROOT/help.html" "$ROOT/tutorial/README.html"
|
||||
ln -s "$ROOT/help.html" "$ROOT/the_question/README.html"
|
||||
ln -s "$ROOT/help.html" "$ROOT/template/README.html"
|
||||
ln -s "$ROOT/help.html" "$ROOT/templates/english/README.html"
|
||||
|
||||
ln -s "$ROOT/sphinx/source/license.rst" "$ROOT/LICENSE.txt"
|
||||
ln -s "$ROOT/sphinx/build/html" "$ROOT/doc"
|
||||
|
||||
if [ "$1" != "" ]; then
|
||||
ln -s "$1/lib" "$ROOT/lib"
|
||||
ln -s "$1/renpy.app" "$ROOT"
|
||||
ln -s "$1/renpy.exe" "$ROOT"
|
||||
fi
|
||||
fi
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# This file sets up the normal python modules. It's used to help eclipse
|
||||
# This file sets up the normal python modules. It's used to help eclipse
|
||||
# do type detection, by providing an importable version of the cython code.
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
lib\windows-i686\python.exe -OO renpy.py
|
||||
pause
|
||||
+94
-155
@@ -1,84 +1,16 @@
|
||||
#!/home/tom/bin/renpython -OO
|
||||
# Builds a distributions of Ren'Py.
|
||||
#!/home/tom/bin/renpython -O
|
||||
|
||||
# Builds a distribution of Ren'Py.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import zipfile
|
||||
import tarfile
|
||||
import zlib
|
||||
import compileall
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
import argparse
|
||||
|
||||
CWD = os.getcwdu()
|
||||
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
|
||||
# Gets the data for the given file.
|
||||
def data(fn):
|
||||
|
||||
rv = file(fn, "rb").read()
|
||||
|
||||
if fn.startswith("renpy.app"):
|
||||
return rv
|
||||
|
||||
if fn.endswith(".rpy") or fn.endswith(".rpym") or fn.endswith(".py") or fn.endswith(".txt"):
|
||||
rv = rv.replace("\n", "\r\n")
|
||||
rv = rv.replace("\r\r\n", "\r\n")
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def tarup(filename, prefix, files):
|
||||
|
||||
tf = tarfile.open(filename, "w:bz2")
|
||||
tf.dereference = True
|
||||
|
||||
sys.stdout.write(filename)
|
||||
sys.stdout.flush()
|
||||
|
||||
for fn in files:
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
|
||||
tf.add(fn, prefix + "/" + fn, False)
|
||||
|
||||
sys.stdout.write("\n")
|
||||
|
||||
tf.close()
|
||||
|
||||
|
||||
# Creates a zip file.
|
||||
def zipup(filename, prefix, files):
|
||||
|
||||
zf = zipfile.ZipFile(filename, "w")
|
||||
|
||||
sys.stdout.write(filename)
|
||||
sys.stdout.flush()
|
||||
|
||||
for fn in files:
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
|
||||
zi = zipfile.ZipInfo(prefix + "/" + fn)
|
||||
|
||||
st = os.stat(fn)
|
||||
|
||||
zi.date_time = time.gmtime(st.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
zi.external_attr = long(st.st_mode) << 16
|
||||
|
||||
zf.writestr(zi, data(fn))
|
||||
|
||||
zf.close()
|
||||
|
||||
sys.stdout.write("\n")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def copy_tutorial_file(src, dest):
|
||||
"""
|
||||
Copies a file from src to dst. Lines between "# tutorial-only" and
|
||||
@@ -87,10 +19,10 @@ def copy_tutorial_file(src, dest):
|
||||
|
||||
sf = open(src, "rb")
|
||||
df = open(dest, "wb")
|
||||
|
||||
|
||||
# True if we want to copy the line.
|
||||
copy = True
|
||||
|
||||
|
||||
for l in sf:
|
||||
if "# tutorial-only" in l:
|
||||
copy = False
|
||||
@@ -99,49 +31,20 @@ def copy_tutorial_file(src, dest):
|
||||
else:
|
||||
if copy:
|
||||
df.write(l)
|
||||
|
||||
|
||||
sf.close()
|
||||
df.close()
|
||||
|
||||
|
||||
def tree(root):
|
||||
|
||||
rv = [ ]
|
||||
|
||||
for dirname, dirs, filenames in os.walk(root):
|
||||
|
||||
if "saves" in dirs:
|
||||
dirs.remove("saves")
|
||||
|
||||
if ".svn" in dirs:
|
||||
dirs.remove(".svn")
|
||||
|
||||
if ".doctrees" in dirs:
|
||||
dirs.remove(".doctrees")
|
||||
|
||||
for f in filenames:
|
||||
if f[-1] == '~' or f[0] == '.':
|
||||
continue
|
||||
|
||||
if f.endswith(".bak") or f.endswith(".pyc"):
|
||||
continue
|
||||
|
||||
if f == "semantic.cache":
|
||||
continue
|
||||
|
||||
if "libSDL_mixer" in f or "mixer_music" in f:
|
||||
continue
|
||||
|
||||
rv.append(dirname + "/" + f)
|
||||
|
||||
return rv
|
||||
|
||||
def main():
|
||||
|
||||
if not sys.flags.optimize:
|
||||
raise Exception("Not running with python optimization.")
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("version")
|
||||
ap.add_argument("--fast", action="store_true")
|
||||
|
||||
|
||||
args = ap.parse_args()
|
||||
|
||||
# Revision updating is done early, so we can do it even if the rest
|
||||
@@ -157,74 +60,101 @@ def main():
|
||||
s = subprocess.check_output([ "git", "describe", "--tags", "--dirty", "--match", match_version ])
|
||||
parts = s.strip().split("-")
|
||||
vc_version = int(parts[1])
|
||||
|
||||
|
||||
if parts[-1] == "dirty":
|
||||
vc_version += 1
|
||||
|
||||
|
||||
with open("renpy/vc_version.py", "w") as f:
|
||||
f.write("vc_version = {}".format(vc_version))
|
||||
|
||||
reload(sys.modules['renpy.vc_version']) #@UndefinedVariable
|
||||
try:
|
||||
reload(sys.modules['renpy.vc_version']) #@UndefinedVariable
|
||||
except:
|
||||
import renpy.vc_version # @UnusedImport
|
||||
|
||||
reload(sys.modules['renpy'])
|
||||
|
||||
# Check that the versions match.
|
||||
full_version = ".".join(str(i) for i in renpy.version_tuple) #@UndefinedVariable
|
||||
if args.version != "experimental" and not full_version.startswith(args.version):
|
||||
raise Exception("The command-line and Ren'Py versions do not match.")
|
||||
if args.version != "experimental" \
|
||||
and not args.version.startswith("renpy-nightly-") \
|
||||
and not full_version.startswith(args.version):
|
||||
|
||||
print "Version {} ({})".format(args.version, full_version)
|
||||
|
||||
# Copy over the screens, to keep them up to date.
|
||||
copy_tutorial_file("tutorial/game/screens.rpy", "template/game/screens.rpy")
|
||||
|
||||
# Compile all the python files.
|
||||
compileall.compile_dir("renpy/", ddir="renpy/", force=1, quiet=1)
|
||||
|
||||
# Compile the various games
|
||||
|
||||
if not args.fast:
|
||||
for i in [ 'tutorial', 'launcher', 'template', 'the_question' ]:
|
||||
print "Compiling", i
|
||||
subprocess.check_call(["./renpy.sh", i, "compile" ])
|
||||
raise Exception("The command-line and Ren'Py versions do not match.")
|
||||
|
||||
# The destination directory.
|
||||
destination = os.path.join("dl", args.version)
|
||||
|
||||
|
||||
print "Version {} ({})".format(args.version, full_version)
|
||||
|
||||
# Copy over the screens, to keep them up to date.
|
||||
copy_tutorial_file("tutorial/game/screens.rpy", "templates/english/game/screens.rpy")
|
||||
|
||||
# Compile all the python files.
|
||||
compileall.compile_dir("renpy/", ddir="renpy/", force=1, quiet=1)
|
||||
|
||||
# Compile the various games
|
||||
|
||||
if not args.fast:
|
||||
for i in [ 'tutorial', 'launcher', 'templates/english', 'templates/japanese', 'the_question' ]:
|
||||
print "Compiling", i
|
||||
subprocess.check_call(["./renpy.sh", i, "quit" ])
|
||||
|
||||
|
||||
|
||||
if not os.path.exists(destination):
|
||||
os.makedirs(destination)
|
||||
|
||||
if args.fast:
|
||||
|
||||
cmd = [
|
||||
"./renpy.sh",
|
||||
"launcher",
|
||||
"distribute",
|
||||
"launcher",
|
||||
"./renpy.sh",
|
||||
"launcher",
|
||||
"distribute",
|
||||
"launcher",
|
||||
"--package",
|
||||
"sdk",
|
||||
"--destination",
|
||||
"--destination",
|
||||
destination,
|
||||
"--no-update",
|
||||
]
|
||||
|
||||
else:
|
||||
cmd = [
|
||||
"./renpy.sh",
|
||||
"launcher",
|
||||
"distribute",
|
||||
"launcher",
|
||||
"--destination",
|
||||
"./renpy.sh",
|
||||
"launcher",
|
||||
"distribute",
|
||||
"launcher",
|
||||
"--destination",
|
||||
destination,
|
||||
]
|
||||
|
||||
|
||||
print
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
# Kick off the rapt build.
|
||||
if not args.fast:
|
||||
out = open("/tmp/rapt_build.txt", "wb")
|
||||
|
||||
print("Building RAPT in the background.")
|
||||
|
||||
android = os.path.abspath("android")
|
||||
|
||||
rapt_build = subprocess.Popen([
|
||||
os.path.join(android, "build_renpy.sh"),
|
||||
zip_version
|
||||
],
|
||||
cwd = android,
|
||||
stdout=out,
|
||||
stderr=out)
|
||||
else:
|
||||
rapt_build = None
|
||||
|
||||
# Sign the update.
|
||||
if not args.fast:
|
||||
subprocess.check_call([
|
||||
"scripts/sign_update.py",
|
||||
"/home/tom/ab/keys/renpy_private.pem",
|
||||
subprocess.check_call([
|
||||
"scripts/sign_update.py",
|
||||
"/home/tom/ab/keys/renpy_private.pem",
|
||||
os.path.join(destination, "updates.json"),
|
||||
])
|
||||
|
||||
@@ -238,49 +168,58 @@ def main():
|
||||
|
||||
with open("7z.sfx", "rb") as f:
|
||||
sfx = f.read()
|
||||
|
||||
|
||||
os.chdir(destination)
|
||||
|
||||
if os.path.exists(sdk):
|
||||
shutil.rmtree(sdk)
|
||||
|
||||
|
||||
subprocess.check_call([ "unzip", "-q", sdk + ".zip" ])
|
||||
|
||||
|
||||
if os.path.exists(sdk + ".7z"):
|
||||
os.unlink(sdk + ".7z")
|
||||
|
||||
|
||||
sys.stdout.write("Creating -sdk.7z")
|
||||
|
||||
|
||||
p = subprocess.Popen([ "7z", "a", sdk +".7z", sdk], stdout=subprocess.PIPE)
|
||||
for i, _l in enumerate(p.stdout):
|
||||
if i % 10 != 0:
|
||||
continue
|
||||
|
||||
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
|
||||
if p.wait() != 0:
|
||||
raise Exception("7z failed")
|
||||
|
||||
|
||||
with open(sdk + ".7z", "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
|
||||
with open(sdk + ".7z.exe", "wb") as f:
|
||||
f.write(sfx)
|
||||
f.write(data)
|
||||
|
||||
|
||||
os.unlink(sdk + ".7z")
|
||||
shutil.rmtree(sdk)
|
||||
|
||||
else:
|
||||
os.chdir(destination)
|
||||
|
||||
|
||||
if os.path.exists(sdk + ".7z.exe"):
|
||||
os.unlink(sdk + ".7z.exe")
|
||||
|
||||
print
|
||||
print "Did you run me with renpython -OO?"
|
||||
|
||||
print
|
||||
|
||||
if rapt_build:
|
||||
code = rapt_build.wait()
|
||||
if code:
|
||||
print "RAPT build failed. The output is in /tmp/rapt_build.txt"
|
||||
else:
|
||||
print "RAPT build succeeded."
|
||||
|
||||
print
|
||||
print "Did you run me with renpython -O?"
|
||||
print "Did you update renpy.py and launcher/script_version.rpy?"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# Checks for various abilities that might be taken away from us by
|
||||
# Checks for various abilities that might be taken away from us by
|
||||
# redistributors.
|
||||
|
||||
init 1 python in ability:
|
||||
|
||||
|
||||
from store import config
|
||||
import store
|
||||
import store.updater as updater
|
||||
|
||||
|
||||
import os
|
||||
|
||||
|
||||
EXECUTABLES = [ "renpy.exe", "renpy.app", "renpy.sh" ]
|
||||
|
||||
# can_distribute - True if we can distribute
|
||||
|
||||
# can_distribute - True if we can distribute
|
||||
for i in EXECUTABLES:
|
||||
if not os.path.exists(os.path.join(config.renpy_base, i)):
|
||||
can_distribute = False
|
||||
else:
|
||||
can_distribute = True
|
||||
|
||||
|
||||
|
||||
|
||||
# can_update - True if we can update.
|
||||
can_update = updater.can_update() or (store.UPDATE_SIMULATE is not None)
|
||||
|
||||
|
||||
|
||||
@@ -2,30 +2,30 @@
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
screen about:
|
||||
|
||||
|
||||
$ version = renpy.version()
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
xfill True
|
||||
|
||||
|
||||
has vbox xfill True
|
||||
|
||||
add "logo.png" xalign 0.5 yoffset -5
|
||||
|
||||
null height 15
|
||||
|
||||
|
||||
text _("[version!q]") xalign 0.5 bold True
|
||||
|
||||
|
||||
null height 20
|
||||
|
||||
textbutton _("View license") action interface.OpenLicense() xalign 0.5
|
||||
|
||||
|
||||
textbutton _("Back") action Jump("front_page") style "l_left_button"
|
||||
|
||||
label about:
|
||||
call screen about
|
||||
|
||||
|
||||
|
||||
@@ -3,34 +3,34 @@ label add_file:
|
||||
python hide:
|
||||
import os
|
||||
import codecs
|
||||
|
||||
|
||||
filename = interface.input(_("FILENAME"), _("Enter the name of the script file to create."), filename="withslash", cancel=Jump("navigation"))
|
||||
|
||||
|
||||
if "." in filename and not filename.endswith(".rpy"):
|
||||
interface.error(_("The filename must have the .rpy extension."), label="navigation")
|
||||
elif "." not in filename:
|
||||
filename += ".rpy"
|
||||
|
||||
|
||||
path = os.path.join(project.current.gamedir, filename)
|
||||
dir = os.path.dirname(path)
|
||||
|
||||
|
||||
if os.path.exists(path):
|
||||
interface.error(_("The file already exists."), label="navigation")
|
||||
|
||||
|
||||
contents = u"\uFEFF"
|
||||
contents += _("# 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")
|
||||
contents += "\n"
|
||||
|
||||
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
contents = u"\uFEFF"
|
||||
contents += _("# 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")
|
||||
|
||||
with open(path, "wb") as f:
|
||||
f.write(contents.encode("utf-8"))
|
||||
|
||||
|
||||
jump navigation_refresh
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python:
|
||||
ANDROID_NO_JDK = 0
|
||||
ANDROID_NO_RAPT = 1
|
||||
ANDROID_NO_SDK = 2
|
||||
ANDROID_NO_KEY = 3
|
||||
ANDROID_NO_CONFIG = 4
|
||||
ANDROID_OK = 5
|
||||
|
||||
|
||||
NO_JDK_TEXT = _("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.")
|
||||
NO_RAPT_TEXT = _("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.")
|
||||
NO_SDK_TEXT = _("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.")
|
||||
NO_KEY_TEXT = _("RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore.")
|
||||
NO_CONFIG_TEXT = _("The current project has not been configured. Use \"Configure\" to configure it before building.")
|
||||
OK_TEXT = _("Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device.")
|
||||
|
||||
PHONE_TEXT = _("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.")
|
||||
TABLET_TEXT = _("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.")
|
||||
OUYA_TEXT = _("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.")
|
||||
|
||||
INSTALL_SDK_TEXT = _("Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package.")
|
||||
CONFIGURE_TEXT = _("Configures the package name, version, and other information about this project.")
|
||||
PLAY_KEYS_TEXT = _("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.")
|
||||
BUILD_TEXT = _("Builds the Android package.")
|
||||
BUILD_AND_INSTALL_TEXT = _("Builds the Android package, and installs it on an Android device connected to your computer.")
|
||||
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
|
||||
def find_rapt():
|
||||
|
||||
global RAPT_PATH
|
||||
|
||||
candidates = [ ]
|
||||
|
||||
for fn in os.listdir(config.renpy_base):
|
||||
if not fn.startswith("rapt-"):
|
||||
continue
|
||||
|
||||
if not os.path.isdir(os.path.join(config.renpy_base, fn)):
|
||||
continue
|
||||
|
||||
try:
|
||||
version = fn[5:]
|
||||
version = tuple(int(i) for i in version.split('.'))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
candidates.append((version, fn))
|
||||
|
||||
if not candidates:
|
||||
RAPT_PATH = None
|
||||
else:
|
||||
RAPT_PATH = os.path.join(config.renpy_base, candidates[-1][1])
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, os.path.join(RAPT_PATH, "buildlib"))
|
||||
|
||||
find_rapt()
|
||||
|
||||
import threading
|
||||
|
||||
if RAPT_PATH:
|
||||
import rapt
|
||||
import rapt.build
|
||||
import rapt.configure
|
||||
import rapt.install_sdk
|
||||
import rapt.plat
|
||||
else:
|
||||
rapt = None
|
||||
|
||||
def AndroidState():
|
||||
"""
|
||||
Determines the state of the android install, and returns it.
|
||||
"""
|
||||
|
||||
if renpy.windows and not "JAVA_HOME" in os.environ:
|
||||
return ANDROID_NO_JDK
|
||||
if RAPT_PATH is None:
|
||||
return ANDROID_NO_RAPT
|
||||
if not os.path.exists(os.path.join(RAPT_PATH, "android-sdk/extras/google/play_licensing")):
|
||||
return ANDROID_NO_SDK
|
||||
if not os.path.exists(os.path.join(RAPT_PATH, "android.keystore")):
|
||||
return ANDROID_NO_KEY
|
||||
if not os.path.exists(os.path.join(project.current.path, ".android.json")):
|
||||
return ANDROID_NO_CONFIG
|
||||
return ANDROID_OK
|
||||
|
||||
|
||||
def AndroidStateText(state):
|
||||
"""
|
||||
Returns text corresponding to the state.
|
||||
"""
|
||||
|
||||
if state == ANDROID_NO_JDK:
|
||||
return NO_JDK_TEXT
|
||||
if state == ANDROID_NO_RAPT:
|
||||
return NO_RAPT_TEXT
|
||||
if state == ANDROID_NO_SDK:
|
||||
return NO_SDK_TEXT
|
||||
if state == ANDROID_NO_KEY:
|
||||
return NO_KEY_TEXT
|
||||
if state == ANDROID_NO_CONFIG:
|
||||
return NO_CONFIG_TEXT
|
||||
if state == ANDROID_OK:
|
||||
return OK_TEXT
|
||||
|
||||
def AndroidIfState(state, needed, action):
|
||||
"""
|
||||
If `state` is `needed` or better, `action` is returned. Otherwise,
|
||||
returns None, disabling the button.
|
||||
"""
|
||||
|
||||
if state >= needed:
|
||||
return action
|
||||
else:
|
||||
return None
|
||||
|
||||
class AndroidInterface(object):
|
||||
|
||||
def __init__(self):
|
||||
self.process = None
|
||||
self.filename = project.current.temp_filename("android.txt")
|
||||
|
||||
self.info_msg = ""
|
||||
|
||||
with open(self.filename, "w"):
|
||||
pass
|
||||
|
||||
def info(self, prompt):
|
||||
self.info_msg = prompt
|
||||
interface.processing(prompt, pause=False)
|
||||
|
||||
def yesno(self, prompt, submessage=None):
|
||||
return interface.yesno(prompt, submessage=submessage)
|
||||
|
||||
def yesno_choice(self, prompt, default=None):
|
||||
choices = [ (True, "Yes"), (False, "No") ]
|
||||
return interface.choice(prompt, choices, default)
|
||||
|
||||
def terms(self, url, prompt):
|
||||
submessage = _("{a=%s}%s{/a}") % (url, url)
|
||||
return interface.yesno(prompt, submessage=submessage)
|
||||
|
||||
def input(self, prompt, empty=None):
|
||||
|
||||
if empty is None:
|
||||
empty = ''
|
||||
|
||||
while True:
|
||||
rv = interface.input(_("QUESTION"), prompt, default=empty, cancel=Jump("android"))
|
||||
|
||||
rv = rv.strip()
|
||||
|
||||
if rv:
|
||||
return rv
|
||||
|
||||
def choice(self, prompt, choices, default):
|
||||
return interface.choice(prompt, choices, default, cancel=Jump("android"))
|
||||
|
||||
def fail(self, prompt):
|
||||
prompt = re.sub(r'(http://\S+)', r'{a=\1}\1{/a}', prompt)
|
||||
interface.error(prompt, label="android")
|
||||
|
||||
def success(self, prompt):
|
||||
interface.info(prompt, pause=False)
|
||||
|
||||
def final_success(self, prompt):
|
||||
interface.info(prompt, label="android")
|
||||
|
||||
def call(self, cmd, cancel=False, use_path=False):
|
||||
|
||||
if not use_path:
|
||||
cmd = [ rapt.plat.path(cmd[0]) ] + list(cmd[1:])
|
||||
|
||||
self.cmd = cmd
|
||||
|
||||
f = open(self.filename, "a")
|
||||
|
||||
f.write("\n\n\n")
|
||||
|
||||
if cancel:
|
||||
cancel_action = self.cancel
|
||||
else:
|
||||
cancel_action = None
|
||||
|
||||
startupinfo = None
|
||||
if renpy.windows:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
|
||||
try:
|
||||
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action)
|
||||
self.process = subprocess.Popen(cmd, cwd=RAPT_PATH, stdout=f, stderr=f, startupinfo=startupinfo)
|
||||
renpy.call_screen("android_process", interface=self)
|
||||
finally:
|
||||
f.close()
|
||||
interface.hide_screen()
|
||||
self.process = None
|
||||
|
||||
def check_process(self):
|
||||
rv = self.process.poll()
|
||||
|
||||
if rv is not None:
|
||||
if rv:
|
||||
raise subprocess.CalledProcessError(rv, self.cmd)
|
||||
else:
|
||||
return True
|
||||
|
||||
def download(self, url, dest):
|
||||
try:
|
||||
d = Downloader(url, dest)
|
||||
cancel_action = [ d.cancel, Jump("android") ]
|
||||
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action, bar_value=DownloaderValue(d))
|
||||
ui.timer(.1, action=d.check, repeat=True)
|
||||
ui.interact()
|
||||
finally:
|
||||
interface.hide_screen()
|
||||
|
||||
def background(self, f):
|
||||
try:
|
||||
t = threading.Thread(target=f)
|
||||
t.start()
|
||||
|
||||
interface.processing(self.info_msg, show_screen=True)
|
||||
|
||||
while t.is_alive():
|
||||
renpy.pause(0)
|
||||
t.join(0.25)
|
||||
|
||||
finally:
|
||||
interface.hide_screen()
|
||||
|
||||
|
||||
def cancel(self):
|
||||
if self.process:
|
||||
self.process.terminate()
|
||||
|
||||
renpy.jump("android")
|
||||
|
||||
|
||||
class AndroidBuild(Action):
|
||||
"""
|
||||
Activates an Android build process.
|
||||
"""
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
def __call__(self):
|
||||
renpy.jump(self.label)
|
||||
|
||||
class LaunchEmulator(Action):
|
||||
|
||||
def __init__(self, emulator, variants):
|
||||
self.emulator = emulator
|
||||
self.variants = variants
|
||||
|
||||
def __call__(self):
|
||||
|
||||
env = {
|
||||
"RENPY_EMULATOR" : self.emulator,
|
||||
"RENPY_VARIANT" : self.variants,
|
||||
}
|
||||
|
||||
p = project.current
|
||||
p.launch(env=env)
|
||||
|
||||
def update_android_json():
|
||||
"""
|
||||
Updates .android.json to include the google play information.
|
||||
"""
|
||||
|
||||
project.current.update_dump(True)
|
||||
|
||||
build = project.current.dump["build"]
|
||||
|
||||
filename = os.path.join(project.current.path, ".android.json")
|
||||
|
||||
with open(filename, "r") as f:
|
||||
android_json = json.load(f)
|
||||
|
||||
if "google_play_key" in build:
|
||||
android_json["google_play_key"] = build["google_play_key"]
|
||||
else:
|
||||
android_json.pop("google_play_key", None)
|
||||
|
||||
if "google_play_salt" in build:
|
||||
|
||||
if len(build["google_play_salt"]) != 20:
|
||||
raise Exception("build.google_play_salt must be exactly 20 bytes long.")
|
||||
|
||||
android_json["google_play_salt"] = ", ".join(str(i) for i in build["google_play_salt"])
|
||||
else:
|
||||
android_json.pop("google_play_salt", None)
|
||||
|
||||
|
||||
with open(filename, "w") as f:
|
||||
json.dump(android_json, f)
|
||||
|
||||
def android_build(command):
|
||||
"""
|
||||
This actually builds the package.
|
||||
"""
|
||||
|
||||
update_android_json()
|
||||
|
||||
dist = project.current.temp_filename("android.dist")
|
||||
|
||||
if os.path.exists(dist):
|
||||
shutil.rmtree(dist)
|
||||
|
||||
distribute.Distributor(project.current,
|
||||
reporter=distribute.GuiReporter(),
|
||||
packages=[ 'android' ],
|
||||
build_update=False,
|
||||
noarchive=True,
|
||||
packagedest=dist,
|
||||
report_success=False,
|
||||
)
|
||||
|
||||
with interface.nolinks():
|
||||
rapt.build.build(AndroidInterface(), dist, command)
|
||||
|
||||
# The android support can stick unicode into os.environ. Fix that.
|
||||
init 100 python:
|
||||
for k, v in list(os.environ.items()):
|
||||
if isinstance(v, str):
|
||||
os.environ[k] = renpy.fsencode(v)
|
||||
|
||||
screen android_process(interface):
|
||||
|
||||
zorder 100
|
||||
|
||||
default ft = FileTail(interface.filename)
|
||||
|
||||
text "[ft.text!q]":
|
||||
size 14
|
||||
color TEXT
|
||||
font "Roboto-Light.ttf"
|
||||
xpos 75
|
||||
ypos 350
|
||||
|
||||
timer .1 action interface.check_process repeat True
|
||||
timer .2 action ft.update repeat True
|
||||
|
||||
|
||||
screen android:
|
||||
|
||||
default tt = Tooltip(None)
|
||||
$ state = AndroidState()
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
window:
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Android: [project.current.name!q]")
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
hbox:
|
||||
|
||||
# Left side.
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONEHALF
|
||||
xfill True
|
||||
|
||||
has vbox
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
text _("Emulation:")
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
has vbox
|
||||
|
||||
textbutton _("Phone"):
|
||||
action LaunchEmulator("touch", "small phone touch android")
|
||||
hovered tt.Action(PHONE_TEXT)
|
||||
|
||||
textbutton _("Tablet"):
|
||||
action LaunchEmulator("touch", "medium tablet touch android")
|
||||
hovered tt.Action(TABLET_TEXT)
|
||||
|
||||
textbutton _("Television / OUYA"):
|
||||
action LaunchEmulator("tv", "small tv ouya android")
|
||||
hovered tt.Action(OUYA_TEXT)
|
||||
|
||||
|
||||
add SPACER
|
||||
add SEPARATOR2
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
text _("Build:")
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
has vbox
|
||||
|
||||
textbutton _("Install SDK & Create Keys"):
|
||||
action AndroidIfState(state, ANDROID_NO_SDK, Jump("android_installsdk"))
|
||||
hovered tt.Action(INSTALL_SDK_TEXT)
|
||||
|
||||
textbutton _("Configure"):
|
||||
action AndroidIfState(state, ANDROID_NO_CONFIG, Jump("android_configure"))
|
||||
hovered tt.Action(CONFIGURE_TEXT)
|
||||
|
||||
textbutton _("Build Package"):
|
||||
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build"))
|
||||
hovered tt.Action(BUILD_TEXT)
|
||||
|
||||
textbutton _("Build & Install"):
|
||||
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_and_install"))
|
||||
hovered tt.Action(BUILD_AND_INSTALL_TEXT)
|
||||
|
||||
|
||||
|
||||
# Right side.
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONEHALF
|
||||
xfill True
|
||||
|
||||
has vbox
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
add SPACER
|
||||
|
||||
if tt.value:
|
||||
text tt.value
|
||||
else:
|
||||
text AndroidStateText(state)
|
||||
|
||||
|
||||
textbutton _("Back") action Jump("front_page") style "l_left_button"
|
||||
|
||||
|
||||
label android:
|
||||
call screen android
|
||||
|
||||
|
||||
label android_installsdk:
|
||||
|
||||
python:
|
||||
with interface.nolinks():
|
||||
rapt.install_sdk.install_sdk(AndroidInterface())
|
||||
|
||||
jump android
|
||||
|
||||
|
||||
label android_configure:
|
||||
|
||||
python:
|
||||
rapt.configure.configure(AndroidInterface(), project.current.path)
|
||||
|
||||
jump android
|
||||
|
||||
|
||||
label android_build:
|
||||
|
||||
$ android_build([ 'release' ])
|
||||
|
||||
jump android
|
||||
|
||||
|
||||
label android_build_and_install:
|
||||
|
||||
$ android_build([ 'release', 'install' ])
|
||||
|
||||
jump android
|
||||
@@ -2,7 +2,7 @@
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# Ren'Py archiver. This builds a Ren'Py archive file, and the
|
||||
# associated index file. These files are really easy to
|
||||
# associated index file. These files are really easy to
|
||||
# reverse-engineer, but are probably better than nothing.
|
||||
|
||||
init python in archiver:
|
||||
@@ -23,16 +23,16 @@ init python in archiver:
|
||||
|
||||
# The archive file.
|
||||
self.f = open(filename, "wb")
|
||||
|
||||
|
||||
# The index to the file.
|
||||
self.index = _dict()
|
||||
|
||||
|
||||
# A fixed key minimizes difference between archive versions.
|
||||
self.key = 0x42424242
|
||||
|
||||
padding = "RPA-3.0 XXXXXXXXXXXXXXXX XXXXXXXX\n"
|
||||
self.f.write(padding)
|
||||
|
||||
|
||||
def add(self, name, path):
|
||||
"""
|
||||
Adds a file to the archive.
|
||||
@@ -55,7 +55,7 @@ init python in archiver:
|
||||
self.index[name].append((offset ^ self.key, dlen ^ self.key, ""))
|
||||
|
||||
def close(self):
|
||||
|
||||
|
||||
indexoff = self.f.tell()
|
||||
|
||||
self.f.write(dumps(self.index, HIGHEST_PROTOCOL).encode("zlib"))
|
||||
@@ -64,4 +64,4 @@ init python in archiver:
|
||||
self.f.write("RPA-3.0 %016x %08x\n" % (indexoff, self.key))
|
||||
|
||||
self.f.close()
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class BinFile(object):
|
||||
self.a[addr+1] = (value >> 8) & 0xff
|
||||
self.a[addr+2] = (value >> 16) & 0xff
|
||||
self.a[addr+3] = (value >> 24) & 0xff
|
||||
|
||||
|
||||
def u32(self):
|
||||
addr = self.addr
|
||||
rv = self.a[addr]
|
||||
@@ -46,7 +46,7 @@ class BinFile(object):
|
||||
rv += unichr(self.u16())
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def seek(self, addr):
|
||||
self.addr = addr
|
||||
|
||||
@@ -55,7 +55,7 @@ class BinFile(object):
|
||||
|
||||
def substring(self, start, len): #@ReservedAssignment
|
||||
return self.a[start:start+len].tostring()
|
||||
|
||||
|
||||
def __init__(self, data):
|
||||
self.a = array.array('B')
|
||||
self.a.fromstring(data)
|
||||
@@ -66,7 +66,7 @@ class BinFile(object):
|
||||
|
||||
# The virtual address of the resource segment.
|
||||
resource_virtual = 0
|
||||
|
||||
|
||||
# This parses a data block out of the resources.
|
||||
def parse_data(bf, offset):
|
||||
bf.seek(offset)
|
||||
@@ -95,7 +95,7 @@ def parse_directory(bf, offset):
|
||||
n_id = bf.u16()
|
||||
|
||||
entries = [ ]
|
||||
|
||||
|
||||
for _i in range(n_named + n_id):
|
||||
entries.append((bf.u32(), bf.u32()))
|
||||
|
||||
@@ -113,8 +113,8 @@ def parse_directory(bf, offset):
|
||||
value = parse_data(bf, value)
|
||||
|
||||
rv[name] = value
|
||||
|
||||
return rv
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -124,7 +124,7 @@ def show_resources(d, prefix):
|
||||
if not isinstance(d, dict):
|
||||
print prefix, "Codepage", d[0], "length", len(d[1])
|
||||
return
|
||||
|
||||
|
||||
for k in d:
|
||||
print prefix, k
|
||||
show_resources(d[k], prefix + " ")
|
||||
@@ -141,7 +141,7 @@ class Packer(object):
|
||||
|
||||
self.entries = ""
|
||||
self.entries_offset = 0
|
||||
|
||||
|
||||
head = self.pack_dict(d, 0)
|
||||
|
||||
self.data = ""
|
||||
@@ -151,44 +151,44 @@ class Packer(object):
|
||||
self.entries_offset = len(head)
|
||||
|
||||
return self.pack_dict(d, 0) + self.entries + self.data
|
||||
|
||||
|
||||
def pack_name(self, s):
|
||||
rv = self.data_offset + len(self.data)
|
||||
|
||||
l = len(s)
|
||||
s = s.encode("utf-16le")
|
||||
self.data += struct.pack("<H", l) + s + "\0\0"
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
def pack_tuple(self, t):
|
||||
codepage, data = t
|
||||
|
||||
rv = len(self.entries) + self.entries_offset
|
||||
rv = len(self.entries) + self.entries_offset
|
||||
|
||||
if len(self.data) % 2:
|
||||
self.data += "P"
|
||||
|
||||
daddr = len(self.data) + self.data_offset
|
||||
|
||||
|
||||
self.entries += struct.pack("<IIII", daddr + resource_virtual, len(data), codepage, 0)
|
||||
self.data += data
|
||||
|
||||
# if len(self.data) % 1 == 1:
|
||||
# self.data += 'P'
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def pack_dict(self, d, offset):
|
||||
name_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, unicode))
|
||||
id_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, int))
|
||||
|
||||
|
||||
rv = struct.pack("<IIHHHH", 0, 0, 4, 0, len(name_entries), len(id_entries))
|
||||
|
||||
|
||||
offset += len(rv) + (len(name_entries) + len(id_entries)) * 8
|
||||
|
||||
|
||||
rest = ""
|
||||
|
||||
|
||||
for (name, value) in name_entries + id_entries:
|
||||
if isinstance(name, unicode):
|
||||
name = 0x80000000 | self.pack_name(name)
|
||||
@@ -200,11 +200,11 @@ class Packer(object):
|
||||
rest += packed
|
||||
else:
|
||||
addr = self.pack_tuple(value)
|
||||
|
||||
|
||||
rv += struct.pack("<II", name, addr)
|
||||
|
||||
return rv + rest
|
||||
|
||||
|
||||
##############################################################################
|
||||
# This loads in an icon file, and returns a dictionary that is suitable for
|
||||
# use in the resources of an exe file.
|
||||
@@ -219,8 +219,8 @@ def load_icon(fn):
|
||||
rv = { }
|
||||
rv[3] = { }
|
||||
|
||||
group = struct.pack("HHH", 0, 1, count)
|
||||
|
||||
group = struct.pack("HHH", 0, 1, count)
|
||||
|
||||
for i in range(count):
|
||||
width = f.u8()
|
||||
height = f.u8()
|
||||
@@ -235,17 +235,17 @@ def load_icon(fn):
|
||||
f.seek(offset + 16)
|
||||
if not f.u32():
|
||||
f.set_u32(offset + 20, 0)
|
||||
|
||||
|
||||
rv[3][i + 1] = { 0 : (1252, f.substring(offset, size)) }
|
||||
|
||||
|
||||
group += struct.pack("BBBBHHIH", width, height, colors, reserved,
|
||||
planes, bpp, size, i + 1)
|
||||
|
||||
|
||||
f.seek(addr)
|
||||
|
||||
rv[14] = { 1 : { 0 : (1252, group) } }
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
@@ -269,25 +269,25 @@ def change_icons(oldexe, icofn):
|
||||
|
||||
physize = rsrc_section.SizeOfRawData
|
||||
virsize = rsrc_section.Misc_VirtualSize
|
||||
|
||||
|
||||
f = file(oldexe, "rb")
|
||||
f.seek(base)
|
||||
data = f.read(physize)
|
||||
f.close()
|
||||
|
||||
bf = BinFile(data)
|
||||
|
||||
|
||||
resources = parse_directory(bf, 0)
|
||||
# show_resources(resources, "")
|
||||
resources.update(load_icon(icofn))
|
||||
# show_resources(resources, "")
|
||||
|
||||
|
||||
rsrc = Packer().pack(resources)
|
||||
|
||||
alignment = pe.OPTIONAL_HEADER.SectionAlignment
|
||||
|
||||
|
||||
# print "Alignment is", alignment
|
||||
|
||||
|
||||
if len(rsrc) % alignment:
|
||||
pad = alignment - (len(rsrc) % alignment)
|
||||
padding = "RENPYVNE" * (pad / 8 + 1)
|
||||
@@ -295,34 +295,34 @@ def change_icons(oldexe, icofn):
|
||||
rsrc += padding
|
||||
|
||||
newsize = len(rsrc)
|
||||
|
||||
|
||||
rsrc_section.Misc_VirtualSize += newsize - virsize
|
||||
rsrc_section.Misc_PhysicalAddress += newsize - virsize
|
||||
rsrc_section.Misc += newsize - virsize
|
||||
rsrc_section.SizeOfRawData += newsize - physize
|
||||
|
||||
pe.OPTIONAL_HEADER.SizeOfInitializedData += newsize - physize
|
||||
|
||||
pe.OPTIONAL_HEADER.SizeOfInitializedData += newsize - physize
|
||||
|
||||
# Resource size.
|
||||
pe.OPTIONAL_HEADER.DATA_DIRECTORY[2].Size += newsize - virsize
|
||||
|
||||
# Compute the total size of the image.
|
||||
total_size = 0
|
||||
|
||||
|
||||
for i in pe.sections:
|
||||
|
||||
sec_size = i.Misc_VirtualSize
|
||||
sec_size = sec_size - (sec_size % alignment) + alignment
|
||||
|
||||
|
||||
total_size += sec_size
|
||||
|
||||
pe.OPTIONAL_HEADER.SizeOfImage = total_size
|
||||
|
||||
return pe.write()[:base] + rsrc
|
||||
|
||||
return pe.write()[:base] + rsrc
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
f = file(sys.argv[3], "wb")
|
||||
f.write(change_icons(sys.argv[1], sys.argv[2]))
|
||||
f.close()
|
||||
|
||||
|
||||
|
||||
@@ -11,64 +11,64 @@ init python:
|
||||
"""
|
||||
Gets a list of all of the theme names we know about.
|
||||
"""
|
||||
|
||||
|
||||
names = list(theme_data.THEME.keys())
|
||||
names.sort(key=lambda a : a.lower())
|
||||
|
||||
|
||||
return names
|
||||
|
||||
|
||||
def scheme_names(theme):
|
||||
"""
|
||||
Gets a list of the color scheme names corresponding to the given
|
||||
theme.
|
||||
"""
|
||||
|
||||
|
||||
names = list(theme_data.THEME[theme].keys())
|
||||
names.sort(key=lambda a : a.lower())
|
||||
|
||||
|
||||
return names
|
||||
|
||||
def theme_yinitial():
|
||||
names = theme_names()
|
||||
|
||||
|
||||
if len(names) < 2:
|
||||
return 0
|
||||
|
||||
|
||||
return 1.0 * names.index(current_theme) / (len(names) - 1)
|
||||
|
||||
def scheme_yinitial():
|
||||
names = scheme_names(current_theme)
|
||||
|
||||
|
||||
if len(names) < 2:
|
||||
return 0
|
||||
|
||||
|
||||
return 1.0 * names.index(current_scheme) / (len(names) - 1)
|
||||
|
||||
def pick_theme(theme, scheme):
|
||||
"""
|
||||
Returns a theme and scheme that are similar to `theme` and `scheme`.
|
||||
|
||||
Returns a theme and scheme that are similar to `theme` and `scheme`.
|
||||
|
||||
If the theme is known, picks it, otherwise picks a random theme. If
|
||||
the scheme is known for that theme, picks it, otherwise picks a
|
||||
the scheme is known for that theme, picks it, otherwise picks a
|
||||
random scheme that is known for the current theme.
|
||||
"""
|
||||
|
||||
|
||||
if theme not in theme_data.THEME:
|
||||
theme = random.choice(list(theme_data.THEME))
|
||||
|
||||
|
||||
schemes = theme_data.THEME[theme]
|
||||
|
||||
|
||||
if scheme not in schemes:
|
||||
if theme in schemes:
|
||||
scheme = theme
|
||||
else:
|
||||
scheme = random.choice(list(schemes))
|
||||
|
||||
|
||||
return theme, scheme
|
||||
|
||||
|
||||
def implement_theme(theme, scheme):
|
||||
global showing_theme, showing_scheme
|
||||
|
||||
|
||||
if theme == showing_theme and scheme == showing_scheme:
|
||||
return
|
||||
|
||||
@@ -80,52 +80,52 @@ init python:
|
||||
showing_scheme = scheme
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
showing_theme = None
|
||||
showing_scheme = None
|
||||
|
||||
class SetTheme(Action):
|
||||
def __init__(self, theme):
|
||||
self.theme = theme
|
||||
|
||||
|
||||
def __call__(self):
|
||||
global current_theme
|
||||
global current_scheme
|
||||
|
||||
global current_scheme
|
||||
|
||||
current_theme, current_scheme = pick_theme(self.theme, current_scheme)
|
||||
|
||||
|
||||
implement_theme(current_theme, current_scheme)
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
return current_theme == self.theme
|
||||
|
||||
|
||||
class SetScheme(Action):
|
||||
def __init__(self, scheme):
|
||||
self.scheme = scheme
|
||||
|
||||
|
||||
def __call__(self):
|
||||
global current_theme
|
||||
global current_scheme
|
||||
|
||||
global current_scheme
|
||||
|
||||
current_theme, current_scheme = pick_theme(current_theme, self.scheme)
|
||||
|
||||
|
||||
implement_theme(current_theme, current_scheme)
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return current_scheme == self.scheme
|
||||
|
||||
|
||||
class PreviewTheme(Action):
|
||||
|
||||
|
||||
def __init__(self, theme, scheme):
|
||||
self.theme = theme
|
||||
self.scheme = scheme
|
||||
|
||||
|
||||
def __call__(self):
|
||||
theme, scheme = pick_theme(self.theme, self.scheme)
|
||||
implement_theme(theme, scheme)
|
||||
|
||||
|
||||
def unhovered(self):
|
||||
if (showing_theme == self.theme and showing_scheme == self.scheme):
|
||||
implement_theme(current_theme, current_scheme)
|
||||
@@ -135,11 +135,11 @@ init python:
|
||||
|
||||
##########################################################################
|
||||
# Code to update options.rpy
|
||||
|
||||
|
||||
def list_logical_lines(filename):
|
||||
"""
|
||||
This reads in filename, and turns it into a list of logical
|
||||
lines.
|
||||
lines.
|
||||
"""
|
||||
|
||||
f = codecs.open(filename, "rb", "utf-8")
|
||||
@@ -227,7 +227,7 @@ init python:
|
||||
continue
|
||||
|
||||
continue
|
||||
|
||||
|
||||
line += c
|
||||
pos += 1
|
||||
|
||||
@@ -239,7 +239,7 @@ init python:
|
||||
|
||||
def switch_theme():
|
||||
"""
|
||||
Switches the theme of the current project to the current theme
|
||||
Switches the theme of the current project to the current theme
|
||||
and color scheme. (As set in current_theme and current_scheme.)
|
||||
"""
|
||||
|
||||
@@ -258,7 +258,7 @@ init python:
|
||||
if (not changed) and m and (m.group(1) in theme_data.THEME_FUNCTIONS):
|
||||
l = " " + theme_code
|
||||
changed = True
|
||||
|
||||
|
||||
out.write(l + "\n")
|
||||
|
||||
if changed:
|
||||
@@ -272,7 +272,7 @@ init python:
|
||||
else:
|
||||
os.unlink(filename + ".new")
|
||||
interface.error(_("Could not change the theme. Perhaps options.rpy was changed too much."))
|
||||
|
||||
|
||||
|
||||
# Now give the theme's screen-ops function a chance to make any
|
||||
# necessary changes to the screens.rpy file
|
||||
@@ -289,13 +289,13 @@ init python:
|
||||
for l in lines:
|
||||
out.write(l + "\n")
|
||||
changed = True
|
||||
|
||||
|
||||
if changed:
|
||||
try:
|
||||
os.unlink(filename + ".bak")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
os.rename(filename, filename + ".bak")
|
||||
os.rename(filename + ".new", filename)
|
||||
|
||||
@@ -307,13 +307,20 @@ init python:
|
||||
pass
|
||||
pass
|
||||
|
||||
def make_style_backup():
|
||||
"""
|
||||
Call this to back up the styles. This should be called in a
|
||||
translate python block in each translation.
|
||||
"""
|
||||
|
||||
init 100 python:
|
||||
style_backup = renpy.style.backup()
|
||||
global style_backup
|
||||
style_backup = renpy.style.backup()
|
||||
|
||||
translate None python:
|
||||
make_style_backup()
|
||||
|
||||
screen theme_demo:
|
||||
|
||||
|
||||
window:
|
||||
style "gm_root"
|
||||
xpadding 5
|
||||
@@ -324,16 +331,16 @@ screen theme_demo:
|
||||
style_group "prefs"
|
||||
|
||||
vbox:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "pref"
|
||||
has vbox
|
||||
|
||||
|
||||
label _("Display")
|
||||
textbutton _("Window") action SelectedIf(True)
|
||||
textbutton _("Fullscreen") action ui.returns(None)
|
||||
textbutton _("Planetarium") action None
|
||||
|
||||
|
||||
|
||||
frame:
|
||||
style_group "pref"
|
||||
@@ -368,16 +375,16 @@ screen choose_theme:
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Choose Theme")
|
||||
|
||||
hbox:
|
||||
yfill True
|
||||
|
||||
|
||||
# Theme selector.
|
||||
frame:
|
||||
style "l_indent"
|
||||
@@ -385,47 +392,47 @@ screen choose_theme:
|
||||
xmaximum 225
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
label _("Theme") style "l_label_small"
|
||||
|
||||
viewport:
|
||||
scrollbars "vertical"
|
||||
yinitial theme_yinitial()
|
||||
mousewheel True
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
for i in theme_names():
|
||||
textbutton "[i]":
|
||||
action SetTheme(i)
|
||||
hovered PreviewTheme(i, current_scheme)
|
||||
style "l_list2"
|
||||
style "l_list2"
|
||||
|
||||
|
||||
|
||||
# Color scheme selector.
|
||||
frame:
|
||||
style "l_indent"
|
||||
bottom_margin HALF_SPACER_HEIGHT
|
||||
xmaximum 225
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
label _("Color Scheme") style "l_label_small"
|
||||
|
||||
|
||||
viewport:
|
||||
scrollbars "vertical"
|
||||
mousewheel True
|
||||
yinitial scheme_yinitial()
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
for i in scheme_names(current_theme):
|
||||
textbutton "[i]":
|
||||
textbutton "[i]":
|
||||
action SetScheme(i)
|
||||
hovered PreviewTheme(current_theme, i)
|
||||
style "l_list2"
|
||||
style "l_list2"
|
||||
|
||||
|
||||
|
||||
# Preview
|
||||
frame:
|
||||
style "l_default"
|
||||
@@ -437,19 +444,19 @@ screen choose_theme:
|
||||
yfill True
|
||||
xmargin 20
|
||||
bottom_margin 6
|
||||
|
||||
|
||||
use theme_demo
|
||||
|
||||
textbutton _("Back") action Jump("front_page") style "l_left_button"
|
||||
textbutton _("Continue") action Return(True) style "l_right_button"
|
||||
|
||||
|
||||
|
||||
label choose_theme_callable:
|
||||
|
||||
python:
|
||||
current_theme, current_scheme = pick_theme(None, None)
|
||||
implement_theme(current_theme, current_scheme)
|
||||
|
||||
implement_theme(current_theme, current_scheme)
|
||||
|
||||
call screen choose_theme
|
||||
|
||||
python hide:
|
||||
@@ -457,9 +464,7 @@ label choose_theme_callable:
|
||||
switch_theme()
|
||||
|
||||
return
|
||||
|
||||
|
||||
label choose_theme:
|
||||
call choose_theme_callable
|
||||
jump front_page
|
||||
|
||||
|
||||
|
||||
+245
-190
@@ -1,7 +1,7 @@
|
||||
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# This file contains code that manages the distribution of Ren'Py games
|
||||
# This file contains code that manages the distribution of Ren'Py games
|
||||
# and Ren'Py proper.
|
||||
#
|
||||
# In this module, all files and paths are stored in unicode. Full paths
|
||||
@@ -34,14 +34,14 @@ init python in distribute:
|
||||
import time
|
||||
|
||||
match_cache = { }
|
||||
|
||||
|
||||
def compile_match(pattern):
|
||||
"""
|
||||
Compiles a pattern for use with match.
|
||||
"""
|
||||
|
||||
|
||||
regexp = ""
|
||||
|
||||
|
||||
while pattern:
|
||||
if pattern.startswith("**"):
|
||||
regexp += r'.*'
|
||||
@@ -52,20 +52,20 @@ init python in distribute:
|
||||
elif pattern[0] == '[':
|
||||
regexp += r'['
|
||||
pattern = pattern[1:]
|
||||
|
||||
|
||||
while pattern and pattern[0] != ']':
|
||||
regexp += pattern[0]
|
||||
pattern = pattern[1:]
|
||||
|
||||
|
||||
pattern = pattern[1:]
|
||||
regexp += ']'
|
||||
|
||||
|
||||
else:
|
||||
regexp += re.escape(pattern[0])
|
||||
pattern = pattern[1:]
|
||||
|
||||
|
||||
regexp += "$"
|
||||
|
||||
|
||||
return re.compile(regexp, re.I)
|
||||
|
||||
def match(s, pattern):
|
||||
@@ -79,15 +79,15 @@ init python in distribute:
|
||||
|
||||
Things are matched case-insensitively.
|
||||
"""
|
||||
|
||||
|
||||
regexp = match_cache.get(pattern, None)
|
||||
if regexp is None:
|
||||
regexp = compile_match(pattern)
|
||||
match_cache[pattern] = regexp
|
||||
|
||||
|
||||
if regexp.match(s):
|
||||
return True
|
||||
|
||||
|
||||
if regexp.match("/" + s):
|
||||
return True
|
||||
|
||||
@@ -96,28 +96,28 @@ init python in distribute:
|
||||
class File(object):
|
||||
"""
|
||||
Represents a file that we can distribute.
|
||||
|
||||
|
||||
self.name
|
||||
The name of the file as it will be stored in the archives.
|
||||
|
||||
|
||||
self.path
|
||||
The path to the file on disk. None if it won't be stored
|
||||
on disk.
|
||||
|
||||
|
||||
self.directory
|
||||
True if this is a directory.
|
||||
|
||||
|
||||
self.executable
|
||||
True if this is an executable that should be distributed
|
||||
with the xbit set.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name, path, directory, executable):
|
||||
self.name = name
|
||||
self.path = path
|
||||
self.directory = directory
|
||||
self.executable = executable
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
if self.directory:
|
||||
extra = "dir"
|
||||
@@ -125,72 +125,72 @@ init python in distribute:
|
||||
extra = "x-bit"
|
||||
else:
|
||||
extra = ""
|
||||
|
||||
|
||||
return "<File {!r} {!r} {}>".format(self.name, self.path, extra)
|
||||
|
||||
|
||||
def copy(self):
|
||||
return File(self.name, self.path, self.directory, self.executable)
|
||||
|
||||
|
||||
|
||||
class FileList(list):
|
||||
"""
|
||||
This represents a list of files that we know about.
|
||||
"""
|
||||
|
||||
|
||||
def sort(self):
|
||||
list.sort(self, key=lambda a : a.name)
|
||||
|
||||
|
||||
def copy(self):
|
||||
"""
|
||||
Makes a deep copy of this file list.
|
||||
"""
|
||||
|
||||
|
||||
rv = FileList()
|
||||
|
||||
|
||||
for i in self:
|
||||
rv.append(i.copy())
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def filter_empty(self):
|
||||
"""
|
||||
Makes a deep copy of this file list with empty directories
|
||||
omitted.
|
||||
"""
|
||||
|
||||
|
||||
rv = FileList()
|
||||
|
||||
|
||||
needed_dirs = set()
|
||||
|
||||
|
||||
for i in reversed(self):
|
||||
|
||||
if (not i.directory) or (i.name in needed_dirs):
|
||||
|
||||
if (not i.directory) or (i.name in needed_dirs):
|
||||
rv.insert(0, i.copy())
|
||||
|
||||
|
||||
directory, _sep, _filename = i.name.rpartition("/")
|
||||
needed_dirs.add(directory)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
@staticmethod
|
||||
def merge(l):
|
||||
"""
|
||||
Merges a list of file lists into a single file list with no
|
||||
duplicate entries.
|
||||
"""
|
||||
|
||||
|
||||
rv = FileList()
|
||||
|
||||
|
||||
seen = set()
|
||||
|
||||
|
||||
for fl in l:
|
||||
for f in fl:
|
||||
if f.name in seen:
|
||||
continue
|
||||
|
||||
|
||||
rv.append(f)
|
||||
seen.add(f.name)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
def prepend_directory(self, directory):
|
||||
@@ -198,32 +198,32 @@ init python in distribute:
|
||||
Modifies this file list such that every file in it has `directory`
|
||||
prepended.
|
||||
"""
|
||||
|
||||
|
||||
for i in self:
|
||||
i.name = directory + "/" + i.name
|
||||
|
||||
|
||||
self.insert(0, File(directory, None, True, False))
|
||||
|
||||
|
||||
|
||||
|
||||
def mac_transform(self, app, documentation):
|
||||
"""
|
||||
Creates a new file list that has the mac transform applied to it.
|
||||
|
||||
|
||||
The mac transform places all files that aren't already in <app> in
|
||||
<app>/Contents/Resources/autorun. If it matches one of the documentation
|
||||
patterns, then it appears both inside and outside of the app.
|
||||
"""
|
||||
|
||||
|
||||
rv = FileList()
|
||||
|
||||
|
||||
for f in self:
|
||||
|
||||
|
||||
# Already in the app.
|
||||
if f.name == app or f.name.startswith(app + "/"):
|
||||
rv.append(f)
|
||||
continue
|
||||
|
||||
# If it's documentation, keep the file. (But also make
|
||||
# If it's documentation, keep the file. (But also make
|
||||
# a copy.)
|
||||
for pattern in documentation:
|
||||
if match(f.name, pattern):
|
||||
@@ -231,16 +231,16 @@ init python in distribute:
|
||||
|
||||
if match("/" + f.name, pattern):
|
||||
rv.append(f)
|
||||
|
||||
|
||||
# Make a copy.
|
||||
f = f.copy()
|
||||
|
||||
|
||||
f.name = app + "/Contents/Resources/autorun/" + f.name
|
||||
rv.append(f)
|
||||
|
||||
|
||||
rv.append(File(app + "/Contents/Resources/autorun", None, True, False))
|
||||
rv.sort()
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
@@ -248,28 +248,45 @@ init python in distribute:
|
||||
"""
|
||||
This manages the process of building distributions.
|
||||
"""
|
||||
|
||||
def __init__(self, project, destination=None, reporter=None, packages=None, build_update=True):
|
||||
|
||||
def __init__(self, project, destination=None, reporter=None, packages=None, build_update=True, open_directory=False, noarchive=False, packagedest=None, report_success=True):
|
||||
"""
|
||||
Distributes `project`.
|
||||
|
||||
|
||||
`destination`
|
||||
The destination in which the distribution will be placed. If None,
|
||||
uses a default location.
|
||||
|
||||
|
||||
`reporter`
|
||||
An object that's used to report status and progress to the user.
|
||||
|
||||
|
||||
`packages`
|
||||
If not None, a list of packages to distributed. If None, all
|
||||
packages are distributed.
|
||||
|
||||
|
||||
`build_update`
|
||||
Will updates be built?
|
||||
|
||||
`open_directory`
|
||||
If true, the directory containing the built files will be opened
|
||||
if the build succeeds.
|
||||
|
||||
`noarchive`
|
||||
If true, files will not be placed into archives.
|
||||
|
||||
`packagedest`
|
||||
If given, gives the full path to the single package (without any
|
||||
extensions).
|
||||
|
||||
`report_success`
|
||||
If true, we report that the build succeeded.
|
||||
"""
|
||||
|
||||
|
||||
# Safety - prevents us frome releasing a launcher that won't update.
|
||||
|
||||
if packagedest is not None:
|
||||
if packages is None or len(packages) != 1:
|
||||
raise Exception("Packagedest requires a single package be given.")
|
||||
|
||||
# Safety - prevents us from releasing a launcher that won't update.
|
||||
if store.UPDATE_SIMULATE:
|
||||
raise Exception("Cannot build distributions when UPDATE_SIMULATE is True.")
|
||||
|
||||
@@ -282,7 +299,7 @@ init python in distribute:
|
||||
# Start by scanning the project, to get the data and build
|
||||
# dictionaries.
|
||||
data = project.data
|
||||
|
||||
|
||||
project.update_dump(force=True, gui=False)
|
||||
if project.dump.get("error", False):
|
||||
raise Exception("Could not get build data from the project. Please ensure the project runs.")
|
||||
@@ -295,17 +312,22 @@ init python in distribute:
|
||||
self.base_name = build['directory_name']
|
||||
self.executable_name = build['executable_name']
|
||||
self.pretty_version = build['version']
|
||||
|
||||
|
||||
# The destination directory.
|
||||
if destination is None:
|
||||
destination = build["destination"]
|
||||
parent = os.path.dirname(project.path)
|
||||
self.destination = os.path.join(parent, self.base_name + "-dists")
|
||||
self.destination = os.path.join(parent, destination)
|
||||
else:
|
||||
self.destination = destination
|
||||
|
||||
if not packagedest:
|
||||
try:
|
||||
os.makedirs(self.destination)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.destination = destination
|
||||
|
||||
self.packagedest = packagedest
|
||||
|
||||
# Status reporter.
|
||||
self.reporter = reporter
|
||||
@@ -322,15 +344,19 @@ init python in distribute:
|
||||
self.documentation_patterns = build['documentation_patterns']
|
||||
|
||||
build_packages = [ ]
|
||||
|
||||
|
||||
for i in build['packages']:
|
||||
name = i['name']
|
||||
|
||||
if (packages is None) or (name in packages):
|
||||
|
||||
if packages is None:
|
||||
if not i['hidden']:
|
||||
build_packages.append(i)
|
||||
elif name in packages:
|
||||
build_packages.append(i)
|
||||
|
||||
|
||||
if not build_packages:
|
||||
self.reporter.info(_("Nothing to do."), pause=True)
|
||||
self.reporter.info(_("No packages are selected, so there's nothing to do."), pause=True)
|
||||
self.log.close()
|
||||
return
|
||||
|
||||
# add the game.
|
||||
@@ -338,7 +364,10 @@ init python in distribute:
|
||||
|
||||
self.scan_and_classify(project.path, build["base_patterns"])
|
||||
|
||||
self.archive_files(build["archives"])
|
||||
if noarchive:
|
||||
self.ignore_archives(build['archives'])
|
||||
else:
|
||||
self.archive_files(build["archives"])
|
||||
|
||||
# Add Ren'Py.
|
||||
self.reporter.info(_("Scanning Ren'Py files..."))
|
||||
@@ -366,43 +395,51 @@ init python in distribute:
|
||||
self.update_version = int(time.time())
|
||||
|
||||
for p in build_packages:
|
||||
|
||||
|
||||
for f in p["formats"]:
|
||||
self.make_package(
|
||||
p["name"],
|
||||
f,
|
||||
p["file_lists"],
|
||||
dlc=p["dlc"])
|
||||
|
||||
|
||||
if self.build_update and p["update"]:
|
||||
self.make_package(
|
||||
p["name"],
|
||||
"update",
|
||||
p["file_lists"],
|
||||
dlc=False)
|
||||
|
||||
|
||||
|
||||
|
||||
if self.build_update:
|
||||
self.finish_updates(build_packages)
|
||||
|
||||
# Finish up.
|
||||
self.log.close()
|
||||
|
||||
if report_success:
|
||||
self.reporter.info(_("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."))
|
||||
|
||||
if open_directory:
|
||||
store.OpenDirectory(self.destination)()
|
||||
|
||||
|
||||
|
||||
def scan_and_classify(self, directory, patterns):
|
||||
"""
|
||||
Walks through the `directory`, finds files and directories that
|
||||
match the pattern, and assds them to the appropriate file list.
|
||||
|
||||
match the pattern, and assigns them to the appropriate file list.
|
||||
|
||||
`patterns`
|
||||
A list of pattern, file_list tuples. The pattern is a string
|
||||
that is matched using match. File_list is either
|
||||
a space-separated list of file lists to add the file to,
|
||||
a space-separated list of file lists to add the file to,
|
||||
or None to ignore it.
|
||||
|
||||
Directories are matched with a trailing /, but added to the
|
||||
|
||||
Directories are matched with a trailing /, but added to the
|
||||
file list with the trailing / removed.
|
||||
"""
|
||||
|
||||
|
||||
def walk(name, path):
|
||||
is_dir = os.path.isdir(path)
|
||||
|
||||
@@ -426,9 +463,9 @@ init python in distribute:
|
||||
return
|
||||
|
||||
for fl in file_list:
|
||||
f = File(name, path, is_dir, False)
|
||||
f = File(name, path, is_dir, False)
|
||||
self.file_lists[fl].append(f)
|
||||
|
||||
|
||||
if is_dir:
|
||||
|
||||
for fn in os.listdir(path):
|
||||
@@ -436,7 +473,7 @@ init python in distribute:
|
||||
name + "/" + fn,
|
||||
os.path.join(path, fn),
|
||||
)
|
||||
|
||||
|
||||
for fn in os.listdir(directory):
|
||||
walk(fn, os.path.join(directory, fn))
|
||||
|
||||
@@ -447,45 +484,59 @@ init python in distribute:
|
||||
def add_file(self, file_list, name, path, executable=False):
|
||||
"""
|
||||
Adds a file to the file lists.
|
||||
|
||||
|
||||
`file_list`
|
||||
A space-separated list of file list names.
|
||||
|
||||
|
||||
`name`
|
||||
The name of the file to be added.
|
||||
|
||||
|
||||
`path`
|
||||
The path to that file on disk.
|
||||
"""
|
||||
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise Exception("{} does not exist.".format(path))
|
||||
|
||||
|
||||
if isinstance(file_list, basestring):
|
||||
file_list = file_list.split()
|
||||
|
||||
|
||||
f = File(name, path, False, executable)
|
||||
|
||||
|
||||
for fl in file_list:
|
||||
self.file_lists[fl].append(f)
|
||||
|
||||
def ignore_archives(self, archives):
|
||||
"""
|
||||
Ignore archiving commands by adding the files that would be in
|
||||
archives into packages instead.
|
||||
"""
|
||||
|
||||
for arcname, file_lists in archives:
|
||||
if not self.file_lists[arcname]:
|
||||
continue
|
||||
|
||||
for f in self.file_lists[arcname]:
|
||||
for fl in file_lists:
|
||||
self.file_lists[fl].append(f)
|
||||
|
||||
def archive_files(self, archives):
|
||||
"""
|
||||
Add files to archives.
|
||||
"""
|
||||
|
||||
|
||||
for arcname, file_list in archives:
|
||||
|
||||
|
||||
if not self.file_lists[arcname]:
|
||||
continue
|
||||
|
||||
|
||||
arcfn = arcname + ".rpa"
|
||||
arcpath = self.temp_filename(arcfn)
|
||||
|
||||
|
||||
af = archiver.Archive(arcpath)
|
||||
|
||||
|
||||
fll = len(self.file_lists[arcname])
|
||||
|
||||
|
||||
for i, entry in enumerate(self.file_lists[arcname]):
|
||||
|
||||
if entry.directory:
|
||||
@@ -495,11 +546,11 @@ init python in distribute:
|
||||
|
||||
name = "/".join(entry.name.split("/")[1:])
|
||||
af.add(name, entry.path)
|
||||
|
||||
|
||||
self.reporter.progress_done()
|
||||
|
||||
|
||||
af.close()
|
||||
|
||||
|
||||
self.add_file(file_list, "game/" + arcfn, arcpath)
|
||||
|
||||
def add_renpy_files(self):
|
||||
@@ -509,11 +560,11 @@ init python in distribute:
|
||||
|
||||
if not os.path.exists(os.path.join(self.project.path, "game", "script_version.rpy")):
|
||||
self.add_file("all", "game/script_version.rpy", os.path.join(config.gamedir, "script_version.rpy"))
|
||||
|
||||
|
||||
if not os.path.exists(os.path.join(self.project.path, "game", "script_version.rpyc")):
|
||||
self.add_file("all", "game/script_version.rpyc", os.path.join(config.gamedir, "script_version.rpyc"))
|
||||
|
||||
self.add_file("all", "renpy/LICENSE.txt", os.path.join(config.renpy_base, "LICENSE.txt"))
|
||||
|
||||
self.add_file("renpy", "renpy/LICENSE.txt", os.path.join(config.renpy_base, "LICENSE.txt"))
|
||||
|
||||
|
||||
def write_plist(self):
|
||||
@@ -532,14 +583,14 @@ init python in distribute:
|
||||
CFBundlePackageType="APPL",
|
||||
CFBundleShortVersionString=version,
|
||||
CFBundleVersion="1.0.{0}".format(int(time.time())),
|
||||
CFBundleDocumentTypes = [
|
||||
CFBundleDocumentTypes = [
|
||||
{
|
||||
"CFBundleTypeOSTypes" : [ "****", "fold", "disk" ],
|
||||
"CFBundleTypeRole" : "Viewer",
|
||||
},
|
||||
},
|
||||
],
|
||||
UTExportedTypeDeclarations = [
|
||||
{
|
||||
UTExportedTypeDeclarations = [
|
||||
{
|
||||
"UTTypeConformsTo" : [ "public.python-script" ],
|
||||
"UTTypeDescription" : "Ren'Py Script",
|
||||
"UTTypeIdentifier" : "org.renpy.rpy",
|
||||
@@ -547,7 +598,7 @@ init python in distribute:
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rv = self.temp_filename("Info.plist")
|
||||
plistlib.writePlist(plist, rv)
|
||||
return rv
|
||||
@@ -562,27 +613,27 @@ init python in distribute:
|
||||
windows = 'windows'
|
||||
linux = 'linux'
|
||||
mac = 'mac'
|
||||
|
||||
|
||||
self.add_file(
|
||||
linux,
|
||||
linux,
|
||||
"lib/linux-i686/" + self.executable_name,
|
||||
os.path.join(config.renpy_base, "lib/linux-i686/pythonw"),
|
||||
True)
|
||||
|
||||
self.add_file(
|
||||
linux,
|
||||
linux,
|
||||
"lib/linux-x86_64/" + self.executable_name,
|
||||
os.path.join(config.renpy_base, "lib/linux-x86_64/pythonw"),
|
||||
True)
|
||||
|
||||
|
||||
self.add_file(
|
||||
mac,
|
||||
mac,
|
||||
"lib/darwin-x86_64/" + self.executable_name,
|
||||
os.path.join(config.renpy_base, "lib/darwin-x86_64/pythonw"),
|
||||
True)
|
||||
|
||||
self.add_file(
|
||||
windows,
|
||||
windows,
|
||||
"lib/windows-i686/" + self.executable_name + ".exe",
|
||||
os.path.join(config.renpy_base, "lib/windows-i686/pythonw.exe"))
|
||||
|
||||
@@ -599,7 +650,7 @@ init python in distribute:
|
||||
contents = self.app + "/Contents"
|
||||
|
||||
plist_fn = self.write_plist()
|
||||
self.add_file(filelist, contents + "/Info.plist", plist_fn)
|
||||
self.add_file(filelist, contents + "/Info.plist", plist_fn)
|
||||
self.add_file(filelist, contents + "/MacOS/" + self.executable_name, os.path.join(config.renpy_base, "renpy.sh"))
|
||||
|
||||
custom_fn = os.path.join(self.project.path, "icon.icns")
|
||||
@@ -609,7 +660,7 @@ init python in distribute:
|
||||
icon_fn = custom_fn
|
||||
else:
|
||||
icon_fn = default_fn
|
||||
|
||||
|
||||
self.add_file(filelist, contents + "/Resources/icon.icns", icon_fn)
|
||||
|
||||
|
||||
@@ -617,80 +668,83 @@ init python in distribute:
|
||||
"""
|
||||
Adds windows-specific files.
|
||||
"""
|
||||
|
||||
|
||||
icon_fn = os.path.join(self.project.path, "icon.ico")
|
||||
old_exe_fn = os.path.join(config.renpy_base, "renpy.exe")
|
||||
|
||||
|
||||
if os.path.exists(icon_fn):
|
||||
exe_fn = self.temp_filename("renpy.exe")
|
||||
|
||||
with open(exe_fn, "wb") as f:
|
||||
with open(exe_fn, "wb") as f:
|
||||
f.write(change_icons(old_exe_fn, icon_fn))
|
||||
|
||||
else:
|
||||
exe_fn = old_exe_fn
|
||||
|
||||
self.add_file("windows", "renpy.exe", exe_fn)
|
||||
|
||||
self.add_file("windows", "renpy.exe", exe_fn)
|
||||
|
||||
def mark_executable(self):
|
||||
"""
|
||||
Marks files as executable.
|
||||
"""
|
||||
|
||||
|
||||
for l in self.file_lists.values():
|
||||
for f in l:
|
||||
for pat in self.build['xbit_patterns']:
|
||||
if match(f.name, pat):
|
||||
for pat in self.build['xbit_patterns']:
|
||||
if match(f.name, pat):
|
||||
f.executable = True
|
||||
|
||||
if match("/" + f.name, pat):
|
||||
|
||||
if match("/" + f.name, pat):
|
||||
f.executable = True
|
||||
|
||||
def rename(self):
|
||||
"""
|
||||
Rename files in all lists to match the executable names.
|
||||
"""
|
||||
|
||||
|
||||
def rename_one(fn):
|
||||
parts = fn.split('/')
|
||||
p = parts[0]
|
||||
|
||||
|
||||
if p == "renpy.exe":
|
||||
p = self.exe
|
||||
elif p == "renpy.sh":
|
||||
p = self.sh
|
||||
elif p == "renpy.py":
|
||||
p = self.py
|
||||
|
||||
|
||||
parts[0] = p
|
||||
return "/".join(parts)
|
||||
|
||||
|
||||
for l in self.file_lists.values():
|
||||
for f in l:
|
||||
f.name = rename_one(f.name)
|
||||
|
||||
def make_package(self, variant, format, file_lists, dlc=False):
|
||||
"""
|
||||
Creates a package file in the projects directory.
|
||||
Creates a package file in the projects directory.
|
||||
|
||||
`variant`
|
||||
The name of the variant to package. This is appended to the base name to become
|
||||
part of the file and directory names.
|
||||
|
||||
`format`
|
||||
The format things will be packaged in. This should be one of "zip", "tar.bz2", or
|
||||
"update".
|
||||
|
||||
The format things will be packaged in. This should be one of "zip", "tar.bz2", or
|
||||
"update".
|
||||
|
||||
`file_lists`
|
||||
A string containing a space-separated list of file_lists to include in this
|
||||
A string containing a space-separated list of file_lists to include in this
|
||||
package.
|
||||
|
||||
|
||||
`dlc`
|
||||
True if we want to build a non-update file in DLC mode.
|
||||
"""
|
||||
filename = self.base_name + "-" + variant
|
||||
path = os.path.join(self.destination, filename)
|
||||
|
||||
|
||||
if self.packagedest:
|
||||
path = self.packagedest
|
||||
|
||||
fl = FileList.merge([ self.file_lists[i] for i in file_lists ])
|
||||
fl = fl.copy()
|
||||
fl.sort()
|
||||
@@ -708,10 +762,10 @@ init python in distribute:
|
||||
update_files.append(i.name)
|
||||
else:
|
||||
update_directories.append(i.name)
|
||||
|
||||
|
||||
if i.executable:
|
||||
update_xbit.append(i.name)
|
||||
|
||||
|
||||
update = { variant : { "version" : self.update_version, "pretty_version" : self.pretty_version, "files" : update_files, "directories" : update_directories, "xbit" : update_xbit } }
|
||||
|
||||
if self.include_update and not dlc:
|
||||
@@ -726,11 +780,11 @@ init python in distribute:
|
||||
# The mac transform.
|
||||
if format == "app-zip":
|
||||
fl = fl.mac_transform(self.app, self.documentation_patterns)
|
||||
|
||||
|
||||
# If we're not an update file, prepend the directory.
|
||||
if (not dlc) and format != "update":
|
||||
if (not dlc) and format != "update" and format != "directory":
|
||||
fl.prepend_directory(filename)
|
||||
|
||||
|
||||
if format == "tar.bz2":
|
||||
path += ".tar.bz2"
|
||||
pkg = TarPackage(path, "w:bz2")
|
||||
@@ -740,10 +794,12 @@ init python in distribute:
|
||||
elif format == "zip" or format == "app-zip":
|
||||
path += ".zip"
|
||||
pkg = ZipPackage(path)
|
||||
|
||||
elif format == "directory":
|
||||
pkg = DirectoryPackage(path)
|
||||
|
||||
for i, f in enumerate(fl):
|
||||
self.reporter.progress(_("Writing the [variant] [format] package."), i, len(fl), variant=variant, format=format)
|
||||
|
||||
|
||||
if f.directory:
|
||||
pkg.add_directory(f.name, f.path)
|
||||
else:
|
||||
@@ -754,31 +810,31 @@ init python in distribute:
|
||||
|
||||
if format == "update":
|
||||
# Build the zsync file.
|
||||
|
||||
|
||||
self.reporter.info(_("Making the [variant] update zsync file."), variant=variant)
|
||||
|
||||
cmd = [
|
||||
updater.zsync_path("zsyncmake"),
|
||||
|
||||
cmd = [
|
||||
updater.zsync_path("zsyncmake"),
|
||||
"-z",
|
||||
# -u url to gzipped data - not a local filename!
|
||||
"-u", filename + ".update.gz",
|
||||
"-u", filename + ".update.gz",
|
||||
"-o", os.path.join(self.destination, filename + ".zsync"),
|
||||
os.path.abspath(path),
|
||||
os.path.abspath(path),
|
||||
]
|
||||
|
||||
subprocess.check_call([ renpy.fsencode(i) for i in cmd ])
|
||||
|
||||
# Build the sums file. This is a file with an adler32 hash of each 64k block
|
||||
# of the zsync file. It's used to help us determine how much of the file is
|
||||
# of the zsync file. It's used to help us determine how much of the file is
|
||||
# downloaded.
|
||||
with open(path, "rb") as src:
|
||||
with open(renpy.fsencode(os.path.join(self.destination, filename + ".sums")), "wb") as sums:
|
||||
while True:
|
||||
data = src.read(65536)
|
||||
|
||||
|
||||
if not data:
|
||||
break
|
||||
|
||||
|
||||
sums.write(struct.pack("I", zlib.adler32(data) & 0xffffffff))
|
||||
|
||||
if self.include_update and not self.build_update and not dlc:
|
||||
@@ -794,28 +850,28 @@ init python in distribute:
|
||||
return
|
||||
|
||||
index = { }
|
||||
|
||||
|
||||
def add_variant(variant):
|
||||
fn = renpy.fsencode(os.path.join(self.destination, self.base_name + "-" + variant + ".update"))
|
||||
|
||||
with open(fn, "rb") as f:
|
||||
digest = hashlib.sha256(f.read()).hexdigest()
|
||||
|
||||
index[variant] = {
|
||||
"version" : self.update_version,
|
||||
"pretty_version" : self.pretty_version,
|
||||
"digest" : digest,
|
||||
"zsync_url" : self.base_name + "-" + variant + ".zsync",
|
||||
"sums_url" : self.base_name + "-" + variant + ".sums",
|
||||
|
||||
index[variant] = {
|
||||
"version" : self.update_version,
|
||||
"pretty_version" : self.pretty_version,
|
||||
"digest" : digest,
|
||||
"zsync_url" : self.base_name + "-" + variant + ".zsync",
|
||||
"sums_url" : self.base_name + "-" + variant + ".sums",
|
||||
"json_url" : self.base_name + "-" + variant + ".update.json",
|
||||
}
|
||||
|
||||
|
||||
os.unlink(fn)
|
||||
|
||||
for p in packages:
|
||||
if p["update"]:
|
||||
add_variant(p["name"])
|
||||
|
||||
|
||||
fn = renpy.fsencode(os.path.join(self.destination, "updates.json"))
|
||||
with open(fn, "wb") as f:
|
||||
json.dump(index, f)
|
||||
@@ -835,24 +891,24 @@ init python in distribute:
|
||||
"""
|
||||
Displays progress using the gui.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
# The time at which we should next report progress.
|
||||
self.next_progress = 0
|
||||
|
||||
def info(self, what, pause=False, **kwargs):
|
||||
if pause:
|
||||
interface.information(what, **kwargs)
|
||||
interface.info(what, **kwargs)
|
||||
else:
|
||||
interface.processing(what, **kwargs)
|
||||
|
||||
def progress(self, what, complete, total, **kwargs):
|
||||
|
||||
|
||||
if (complete > 0) and (time.time() < self.next_progress):
|
||||
return
|
||||
|
||||
|
||||
interface.processing(what, _("Processed {b}[complete]{/b} of {b}[total]{/b} files."), complete=complete, total=total, **kwargs)
|
||||
|
||||
|
||||
self.next_progress = time.time() + .05
|
||||
|
||||
def progress_done(self):
|
||||
@@ -863,21 +919,21 @@ init python in distribute:
|
||||
"""
|
||||
Displays progress on the command line.
|
||||
"""
|
||||
|
||||
|
||||
def info(self, what, pause=False, **kwargs):
|
||||
what = what.replace("[", "{")
|
||||
what = what.replace("]", "}")
|
||||
what = what.format(**kwargs)
|
||||
print what
|
||||
|
||||
|
||||
def progress(self, what, done, total, **kwargs):
|
||||
what = what.replace("[", "{")
|
||||
what = what.replace("]", "}")
|
||||
what = what.format(**kwargs)
|
||||
|
||||
|
||||
sys.stdout.write("\r{} - {} of {}".format(what, done + 1, total))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def progress_done(self):
|
||||
sys.stdout.write("\n")
|
||||
|
||||
@@ -885,39 +941,38 @@ init python in distribute:
|
||||
def distribute_command():
|
||||
ap = renpy.arguments.ArgumentParser()
|
||||
ap.add_argument("--destination", "--dest", default=None, action="store", help="The directory where the packaged files should be placed.")
|
||||
ap.add_argument("--packagedest", default=None, action="store", help="If given, gives the full path to the package file, without extensions." )
|
||||
ap.add_argument("--no-update", default=True, action="store_false", dest="build_update", help="Prevents updates from being built.")
|
||||
ap.add_argument("--package", action="append", help="If given, a package to build. Defaults to building all packages.")
|
||||
ap.add_argument("--no-archive", action="store_true", help="If given, files will not be added to archives.")
|
||||
ap.add_argument("project", help="The path to the project directory.")
|
||||
ap.add_argument("--package", action="append", help="If given, a package to build. Defaults to building all packages.")
|
||||
|
||||
args = ap.parse_args()
|
||||
|
||||
p = project.Project(args.project)
|
||||
|
||||
|
||||
if args.package:
|
||||
packages = args.package
|
||||
else:
|
||||
packages = None
|
||||
|
||||
Distributor(p, destination=args.destination, reporter=TextReporter(), packages=packages, build_update=args.build_update)
|
||||
|
||||
Distributor(p, destination=args.destination, reporter=TextReporter(), packages=packages, build_update=args.build_update, noarchive=args.no_archive, packagedest=args.packagedest)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
renpy.arguments.register_command("distribute", distribute_command)
|
||||
|
||||
|
||||
label distribute:
|
||||
|
||||
python hide:
|
||||
|
||||
data = project.current.data
|
||||
d = distribute.Distributor(project.current, reporter=distribute.GuiReporter(), packages=data['packages'], build_update=data['build_update'])
|
||||
OpenDirectory(d.destination)()
|
||||
|
||||
interface.info(_("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."))
|
||||
d = distribute.Distributor(project.current,
|
||||
reporter=distribute.GuiReporter(),
|
||||
packages=data['packages'],
|
||||
build_update=data['build_update'],
|
||||
open_directory=True,
|
||||
)
|
||||
|
||||
|
||||
jump front_page
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,66 +5,66 @@ init python:
|
||||
class PackageToggle(Action):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return self.name in project.current.data['packages']
|
||||
|
||||
return self.name in project.current.data['packages']
|
||||
|
||||
def __call__(self):
|
||||
packages = project.current.data['packages']
|
||||
|
||||
|
||||
if self.name in packages:
|
||||
packages.remove(self.name)
|
||||
else:
|
||||
packages.append(self.name)
|
||||
|
||||
|
||||
project.current.save_data()
|
||||
renpy.restart_interaction()
|
||||
|
||||
class DataToggle(Action):
|
||||
def __init__(self, field):
|
||||
self.field = field
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return project.current.data[self.field]
|
||||
|
||||
|
||||
def __call__(self):
|
||||
project.current.data[self.field] = not project.current.data[self.field]
|
||||
|
||||
|
||||
project.current.save_data()
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
DEFAULT_BUILD_INFO = """
|
||||
|
||||
## This section contains information about how to build your project into
|
||||
|
||||
## This section contains information about how to build your project into
|
||||
## distribution files.
|
||||
init python:
|
||||
|
||||
|
||||
## The name that's used for directories and archive files. For example, if
|
||||
## this is 'mygame-1.0', the windows distribution will be in the
|
||||
## directory 'mygame-1.0-win', in the 'mygame-1.0-win.zip' file.
|
||||
build.directory_name = "PROJECTNAME-1.0"
|
||||
|
||||
|
||||
## The name that's uses for executables - the program that users will run
|
||||
## to start the game. For example, if this is 'mygame', then on Windows,
|
||||
## users can click 'mygame.exe' to start the game.
|
||||
build.executable_name = "PROJECTNAME"
|
||||
|
||||
|
||||
## If True, Ren'Py will include update information into packages. This
|
||||
## allows the updater to run.
|
||||
build.include_update = False
|
||||
|
||||
|
||||
## File patterns:
|
||||
##
|
||||
##
|
||||
## The following functions take file patterns. File patterns are case-
|
||||
## insensitive, and matched against the path relative to the base
|
||||
## directory, with and without a leading /. If multiple patterns match,
|
||||
## the first is used.
|
||||
##
|
||||
##
|
||||
##
|
||||
## In a pattern:
|
||||
##
|
||||
## /
|
||||
## /
|
||||
## Is the directory separator.
|
||||
## *
|
||||
## Matches all characters, except the directory separator.
|
||||
@@ -87,9 +87,9 @@ init python:
|
||||
build.classify('**/.**', None)
|
||||
build.classify('**/#**', None)
|
||||
build.classify('**/thumbs.db', None)
|
||||
|
||||
|
||||
## To archive files, classify them as 'archive'.
|
||||
|
||||
|
||||
# build.classify('game/**.png', 'archive')
|
||||
# build.classify('game/**.jpg', 'archive')
|
||||
|
||||
@@ -100,7 +100,7 @@ init python:
|
||||
build.documentation('*.txt')
|
||||
"""
|
||||
|
||||
# A screen that displays a file or directory name, and
|
||||
# A screen that displays a file or directory name, and
|
||||
# lets the user change it,
|
||||
#
|
||||
# title
|
||||
@@ -108,17 +108,17 @@ init python:
|
||||
# value
|
||||
# The value of the field.
|
||||
screen distribute_name:
|
||||
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
|
||||
text title
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
text "[value!q]"
|
||||
@@ -127,27 +127,27 @@ screen distribute_name:
|
||||
|
||||
|
||||
screen build_distributions:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Build Distributions: [project.current.name!q]")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
hbox:
|
||||
|
||||
|
||||
# Left side.
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONEHALF
|
||||
xfill True
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
use distribute_name(
|
||||
@@ -159,23 +159,23 @@ screen build_distributions:
|
||||
value=project.current.dump["build"]["executable_name"])
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Actions:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
textbutton _("Edit options.rpy") action editor.Edit("game/options.rpy", check=True)
|
||||
textbutton _("Refresh") action Jump("build_distributions")
|
||||
|
||||
|
||||
|
||||
|
||||
# Right side.
|
||||
frame:
|
||||
style "l_indent"
|
||||
@@ -185,23 +185,22 @@ screen build_distributions:
|
||||
has vbox
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Build Packages:")
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
$ packages = project.current.dump["build"]["packages"]
|
||||
|
||||
|
||||
for pkg in packages:
|
||||
|
||||
$ description = pkg["description"]
|
||||
|
||||
textbutton "[description!q]" action PackageToggle(pkg["name"]) style "l_checkbox"
|
||||
|
||||
if not pkg["hidden"]:
|
||||
$ description = pkg["description"]
|
||||
textbutton "[description!q]" action PackageToggle(pkg["name"]) style "l_checkbox"
|
||||
|
||||
add SPACER
|
||||
|
||||
if project.current.dump["build"]["include_update"]:
|
||||
@@ -214,34 +213,30 @@ screen build_distributions:
|
||||
label build_update_dump:
|
||||
python:
|
||||
project.current.update_dump(True)
|
||||
|
||||
|
||||
if project.current.dump.get("error", False):
|
||||
interface.error(_("Errors were detected when running the project. Please ensure the project runs without errors before building distributions."))
|
||||
|
||||
|
||||
return
|
||||
|
||||
label build_distributions:
|
||||
|
||||
|
||||
call build_update_dump
|
||||
|
||||
|
||||
if not project.current.dump["build"]["directory_name"]:
|
||||
jump build_missing
|
||||
|
||||
call screen build_distributions
|
||||
|
||||
label build_missing:
|
||||
|
||||
|
||||
python hide:
|
||||
|
||||
|
||||
interface.yesno(_("Your project does not contain build information. Would you like to add build information to the end of options.rpy?"), yes=Return(True), no=Jump("front_page"))
|
||||
|
||||
build_info = DEFAULT_BUILD_INFO.replace("PROJECTNAME", project.current.name)
|
||||
|
||||
|
||||
with open(os.path.join(project.current.path, "game", "options.rpy"), "a") as f:
|
||||
f.write(build_info)
|
||||
|
||||
jump build_distributions
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
init python:
|
||||
|
||||
import urllib2
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
class Downloader(object):
|
||||
|
||||
def __init__(self, url, dest):
|
||||
"""
|
||||
Downloads `url` to `dest`, providing progress reports
|
||||
as necessary.
|
||||
"""
|
||||
|
||||
self.url = url
|
||||
|
||||
# The destination file, and the destination temp file.
|
||||
self.dest = dest
|
||||
self.tmp = dest + ".tmp"
|
||||
|
||||
# Open the tmpfile.
|
||||
self.safe_unlink(self.tmp)
|
||||
self.tmpfile = open(self.tmp, "wb")
|
||||
|
||||
# Set by the thread to indicate progress (ranges from 0.0 to 1.0).
|
||||
self.progress = 0.0
|
||||
|
||||
# This is set to true by cancel() to indicate the download should be cancelled.
|
||||
self.cancelled = False
|
||||
|
||||
# Set on succes or failure.
|
||||
self.success = False
|
||||
self.failure = None
|
||||
|
||||
try:
|
||||
# Open the URL.
|
||||
self.urlfile = urllib2.urlopen(url)
|
||||
|
||||
t = threading.Thread(target=self.thread)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
except Exception as e:
|
||||
self.failure = str(e)
|
||||
|
||||
def thread(self):
|
||||
|
||||
try:
|
||||
count = 0
|
||||
|
||||
if "content-length" in self.urlfile.headers:
|
||||
length = int(self.urlfile.headers["content-length"])
|
||||
else:
|
||||
length = 0
|
||||
|
||||
while not self.cancelled:
|
||||
|
||||
data = self.urlfile.read(65536)
|
||||
|
||||
if not data:
|
||||
break
|
||||
|
||||
count += len(data)
|
||||
self.tmpfile.write(data)
|
||||
|
||||
if length > 0:
|
||||
self.progress = 1.0 * count / length
|
||||
|
||||
self.tmpfile.close()
|
||||
|
||||
if self.cancelled:
|
||||
return
|
||||
|
||||
if length and count != length:
|
||||
self.failure = "Download length does not match content length."
|
||||
return
|
||||
|
||||
self.safe_unlink(self.dest)
|
||||
os.rename(self.tmp, self.dest)
|
||||
|
||||
self.success = True
|
||||
|
||||
except Exception as e:
|
||||
self.failure = str(e)
|
||||
|
||||
|
||||
def safe_unlink(self, fn):
|
||||
if os.path.exists(fn):
|
||||
os.unlink(fn)
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Cancels the download.
|
||||
"""
|
||||
|
||||
self.cancelled = True
|
||||
|
||||
def check(self):
|
||||
"""
|
||||
Returns True if the download is finished, False if it was cancelled,
|
||||
None if it's ongoing, and raises an Exception if the download has failed.
|
||||
"""
|
||||
|
||||
if self.success:
|
||||
return True
|
||||
if self.cancelled:
|
||||
return False
|
||||
if self.failure:
|
||||
raise Exception("Downloading {} to {} failed: {}".format(self.url, self.dest, self.failure))
|
||||
|
||||
return None
|
||||
|
||||
class DownloaderValue(BarValue):
|
||||
"""
|
||||
A BarValue that reports the progress of a background download.
|
||||
"""
|
||||
|
||||
def __init__(self, d):
|
||||
self.downloader = d
|
||||
|
||||
def get_adjustment(self):
|
||||
self.adjustment = ui.adjustment(value=0.0, range=1.0, adjustable=False)
|
||||
return self.adjustment
|
||||
|
||||
def periodic(self, st):
|
||||
self.adjustment.change(self.downloader.progress)
|
||||
return .25
|
||||
|
||||
+139
-96
@@ -13,29 +13,29 @@ init python in editor:
|
||||
import store.updater as updater
|
||||
import store.interface as interface
|
||||
import store
|
||||
|
||||
|
||||
import glob
|
||||
import re
|
||||
import traceback
|
||||
import os
|
||||
import os.path
|
||||
|
||||
|
||||
# Should we set up the editor?
|
||||
set_editor = "RENPY_EDIT_PY" not in os.environ
|
||||
|
||||
# A map from editor name to EditorInfo object.
|
||||
editors = { }
|
||||
|
||||
|
||||
class EditorInfo(object):
|
||||
def __init__(self, filename):
|
||||
# The path to the editor info file.
|
||||
self.filename = filename
|
||||
|
||||
|
||||
# The name of the editor.
|
||||
self.name = os.path.basename(filename)[:-len(".edit.py")]
|
||||
|
||||
|
||||
# The time the editor file was last modified. We use this
|
||||
# to decide if we should update the editors mat when we
|
||||
# to decide if we should update the editors mat when we
|
||||
# have multiple versions of an editor in contention.
|
||||
self.mtime = os.path.getmtime(filename)
|
||||
|
||||
@@ -46,13 +46,13 @@ init python in editor:
|
||||
"""
|
||||
|
||||
ei = EditorInfo(filename)
|
||||
|
||||
|
||||
if ei.name in editors:
|
||||
if editors[ei.name].mtime >= ei.mtime:
|
||||
return
|
||||
|
||||
|
||||
editors[ei.name] = ei
|
||||
|
||||
|
||||
def scan_all():
|
||||
"""
|
||||
Finds all *.edit.py files, and uses them to populate the list
|
||||
@@ -60,11 +60,11 @@ init python in editor:
|
||||
"""
|
||||
|
||||
editors.clear()
|
||||
|
||||
|
||||
for d in [ config.renpy_base, persistent.projects_directory ]:
|
||||
if d is None:
|
||||
continue
|
||||
|
||||
|
||||
for filename in glob.glob(d + "/*/*.edit.py"):
|
||||
scan_editor(filename)
|
||||
|
||||
@@ -78,42 +78,42 @@ init python in editor:
|
||||
|
||||
class FancyEditorInfo(object):
|
||||
"""
|
||||
Represents an editor in the selection screen. A FEI knows if the
|
||||
Represents an editor in the selection screen. A FEI knows if the
|
||||
editor is installed or not.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, priority, name, description=None, dlc=None, dldescription=None, error_message=None):
|
||||
# The priority of the editor. Lower priorities will come later
|
||||
# in the list.
|
||||
self.priority = priority
|
||||
|
||||
|
||||
# The name of the editor.
|
||||
self.name = name
|
||||
|
||||
|
||||
# Is the editor installed?
|
||||
self.installed = name in editors
|
||||
|
||||
|
||||
# The dlc needed to install the editor.
|
||||
self.dlc = dlc
|
||||
|
||||
|
||||
# A description of the editor.
|
||||
self.description = description
|
||||
|
||||
|
||||
# A description of the download.
|
||||
self.dldescription = dldescription
|
||||
|
||||
|
||||
# An error message to display if the editor failed to start.
|
||||
self.error_message = error_message
|
||||
|
||||
|
||||
def fancy_scan_editors():
|
||||
"""
|
||||
Creates the list of FancyEditorInfo objects.
|
||||
"""
|
||||
|
||||
|
||||
global fancy_editors
|
||||
|
||||
|
||||
scan_all()
|
||||
|
||||
|
||||
fei = fancy_editors = [ ]
|
||||
|
||||
# Editra.
|
||||
@@ -134,36 +134,36 @@ init python in editor:
|
||||
dlc = "editra-linux"
|
||||
installed = os.path.exists(os.path.join(config.basedir, "editra/Editra"))
|
||||
description = EDL
|
||||
error_message = _("The may have occured because wxPython is not installed on this system.")
|
||||
error_message = _("This may have occured because wxPython is not installed on this system.")
|
||||
|
||||
e = FancyEditorInfo(
|
||||
1,
|
||||
"Editra",
|
||||
"Editra",
|
||||
description,
|
||||
dlc,
|
||||
_("Up to 22 MB download required."),
|
||||
error_message)
|
||||
|
||||
|
||||
e.installed = e.installed or installed
|
||||
|
||||
|
||||
fei.append(e)
|
||||
|
||||
|
||||
# jEdit
|
||||
fei.append(FancyEditorInfo(
|
||||
2,
|
||||
"jEdit",
|
||||
"A mature editor that requires Java.",
|
||||
_("A mature editor that requires Java."),
|
||||
"jedit",
|
||||
_("1.8 MB download required."),
|
||||
_("This may have occured because Java is not installed on this system."),
|
||||
))
|
||||
|
||||
|
||||
fei.append(FancyEditorInfo(
|
||||
3,
|
||||
"System Editor",
|
||||
"Invokes the editor your operating system has associated with .rpy files.",
|
||||
_("Invokes the editor your operating system has associated with .rpy files."),
|
||||
None))
|
||||
|
||||
|
||||
for k in editors:
|
||||
if k in [ "Editra", "jEdit", "System Editor", "None" ]:
|
||||
continue
|
||||
@@ -173,13 +173,13 @@ init python in editor:
|
||||
k,
|
||||
None,
|
||||
None))
|
||||
|
||||
|
||||
fei.append(FancyEditorInfo(
|
||||
5,
|
||||
"None",
|
||||
"Prevents Ren'Py from opening a text editor.",
|
||||
_("Prevents Ren'Py from opening a text editor."),
|
||||
None))
|
||||
|
||||
|
||||
fei.sort(key=lambda e : (e.priority, e.name.lower()))
|
||||
|
||||
# If we're in a linux distro or something, assume all editors work.
|
||||
@@ -190,40 +190,40 @@ init python in editor:
|
||||
def fancy_activate_editor(default=False):
|
||||
"""
|
||||
Activates the editor in persistent.editor, if it's installed.
|
||||
|
||||
|
||||
`default`
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
global error_message
|
||||
|
||||
|
||||
fancy_scan_editors()
|
||||
|
||||
|
||||
if default and not set_editor:
|
||||
renpy.editor.init()
|
||||
return
|
||||
|
||||
|
||||
for i in fancy_editors:
|
||||
|
||||
|
||||
if i.name == persistent.editor:
|
||||
if i.installed and i.name in editors:
|
||||
ei = editors[i.name]
|
||||
os.environ["RENPY_EDIT_PY"] = renpy.fsencode(os.path.abspath(ei.filename))
|
||||
error_message = i.error_message
|
||||
break
|
||||
|
||||
|
||||
else:
|
||||
persistent.editor = None
|
||||
os.environ.pop("RENPY_EDIT_PY", None)
|
||||
|
||||
|
||||
renpy.editor.init()
|
||||
|
||||
def fancy_select_editor(name):
|
||||
"""
|
||||
Selects the editor with the given name, installing it if it
|
||||
doesn't already exist.
|
||||
doesn't already exist.
|
||||
"""
|
||||
|
||||
|
||||
for fe in fancy_editors:
|
||||
if fe.name == name:
|
||||
break
|
||||
@@ -231,47 +231,47 @@ init python in editor:
|
||||
return
|
||||
|
||||
if not fe.installed:
|
||||
|
||||
|
||||
# We don't check the status of this because fancy_activate_editor
|
||||
# will fail if the editor is not installed.
|
||||
store.add_dlc(fe.dlc)
|
||||
|
||||
persistent.editor = fe.name
|
||||
fancy_activate_editor()
|
||||
|
||||
|
||||
return persistent.editor is not None
|
||||
|
||||
# Call fancy_activate_editor on startup.
|
||||
fancy_activate_editor(True)
|
||||
|
||||
|
||||
class SelectEditor(Action):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return persistent.editor == self.name
|
||||
|
||||
|
||||
def __call__(self):
|
||||
return fancy_select_editor(self.name)
|
||||
|
||||
|
||||
def check_editor():
|
||||
"""
|
||||
Checks to see if an editor is set. If one isn't asks the user to
|
||||
select one.
|
||||
|
||||
Returns True if the editor is set and editing can proceed, and
|
||||
Checks to see if an editor is set. If one isn't asks the user to
|
||||
select one.
|
||||
|
||||
Returns True if the editor is set and editing can proceed, and
|
||||
False otherwise.
|
||||
"""
|
||||
|
||||
|
||||
if not set_editor:
|
||||
return True
|
||||
|
||||
|
||||
if persistent.editor:
|
||||
return True
|
||||
|
||||
|
||||
return renpy.invoke_in_new_context(renpy.call_screen, "editor")
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Editing actions.
|
||||
|
||||
@@ -280,42 +280,42 @@ init python in editor:
|
||||
def __init__(self, filename, line=None, check=False):
|
||||
"""
|
||||
An action that opens the given line of the given file in a
|
||||
text editor.
|
||||
|
||||
text editor.
|
||||
|
||||
`filename`
|
||||
The filename to open.
|
||||
|
||||
|
||||
`line`
|
||||
The line in the file to jump to.
|
||||
|
||||
|
||||
`check`
|
||||
If true, we will check to see if the file exists, and gray
|
||||
out the box if it does not.
|
||||
"""
|
||||
|
||||
|
||||
self.filename = filename
|
||||
self.line = line
|
||||
self.check = check
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
if not self.check:
|
||||
return True
|
||||
|
||||
|
||||
fn = project.current.unelide_filename(self.filename)
|
||||
return os.path.exists(fn)
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
|
||||
if not check_editor():
|
||||
return
|
||||
|
||||
|
||||
fn = project.current.unelide_filename(self.filename)
|
||||
|
||||
|
||||
try:
|
||||
|
||||
|
||||
e = renpy.editor.editor
|
||||
|
||||
e.begin()
|
||||
@@ -325,23 +325,68 @@ init python in editor:
|
||||
except Exception, e:
|
||||
exception = traceback.format_exception_only(type(e), e)[-1][:-1]
|
||||
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
|
||||
|
||||
|
||||
|
||||
class EditAbsolute(Action):
|
||||
def __init__(self, filename, line=None, check=False):
|
||||
"""
|
||||
An action that lets us edit an absolutely-specified filename.
|
||||
|
||||
`filename`
|
||||
The filename to open.
|
||||
|
||||
`line`
|
||||
The line in the file to jump to.
|
||||
|
||||
`check`
|
||||
If true, we will check to see if the file exists, and gray
|
||||
out the box if it does not.
|
||||
"""
|
||||
|
||||
self.filename = filename
|
||||
self.line = line
|
||||
self.check = check
|
||||
|
||||
def get_sensitive(self):
|
||||
if not self.check:
|
||||
return True
|
||||
|
||||
return os.path.exists(self.filename)
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
if not check_editor():
|
||||
return
|
||||
|
||||
try:
|
||||
|
||||
e = renpy.editor.editor
|
||||
|
||||
e.begin()
|
||||
e.open(self.filename, line=self.line)
|
||||
e.end()
|
||||
|
||||
except Exception, e:
|
||||
exception = traceback.format_exception_only(type(e), e)[-1][:-1]
|
||||
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
|
||||
|
||||
|
||||
class EditAll(Action):
|
||||
"""
|
||||
Opens all scripts that are part of the current project in a web browser.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not check_editor():
|
||||
return
|
||||
|
||||
scripts = project.current.script_files()
|
||||
scripts = project.current.script_files()
|
||||
scripts = [ i for i in scripts if not i.startswith("game/tl/") ]
|
||||
scripts.sort(key=lambda fn : fn.lower())
|
||||
|
||||
@@ -349,12 +394,12 @@ init python in editor:
|
||||
if fn in scripts:
|
||||
scripts.remove(fn)
|
||||
scripts.insert(0, fn)
|
||||
|
||||
|
||||
try:
|
||||
|
||||
e = renpy.editor.editor
|
||||
e.begin()
|
||||
|
||||
|
||||
for fn in scripts:
|
||||
fn = project.current.unelide_filename(fn)
|
||||
e.open(fn)
|
||||
@@ -366,56 +411,54 @@ init python in editor:
|
||||
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
|
||||
|
||||
screen editor:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Select Editor")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
hbox:
|
||||
frame:
|
||||
style "l_indent"
|
||||
xfill True
|
||||
|
||||
|
||||
viewport:
|
||||
scrollbars "vertical"
|
||||
mousewheel True
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
text _("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.") style "l_small_text"
|
||||
|
||||
for fe in editor.fancy_editors:
|
||||
|
||||
|
||||
add SPACER
|
||||
|
||||
|
||||
textbutton fe.name action editor.SelectEditor(fe.name)
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
has vbox
|
||||
|
||||
|
||||
if fe.description:
|
||||
text fe.description style "l_small_text"
|
||||
|
||||
|
||||
if not fe.installed:
|
||||
add HALF_SPACER
|
||||
text fe.dldescription style "l_small_text"
|
||||
|
||||
|
||||
|
||||
textbutton _("Cancel") action Return(False) style "l_left_button"
|
||||
|
||||
label editor_preference:
|
||||
call screen editor
|
||||
jump preferences
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
define PROJECT_ADJUSTMENT = ui.adjustment()
|
||||
|
||||
|
||||
init python:
|
||||
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
@@ -13,113 +13,140 @@ init python:
|
||||
Opens `directory` in a file browser. `directory` is relative to
|
||||
the project root.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, directory, absolute=False):
|
||||
if absolute:
|
||||
self.directory = directory
|
||||
else:
|
||||
self.directory = os.path.join(project.current.path, directory)
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return os.path.exists(self.directory)
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
directory = renpy.fsencode(self.directory)
|
||||
|
||||
|
||||
if renpy.windows:
|
||||
os.startfile(directory)
|
||||
elif renpy.macintosh:
|
||||
subprocess.Popen([ "open", directory ])
|
||||
else:
|
||||
subprocess.Popen([ "xdg-open", directory ])
|
||||
|
||||
|
||||
# Used for testing.
|
||||
def Relaunch():
|
||||
renpy.quit(relaunch=True)
|
||||
|
||||
|
||||
screen front_page:
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
has hbox
|
||||
|
||||
|
||||
# Projects list section - on left.
|
||||
|
||||
|
||||
frame:
|
||||
style "l_projects"
|
||||
xmaximum 300
|
||||
right_margin 2
|
||||
|
||||
|
||||
top_padding 20
|
||||
bottom_padding 26
|
||||
|
||||
|
||||
side "t c b":
|
||||
|
||||
window style "l_label":
|
||||
text "PROJECTS:" style "l_label_text" size 36 yoffset 10
|
||||
|
||||
|
||||
has hbox:
|
||||
xfill True
|
||||
|
||||
text "PROJECTS:" style "l_label_text" size 36 yoffset 10
|
||||
|
||||
textbutton _("refresh"):
|
||||
xalign 1.0
|
||||
yalign 1.0
|
||||
yoffset 5
|
||||
style "l_small_button"
|
||||
action project.Rescan()
|
||||
right_margin HALF_INDENT
|
||||
|
||||
side "c r":
|
||||
|
||||
|
||||
viewport:
|
||||
yadjustment PROJECT_ADJUSTMENT
|
||||
mousewheel True
|
||||
use front_page_project_list
|
||||
|
||||
|
||||
vbar:
|
||||
style "l_vscrollbar"
|
||||
adjustment PROJECT_ADJUSTMENT
|
||||
|
||||
|
||||
vbox:
|
||||
add HALF_SPACER
|
||||
add SEPARATOR
|
||||
add HALF_SPACER
|
||||
|
||||
textbutton _("+ Create New Project"):
|
||||
left_margin (HALF_INDENT)
|
||||
action Jump("new_project")
|
||||
|
||||
|
||||
|
||||
hbox:
|
||||
xfill True
|
||||
|
||||
textbutton _("+ Create New Project"):
|
||||
left_margin (HALF_INDENT)
|
||||
action Jump("new_project")
|
||||
|
||||
|
||||
|
||||
# Project section - on right.
|
||||
|
||||
if project.current is not None:
|
||||
use front_page_project
|
||||
|
||||
|
||||
if project.current is not None:
|
||||
textbutton _("Launch Project") action project.Launch() style "l_right_button"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# This is used by front_page to display the list of known projects on the screen.
|
||||
screen front_page_project_list:
|
||||
|
||||
|
||||
$ projects = project.manager.projects
|
||||
|
||||
$ templates = project.manager.templates
|
||||
|
||||
vbox:
|
||||
|
||||
|
||||
if templates and persistent.show_templates:
|
||||
|
||||
for p in templates:
|
||||
|
||||
textbutton _("[p.name!q] (template)"):
|
||||
action project.Select(p)
|
||||
style "l_list"
|
||||
|
||||
null height 12
|
||||
|
||||
if projects:
|
||||
|
||||
|
||||
for p in projects:
|
||||
|
||||
textbutton "[p.name!q]":
|
||||
action project.Select(p)
|
||||
style "l_list"
|
||||
|
||||
|
||||
null height 12
|
||||
|
||||
|
||||
textbutton _("Tutorial") action project.Select("tutorial") style "l_list"
|
||||
textbutton _("The Question") action project.Select("the_question") style "l_list"
|
||||
|
||||
|
||||
# This is used for the right side of the screen, which is where the project-specific
|
||||
|
||||
# This is used for the right side of the screen, which is where the project-specific
|
||||
# buttons are.
|
||||
screen front_page_project:
|
||||
|
||||
|
||||
$ p = project.current
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
frame style "l_label":
|
||||
@@ -130,10 +157,10 @@ screen front_page_project:
|
||||
grid 2 1:
|
||||
xfill True
|
||||
spacing HALF_INDENT
|
||||
|
||||
|
||||
vbox:
|
||||
|
||||
label _("Open Directory") style "l_label_small"
|
||||
|
||||
label _("Open Directory") style "l_label_small"
|
||||
|
||||
frame style "l_indent":
|
||||
has vbox
|
||||
@@ -142,30 +169,30 @@ screen front_page_project:
|
||||
textbutton _("base") action OpenDirectory(".")
|
||||
# textbutton _("images") action OpenDirectory("game/images") style "l_list"
|
||||
# textbutton _("save") action None style "l_list"
|
||||
|
||||
|
||||
vbox:
|
||||
|
||||
|
||||
label _("Edit File") style "l_label_small"
|
||||
|
||||
frame style "l_indent":
|
||||
has vbox
|
||||
|
||||
|
||||
textbutton "script.rpy" action editor.Edit("game/script.rpy", check=True)
|
||||
textbutton "options.rpy" action editor.Edit("game/options.rpy", check=True)
|
||||
textbutton "screens.rpy" action editor.Edit("game/screens.rpy", check=True)
|
||||
textbutton _("All script files") action editor.EditAll()
|
||||
|
||||
|
||||
add SPACER
|
||||
add SEPARATOR
|
||||
add SPACER
|
||||
|
||||
|
||||
frame style "l_indent":
|
||||
has vbox
|
||||
|
||||
|
||||
textbutton _("Navigate Script") text_size 30 action Jump("navigation")
|
||||
|
||||
|
||||
add SPACER
|
||||
|
||||
|
||||
grid 2 1:
|
||||
xfill True
|
||||
spacing HALF_INDENT
|
||||
@@ -176,7 +203,7 @@ screen front_page_project:
|
||||
textbutton _("Check Script (Lint)") action Jump("lint")
|
||||
textbutton _("Change Theme") action Jump("choose_theme")
|
||||
textbutton _("Delete Persistent") action Jump("rmpersistent")
|
||||
|
||||
|
||||
# textbutton "Relaunch" action Relaunch
|
||||
|
||||
frame style "l_indent":
|
||||
@@ -185,27 +212,29 @@ screen front_page_project:
|
||||
if ability.can_distribute:
|
||||
textbutton _("Build Distributions") action Jump("build_distributions")
|
||||
|
||||
textbutton _("Android") action Jump("android")
|
||||
textbutton _("Generate Translations") action Jump("translate")
|
||||
|
||||
textbutton _("Extract Dialogue") action Jump("extract_dialogue")
|
||||
|
||||
label main_menu:
|
||||
return
|
||||
|
||||
|
||||
label start:
|
||||
show screen bottom_info
|
||||
|
||||
|
||||
label front_page:
|
||||
call screen front_page
|
||||
call screen front_page
|
||||
jump front_page
|
||||
|
||||
|
||||
|
||||
|
||||
label lint:
|
||||
python hide:
|
||||
|
||||
interface.processing(_("Checking script for potential problems..."))
|
||||
lint_fn = project.current.temp_filename("lint.txt")
|
||||
|
||||
|
||||
project.current.launch([ 'lint', lint_fn ], wait=True)
|
||||
|
||||
|
||||
e = renpy.editor.editor
|
||||
e.begin(True)
|
||||
e.open(lint_fn)
|
||||
@@ -214,10 +243,10 @@ label lint:
|
||||
jump front_page
|
||||
|
||||
label rmpersistent:
|
||||
|
||||
|
||||
python hide:
|
||||
interface.processing(_("Deleting persistent data..."))
|
||||
project.current.launch([ 'rmpersistent' ], wait=True)
|
||||
|
||||
|
||||
jump front_page
|
||||
|
||||
|
||||
|
||||
+183
-115
@@ -9,15 +9,15 @@ init python in interface:
|
||||
|
||||
import os.path
|
||||
import contextlib
|
||||
|
||||
|
||||
RENPY_URL = "http://www.renpy.org"
|
||||
RENPY_GAMES_URL = "http://games.renpy.org"
|
||||
RENPY_GAMES_URL = "http://games.renpy.org"
|
||||
DOC_PATH = os.path.join(config.renpy_base, "doc/index.html")
|
||||
DOC_URL = "http://www.renpy.org/doc/html/"
|
||||
|
||||
LICENSE_PATH = os.path.join(config.renpy_base, "doc/license.html")
|
||||
LICENSE_URL = "http://www.renpy.org/doc/html/license.html"
|
||||
|
||||
|
||||
if os.path.exists(DOC_PATH):
|
||||
DOC_LOCAL_URL = "file:///" + DOC_PATH
|
||||
else:
|
||||
@@ -27,12 +27,12 @@ init python in interface:
|
||||
LICENSE_LOCAL_URL = "file:///" + LICENSE_PATH
|
||||
else:
|
||||
LICENSE_LOCAL_URL = None
|
||||
|
||||
|
||||
def OpenDocumentation():
|
||||
"""
|
||||
An action that opens the documentation.
|
||||
"""
|
||||
|
||||
|
||||
if DOC_LOCAL_URL is not None:
|
||||
return OpenURL(DOC_LOCAL_URL)
|
||||
else:
|
||||
@@ -42,97 +42,122 @@ init python in interface:
|
||||
"""
|
||||
An action that opens the license.
|
||||
"""
|
||||
|
||||
|
||||
if LICENSE_LOCAL_URL is not None:
|
||||
return OpenURL(LICENSE_LOCAL_URL)
|
||||
else:
|
||||
return OpenURL(LICENSE_URL)
|
||||
|
||||
|
||||
|
||||
|
||||
# Should we display the bottom links?
|
||||
links = True
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def nolinks():
|
||||
global links
|
||||
links = False
|
||||
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
links = True
|
||||
|
||||
|
||||
# This displays the bottom of the screen. If the tooltip is not None, this displays the
|
||||
# tooltip. Otherwise, it displays a list of links (to various websites, and to the
|
||||
# tooltip. Otherwise, it displays a list of links (to various websites, and to the
|
||||
# preferences and update screen), or is just blank.
|
||||
screen bottom_info:
|
||||
|
||||
|
||||
zorder 100
|
||||
|
||||
|
||||
if interface.links:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_default"
|
||||
|
||||
|
||||
left_margin (10 + INDENT)
|
||||
right_margin (10 + INDENT)
|
||||
xfill True
|
||||
ypos 536
|
||||
yanchor 0.0
|
||||
|
||||
|
||||
hbox:
|
||||
xfill True
|
||||
|
||||
|
||||
hbox:
|
||||
spacing INDENT
|
||||
textbutton _("Documentation") style "l_link" action interface.OpenDocumentation()
|
||||
textbutton _("Ren'Py Website") style "l_link" action OpenURL(interface.RENPY_URL)
|
||||
textbutton _("Ren'Py Games List") style "l_link" action OpenURL(interface.RENPY_GAMES_URL)
|
||||
textbutton _("About") style "l_link" action Jump("about")
|
||||
|
||||
|
||||
hbox:
|
||||
spacing INDENT
|
||||
xalign 1.0
|
||||
|
||||
if ability.can_update:
|
||||
textbutton _("update") action Jump("update") style "l_link"
|
||||
|
||||
|
||||
textbutton _("preferences") style "l_link" action Jump("preferences")
|
||||
textbutton _("quit") style "l_link" action Quit(confirm=False)
|
||||
|
||||
|
||||
|
||||
screen common:
|
||||
|
||||
|
||||
default complete = None
|
||||
default total = None
|
||||
default yes = None
|
||||
default no = None
|
||||
|
||||
default choices = None
|
||||
default cancel = None
|
||||
default bar_value = None
|
||||
|
||||
frame:
|
||||
style "l_root"
|
||||
|
||||
frame:
|
||||
style_group "l_info"
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
text message:
|
||||
text_align 0.5
|
||||
xalign 0.5
|
||||
layout "subtitle"
|
||||
|
||||
|
||||
if complete is not None:
|
||||
add SPACER
|
||||
|
||||
|
||||
frame:
|
||||
style "l_progress_frame"
|
||||
|
||||
|
||||
bar:
|
||||
range total
|
||||
value complete
|
||||
style "l_progress_bar"
|
||||
|
||||
|
||||
if bar_value is not None:
|
||||
add SPACER
|
||||
|
||||
frame:
|
||||
style "l_progress_frame"
|
||||
|
||||
bar:
|
||||
value bar_value
|
||||
style "l_progress_bar"
|
||||
|
||||
|
||||
if choices:
|
||||
add SPACER
|
||||
|
||||
for v, l in choices:
|
||||
textbutton l action SetScreenVariable("selected", v)
|
||||
|
||||
if selected is not None:
|
||||
$ continue_ = Return(selected)
|
||||
else:
|
||||
$ continue_ = None
|
||||
|
||||
if submessage:
|
||||
add SPACER
|
||||
|
||||
@@ -143,21 +168,23 @@ screen common:
|
||||
|
||||
if yes:
|
||||
add SPACER
|
||||
|
||||
|
||||
hbox:
|
||||
xalign 0.5
|
||||
textbutton _("Yes") style "l_button" action yes
|
||||
null width 160
|
||||
textbutton _("No") style "l_button" action no
|
||||
|
||||
|
||||
|
||||
label title text_color title_color style "l_info_label"
|
||||
|
||||
if back:
|
||||
textbutton _("Back") action Return(False) style "l_left_button"
|
||||
|
||||
textbutton _("Back") action back style "l_left_button"
|
||||
elif cancel:
|
||||
textbutton _("Cancel") action cancel style "l_left_button"
|
||||
|
||||
if continue_:
|
||||
textbutton _("Continue") action Return(True) style "l_right_button"
|
||||
textbutton _("Continue") action continue_ style "l_right_button"
|
||||
|
||||
|
||||
screen launcher_input:
|
||||
@@ -167,142 +194,168 @@ screen launcher_input:
|
||||
|
||||
frame:
|
||||
style_group "l_info"
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
text message
|
||||
|
||||
text message:
|
||||
text_align 0.5
|
||||
xalign 0.5
|
||||
layout "subtitle"
|
||||
|
||||
add SPACER
|
||||
|
||||
input style "l_default" size 24 xalign 0.5 default default color INPUT_COLOR
|
||||
input style "l_default" size 24 xalign 0.5 default default color INPUT_COLOR
|
||||
|
||||
if filename:
|
||||
add SPACER
|
||||
text _("Due to package format limitations, non-ASCII file and directory names are not allowed.")
|
||||
|
||||
label _("[title]") style "l_info_label" text_color QUESTION_COLOR
|
||||
|
||||
|
||||
label title style "l_info_label" text_color QUESTION_COLOR
|
||||
|
||||
if cancel:
|
||||
textbutton _("Cancel") action cancel style "l_left_button"
|
||||
|
||||
|
||||
init python in interface:
|
||||
|
||||
import traceback
|
||||
|
||||
def common(title, title_color, message, submessage=None, back=False, continue_=False, pause0=False, **kwargs):
|
||||
from store import Jump
|
||||
|
||||
def common(title, title_color, message, submessage=None, back=None, continue_=None, pause0=False, show_screen=False, **kwargs):
|
||||
"""
|
||||
Displays the info, interaction, and processing screens.
|
||||
|
||||
`title`
|
||||
The title of the screen.
|
||||
|
||||
|
||||
`message`
|
||||
The main message that is displayed when the screen is.
|
||||
|
||||
|
||||
`submessage`
|
||||
If not None, a message that is displayed below the main message.
|
||||
|
||||
|
||||
`back`
|
||||
If True, a back button will be present. If it's clicked, False will
|
||||
be returned.
|
||||
|
||||
If not None, a back button will be present. `back` is the action that
|
||||
is called when the button is clicked.
|
||||
|
||||
`cancel`
|
||||
If not None, a cancel button will be present. `cancel` is the action
|
||||
that is called when the button is clicked.
|
||||
|
||||
`continue_`
|
||||
If True, a continue button will be present. If it's clicked, True
|
||||
will be returned.
|
||||
|
||||
If True, a continue button will be present. `continue_` gives the action
|
||||
that is called when that button is clicked.
|
||||
|
||||
`pause0`
|
||||
If True, a zero-length pause will be inserted before calling the
|
||||
screen. This will display it to the user and then immediately
|
||||
If True, a zero-length pause will be inserted before calling the
|
||||
screen. This will display it to the user and then immediately
|
||||
return.
|
||||
|
||||
|
||||
|
||||
`show_screen`
|
||||
If True, the screen will be show, and will return immediately. if False,
|
||||
the screen will be called, and interaction will pause.
|
||||
|
||||
Other keyword arguments are passed to the screen itself.
|
||||
"""
|
||||
|
||||
if pause0:
|
||||
ui.pausebehavior(0)
|
||||
|
||||
return renpy.call_screen("common", title=title, title_color=title_color, message=message, submessage=submessage, back=back, continue_=continue_, **kwargs)
|
||||
|
||||
|
||||
if show_screen:
|
||||
screen_func = renpy.show_screen
|
||||
else:
|
||||
screen_func = renpy.call_screen
|
||||
|
||||
if pause0:
|
||||
ui.pausebehavior(0)
|
||||
|
||||
return screen_func("common", title=title, title_color=title_color, message=message, submessage=submessage, back=back, continue_=continue_, **kwargs)
|
||||
|
||||
def hide_screen():
|
||||
"""
|
||||
Hides a screen that was shown with show_screen=True.
|
||||
"""
|
||||
|
||||
renpy.hide_screen("common")
|
||||
|
||||
|
||||
def error(message, submessage=None, label="front_page", **kwargs):
|
||||
"""
|
||||
Indicates to the user that an error has occured.
|
||||
|
||||
|
||||
`message`
|
||||
The message to display.
|
||||
The message to display.
|
||||
|
||||
`submessage`
|
||||
Optional secondary message information. For example, this may be
|
||||
Optional secondary message information. For example, this may be
|
||||
used to display an exception string.
|
||||
|
||||
|
||||
`label`
|
||||
The label to redirect to when the user finishes displaying the error. None
|
||||
to just return.
|
||||
|
||||
to just return False.
|
||||
|
||||
Keyword arguments are passed into the screen so that they can be substituted into
|
||||
the message.
|
||||
"""
|
||||
|
||||
common(_("ERROR"), store.ERROR_COLOR, message=message, submessage=submessage, back=True, **kwargs)
|
||||
|
||||
if label is None:
|
||||
action = Return(False)
|
||||
else:
|
||||
action = Jump(label)
|
||||
|
||||
common(_("ERROR"), store.ERROR_COLOR, message=message, submessage=submessage, back=action, **kwargs)
|
||||
|
||||
if label:
|
||||
renpy.jump(label)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def error_handling(what, label="front_page"):
|
||||
"""
|
||||
This is a context manager that catches exceptions and displays them using
|
||||
This is a context manager that catches exceptions and displays them using
|
||||
interface.error.
|
||||
|
||||
|
||||
`what`
|
||||
What we're doing when the error occurs. This is usually written using
|
||||
What we're doing when the error occurs. This is usually written using
|
||||
the present participle.
|
||||
|
||||
|
||||
`label`
|
||||
The label to jump to when error handling finishes.
|
||||
|
||||
|
||||
As an example of usage::
|
||||
|
||||
|
||||
with interface.error_handling("opening the log file"):
|
||||
f = open("log.txt", "w")
|
||||
f = open("log.txt", "w")
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
yield
|
||||
except Exception, e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
error(_("While [what!q], an error occured:"),
|
||||
_("[exception!q]"),
|
||||
what=what,
|
||||
error(_("While [what!q], an error occured:"),
|
||||
_("[exception!q]"),
|
||||
what=what,
|
||||
label=label,
|
||||
exception=traceback.format_exception_only(type(e), e)[-1][:-1])
|
||||
|
||||
|
||||
def input(title, message, filename=False, sanitize=True, cancel=None, default=""):
|
||||
"""
|
||||
Requests typewritten input from the user.
|
||||
"""
|
||||
|
||||
|
||||
rv = default
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
|
||||
rv = renpy.call_screen("launcher_input", title=title, message=message, filename=filename, cancel=cancel, default=rv)
|
||||
|
||||
|
||||
if sanitize:
|
||||
if ("[" in rv) or ("{" in rv):
|
||||
error(_("Text input may not contain the {{ or [[ characters."), label=None)
|
||||
continue
|
||||
|
||||
|
||||
if filename:
|
||||
if filename and (filename != "withslash") and (("\\" in rv) or ("/" in rv)):
|
||||
error(_("File and directory names may not contain / or \\."), label=None)
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
rv.encode("ascii")
|
||||
except:
|
||||
@@ -313,25 +366,25 @@ init python in interface:
|
||||
|
||||
def info(message, submessage=None, pause=True, **kwargs):
|
||||
"""
|
||||
Displays an informational message to the user. The user will be asked to click to
|
||||
Displays an informational message to the user. The user will be asked to click to
|
||||
confirm that he has read the message.
|
||||
|
||||
|
||||
`message`
|
||||
The message to display.
|
||||
|
||||
The message to display.
|
||||
|
||||
`pause`
|
||||
True if we should pause while showing the info.
|
||||
|
||||
|
||||
Keyword arguments are passed into the screen so that they can be substituted into
|
||||
the message.
|
||||
"""
|
||||
|
||||
|
||||
if pause:
|
||||
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, continue_=True, **kwargs)
|
||||
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, continue_=Return(True), **kwargs)
|
||||
else:
|
||||
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, pause=0, **kwargs)
|
||||
|
||||
|
||||
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, pause0=True, **kwargs)
|
||||
|
||||
|
||||
def interaction(title, message, submessage=None, **kwargs):
|
||||
"""
|
||||
Put up on the screen while an interaction with an external program occurs.
|
||||
@@ -339,53 +392,68 @@ init python in interface:
|
||||
|
||||
`title`
|
||||
The title of the interaction.
|
||||
|
||||
|
||||
`message`
|
||||
The message itself.
|
||||
|
||||
|
||||
`submessage`
|
||||
An optional sub message.
|
||||
"""
|
||||
|
||||
common(title, store.INTERACTION_COLOR, message, submessage, pause0=True, **kwargs)
|
||||
|
||||
|
||||
def processing(message, submessage=None, complete=None, total=None, **kwargs):
|
||||
"""
|
||||
Indicates to the user that processing is taking place. This should be used when
|
||||
there is an indefinite amount of work to be done.
|
||||
|
||||
|
||||
`message`
|
||||
The message to display.
|
||||
|
||||
The message to display.
|
||||
|
||||
`submessage`
|
||||
An additional message to display.
|
||||
|
||||
`complete`
|
||||
The fraction complete the step is.
|
||||
|
||||
|
||||
`total`
|
||||
The total amount of work to do in this step.
|
||||
|
||||
|
||||
Keyword arguments are passed into the screen so that they can be substituted into
|
||||
the message.
|
||||
"""
|
||||
|
||||
common(_("PROCESSING"), store.INTERACTION_COLOR, message, submessage, pause0=True, complete=complete, total=total, **kwargs)
|
||||
common(_("PROCESSING"), store.INTERACTION_COLOR, message, submessage, pause0=True, complete=complete, total=total, **kwargs)
|
||||
|
||||
|
||||
|
||||
def yesno(message, yes=Return(True), no=Return(False), **kwargs):
|
||||
"""
|
||||
Asks the user a yes or no question.
|
||||
|
||||
|
||||
`message`
|
||||
The question to ask.
|
||||
|
||||
|
||||
`yes`
|
||||
The action to perform if the user answers yes.
|
||||
|
||||
|
||||
`no`
|
||||
The action to perform if the user answer no.
|
||||
"""
|
||||
|
||||
return common(_("QUESTION"), store.QUESTION_COLOR, message, yes=yes, no=no, **kwargs)
|
||||
|
||||
|
||||
def choice(message, choices, selected, **kwargs):
|
||||
"""
|
||||
Asks the user to pick a choice from a menu.
|
||||
|
||||
`choices`
|
||||
A list of (value, label) tuples, giving the choices.
|
||||
|
||||
`selected`
|
||||
The default choice that we mark as selected.
|
||||
"""
|
||||
|
||||
return common(_("CHOICE"), store.QUESTION_COLOR, message, choices=choices, selected=selected, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,25 +6,25 @@ init python in navigation:
|
||||
import store.project as project
|
||||
import store.editor as editor
|
||||
from store import persistent, Action
|
||||
|
||||
|
||||
|
||||
# The last navigation screen we've seen. This is the scree we try to go
|
||||
# to the next time we enter navigation. (We may not be able to go there,
|
||||
# if the screen is empty.)
|
||||
if persistent.navigation is None:
|
||||
persistent.navigation = "label"
|
||||
|
||||
# A map from a kind of information, to how we should sort it. Possible
|
||||
|
||||
# A map from a kind of information, to how we should sort it. Possible
|
||||
# sorts are alphabetical, by-file, natural.
|
||||
if persistent.navigation_sort is None:
|
||||
persistent.navigation_sort = { }
|
||||
|
||||
|
||||
if persistent.navigate_private is None:
|
||||
persistent.navigate_private = False
|
||||
|
||||
|
||||
if persistent.navigate_library is None:
|
||||
persistent.navigate_library = False
|
||||
|
||||
|
||||
# A list of kinds of navigation we support.
|
||||
KINDS = [ "file", "label", "define", "transform", "screen", "callable", "todo" ]
|
||||
|
||||
@@ -37,22 +37,22 @@ init python in navigation:
|
||||
|
||||
def group_and_sort(kind):
|
||||
"""
|
||||
This is responsible for pulling navigation information of the
|
||||
appropriate kind out of project.current.dump, grouping it,
|
||||
This is responsible for pulling navigation information of the
|
||||
appropriate kind out of project.current.dump, grouping it,
|
||||
and sorting it.
|
||||
|
||||
This returns a list of (group, list of (name, filename, line)). The
|
||||
|
||||
This returns a list of (group, list of (name, filename, line)). The
|
||||
group may be a string or None.
|
||||
"""
|
||||
|
||||
project.current.update_dump()
|
||||
|
||||
sort = persistent.navigation_sort[kind]
|
||||
|
||||
|
||||
name_map = project.current.dump.get("location", {}).get(kind, { })
|
||||
|
||||
|
||||
groups = { }
|
||||
|
||||
|
||||
for name, loc in name_map.items():
|
||||
filename, line = loc
|
||||
filename = filename.replace("\\", "/")
|
||||
@@ -63,56 +63,56 @@ init python in navigation:
|
||||
group = filename
|
||||
if group.startswith("game/"):
|
||||
group = group[5:]
|
||||
|
||||
|
||||
g = groups.get(group, None)
|
||||
if g is None:
|
||||
groups[group] = g = [ ]
|
||||
|
||||
|
||||
g.append((name, filename, line))
|
||||
|
||||
|
||||
for g in groups.values():
|
||||
if sort == "natural":
|
||||
g.sort(key=lambda a : a[2])
|
||||
else:
|
||||
g.sort(key=lambda a : a[0].lower())
|
||||
|
||||
|
||||
rv = list(groups.items())
|
||||
rv.sort()
|
||||
|
||||
return rv
|
||||
|
||||
def group_and_sort_files():
|
||||
|
||||
|
||||
rv = [ ]
|
||||
|
||||
|
||||
for fn in project.current.script_files():
|
||||
shortfn = fn
|
||||
shortfn = shortfn.replace("\\", "/")
|
||||
|
||||
if shortfn.startswith("game/"):
|
||||
shortfn = fn[5:]
|
||||
|
||||
|
||||
rv.append((shortfn, fn, None))
|
||||
|
||||
|
||||
rv.sort()
|
||||
|
||||
|
||||
return [ (None, rv) ]
|
||||
|
||||
class ChangeKind(Action):
|
||||
"""
|
||||
Changes the kind of thing we're navigating over.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, kind):
|
||||
self.kind = kind
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return persistent.navigation == self.kind
|
||||
|
||||
def __call__(self):
|
||||
if persistent.navigation == self.kind:
|
||||
return
|
||||
|
||||
|
||||
persistent.navigation = self.kind
|
||||
renpy.jump("navigation_loop")
|
||||
|
||||
@@ -123,38 +123,38 @@ init python in navigation:
|
||||
|
||||
def __init__(self, sort):
|
||||
self.sort = sort
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return persistent.navigation_sort[persistent.navigation] == self.sort
|
||||
|
||||
|
||||
def __call__(self):
|
||||
if self.get_selected():
|
||||
return
|
||||
|
||||
|
||||
persistent.navigation_sort[persistent.navigation] = self.sort
|
||||
renpy.jump("navigation_loop")
|
||||
|
||||
|
||||
|
||||
screen navigation:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
|
||||
frame style "l_label":
|
||||
has hbox xfill True
|
||||
text _("Navigate: [project.current.name]") style "l_label_text"
|
||||
|
||||
|
||||
frame:
|
||||
style "l_alternate"
|
||||
style_group "l_small"
|
||||
|
||||
|
||||
has hbox
|
||||
|
||||
|
||||
if persistent.navigation != "file":
|
||||
text _("Order: ")
|
||||
textbutton _("alphabetical") action navigation.ChangeSort("alphabetical")
|
||||
@@ -164,17 +164,17 @@ screen navigation:
|
||||
textbutton _("natural") action navigation.ChangeSort("natural")
|
||||
|
||||
null width HALF_INDENT
|
||||
|
||||
|
||||
textbutton _("refresh") action Jump("navigation_refresh")
|
||||
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
frame style "l_indent":
|
||||
hbox:
|
||||
spacing HALF_INDENT
|
||||
text _("Category:")
|
||||
|
||||
|
||||
textbutton _("files") action navigation.ChangeKind("file")
|
||||
textbutton _("labels") action navigation.ChangeKind("label")
|
||||
textbutton _("defines") action navigation.ChangeKind("define")
|
||||
@@ -199,19 +199,19 @@ screen navigation:
|
||||
style_group "l_navigation"
|
||||
|
||||
for group_name, group in groups:
|
||||
|
||||
|
||||
if group_name is not None:
|
||||
text "[group_name!q]"
|
||||
|
||||
if persistent.navigation == "todo":
|
||||
|
||||
if persistent.navigation == "todo":
|
||||
vbox:
|
||||
for name, filename, line in group:
|
||||
textbutton "[name!q]" action editor.Edit(filename, line)
|
||||
|
||||
|
||||
else:
|
||||
hbox:
|
||||
box_wrap True
|
||||
|
||||
|
||||
for name, filename, line in group:
|
||||
textbutton "[name!q]" action editor.Edit(filename, line)
|
||||
|
||||
@@ -223,11 +223,11 @@ screen navigation:
|
||||
textbutton _("+ Add script file") action Jump("add_file") style "l_button"
|
||||
|
||||
else:
|
||||
|
||||
|
||||
fixed:
|
||||
|
||||
|
||||
if persistent.navigation == "todo":
|
||||
|
||||
|
||||
text _("No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."):
|
||||
text_align 0.5
|
||||
xalign 0.5
|
||||
@@ -244,18 +244,18 @@ screen navigation:
|
||||
|
||||
label navigation:
|
||||
label navigation_loop:
|
||||
|
||||
|
||||
python in navigation:
|
||||
|
||||
kind = persistent.navigation
|
||||
|
||||
kind = persistent.navigation
|
||||
|
||||
if kind == "file":
|
||||
groups = group_and_sort_files()
|
||||
else:
|
||||
groups = group_and_sort(kind)
|
||||
|
||||
|
||||
renpy.call_screen("navigation", groups=groups)
|
||||
|
||||
|
||||
label navigation_refresh:
|
||||
$ project.current.update_dump(True)
|
||||
jump navigation_loop
|
||||
|
||||
@@ -14,9 +14,9 @@ screen select_template:
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Choose Project Template")
|
||||
@@ -26,18 +26,18 @@ screen select_template:
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONETHIRD
|
||||
|
||||
|
||||
viewport:
|
||||
scrollbars "vertical"
|
||||
vbox:
|
||||
for p in project.manager.templates:
|
||||
textbutton "[p.name!q]" action SetScreenVariable("result", p) style "l_list"
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum TWOTHIRDS
|
||||
|
||||
text _("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.")
|
||||
|
||||
text _("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'.")
|
||||
|
||||
|
||||
textbutton _("Back") action Jump("front_page") style "l_left_button"
|
||||
@@ -45,27 +45,27 @@ screen select_template:
|
||||
|
||||
|
||||
label new_project:
|
||||
|
||||
|
||||
if persistent.projects_directory is None:
|
||||
call choose_projects_directory
|
||||
|
||||
|
||||
python hide:
|
||||
|
||||
|
||||
project_name = interface.input(
|
||||
_("PROJECT NAME"),
|
||||
_("PROJECT NAME"),
|
||||
_("Please enter the name of your project:"),
|
||||
filename=True,
|
||||
cancel=Jump("front_page"))
|
||||
|
||||
|
||||
project_name = project_name.strip()
|
||||
if not project_name:
|
||||
interface.error(_("The project name may not be empty."))
|
||||
|
||||
project_dir = os.path.join(persistent.projects_directory, project_name)
|
||||
|
||||
|
||||
if project.manager.get(project_name) is not None:
|
||||
interface.error(_("[project_name!q] already exists. Please choose a different project name."), project_name=project_name)
|
||||
|
||||
|
||||
if os.path.exists(project_dir):
|
||||
interface.error(_("[project_dir!q] already exists. Please choose a different project name."), project_dir=project_dir)
|
||||
|
||||
@@ -75,25 +75,25 @@ label new_project:
|
||||
template = renpy.call_screen("select_template")
|
||||
|
||||
template_path = template.path
|
||||
|
||||
|
||||
with interface.error_handling("creating a new project"):
|
||||
shutil.copytree(template_path, project_dir)
|
||||
|
||||
|
||||
# Delete the tmp directory, if it exists.
|
||||
if os.path.isdir(os.path.join(project_dir, "tmp")):
|
||||
os.path.rmtree(os.path.join(project_dir, "tmp"))
|
||||
|
||||
|
||||
# Delete project.json, which must exist.
|
||||
os.unlink(os.path.join(project_dir, "project.json"))
|
||||
|
||||
|
||||
# Change the save directory in options.rpy
|
||||
fn = os.path.join(project_dir, "game/options.rpy")
|
||||
with open(fn, "rb") as f:
|
||||
options = f.read().decode("utf-8")
|
||||
|
||||
save_dir = project_name + "-" + str(int(time.time()))
|
||||
options = re.sub(r'template-\d+', save_dir, options)
|
||||
|
||||
options = options.replace("PROJECT_NAME", project_name)
|
||||
options = options.replace("UNIQUE", str(int(time.time())))
|
||||
|
||||
with open(fn, "wb") as f:
|
||||
f.write(options.encode("utf-8"))
|
||||
|
||||
@@ -101,9 +101,7 @@ label new_project:
|
||||
with interface.error_handling("activating the new project"):
|
||||
project.manager.scan()
|
||||
project.Select(project.manager.get(project_name))()
|
||||
|
||||
|
||||
call choose_theme_callable
|
||||
|
||||
jump front_page
|
||||
|
||||
|
||||
|
||||
+28
-24
@@ -35,7 +35,7 @@ init -1 python hide:
|
||||
|
||||
#########################################
|
||||
# Themes
|
||||
|
||||
|
||||
## We then want to call a theme function. themes.roundrect is
|
||||
## a theme that features the use of rounded rectangles. It's
|
||||
## the only theme we currently support.
|
||||
@@ -46,7 +46,7 @@ init -1 python hide:
|
||||
theme.roundrect(
|
||||
## Theme: Roundrect
|
||||
## Color scheme: Basic Blue
|
||||
|
||||
|
||||
## The color of an idle widget face.
|
||||
widget = "#003c78",
|
||||
|
||||
@@ -60,7 +60,7 @@ init -1 python hide:
|
||||
## example, the current value of a preference.)
|
||||
widget_selected = "#ffffc8",
|
||||
|
||||
## The color of a disabled widget face.
|
||||
## The color of a disabled widget face.
|
||||
disabled = "#404040",
|
||||
|
||||
## The color of disabled widget text.
|
||||
@@ -88,7 +88,7 @@ init -1 python hide:
|
||||
|
||||
## And we're done with the theme. The theme will customize
|
||||
## various styles, so if we want to change them, we should
|
||||
## do so below.
|
||||
## do so below.
|
||||
)
|
||||
|
||||
#########################################
|
||||
@@ -100,7 +100,7 @@ init -1 python hide:
|
||||
## show help to the user.
|
||||
## - A file name relative to the base directory, which is opened in a
|
||||
## web browser.
|
||||
## - None, to disable help.
|
||||
## - None, to disable help.
|
||||
config.help = "README.html"
|
||||
|
||||
#########################################
|
||||
@@ -171,9 +171,9 @@ init -1 python hide:
|
||||
config.has_autosave = False
|
||||
config.log_enable = False
|
||||
config.mouse_hide_time = 86400 * 366
|
||||
|
||||
|
||||
_game_menu_screen = None
|
||||
|
||||
|
||||
config.underlay = [
|
||||
renpy.Keymap(
|
||||
quit = renpy.quit_event,
|
||||
@@ -188,37 +188,41 @@ init -1 python hide:
|
||||
## This section controls how to build Ren'Py. (Building the launcher is how
|
||||
## we build Ren'Py distributions.)
|
||||
init python:
|
||||
|
||||
|
||||
## We're building Ren'Py tonight.
|
||||
build.renpy = True
|
||||
|
||||
|
||||
## The version number that's supplied to the updater.
|
||||
build.version = "Ren'Py {}".format(config.version)
|
||||
|
||||
|
||||
## The name that's used for directories and archive files. For example, if
|
||||
## this is 'mygame-1.0', the windows distribution will be in the
|
||||
## directory 'mygame-1.0-win', in the 'mygame-1.0-win.zip' file.
|
||||
build.directory_name = "renpy-" + config.version.rsplit('.', 1)[0]
|
||||
|
||||
|
||||
if 'RENPY_NIGHTLY' in os.environ:
|
||||
build.directory_name = os.environ['RENPY_NIGHTLY']
|
||||
else:
|
||||
build.directory_name = "renpy-" + config.version.rsplit('.', 1)[0]
|
||||
|
||||
## The name that's uses for executables - the program that users will run
|
||||
## to start the game. For example, if this is 'mygame', then on Windows,
|
||||
## users can click 'mygame.exe' to start the game.
|
||||
build.executable_name = "renpy"
|
||||
|
||||
|
||||
## If True, Ren'Py will include update information into packages. This
|
||||
## allows the updater to run.
|
||||
build.include_update = True
|
||||
|
||||
|
||||
## Clear out various file patterns.
|
||||
build.renpy_patterns = [ ]
|
||||
build.early_base_patterns = [ ]
|
||||
build.base_patterns = [ ]
|
||||
build.late_base_patterns = [ ]
|
||||
|
||||
# We don't need to clear out the executable patterns, since they're
|
||||
|
||||
# We don't need to clear out the executable patterns, since they're
|
||||
# correct for Ren'Py.
|
||||
|
||||
## Now, add the Ren'Py distribution in using classify_renpy.
|
||||
|
||||
## Now, add the Ren'Py distribution in using classify_renpy.
|
||||
build.classify_renpy("**~", None)
|
||||
build.classify_renpy("**/#*", None)
|
||||
build.classify_renpy("**/thumbs.db", None)
|
||||
@@ -241,18 +245,18 @@ init python:
|
||||
# games.
|
||||
build.classify_renpy("launcher/game/theme/", None)
|
||||
build.classify_renpy("launcher/**", "source")
|
||||
build.classify_renpy("template/**", "source")
|
||||
build.classify_renpy("templates/**", "source")
|
||||
build.classify_renpy("the_question/**", "source")
|
||||
build.classify_renpy("tutorial/**", "source")
|
||||
|
||||
# docs.
|
||||
# docs.
|
||||
build.classify_renpy("doc/", "source")
|
||||
build.classify_renpy("doc/.doctrees/", None)
|
||||
build.classify_renpy("doc/_sources/", None)
|
||||
build.classify_renpy("doc/**", "source")
|
||||
build.classify_renpy("LICENSE.txt", "source")
|
||||
|
||||
# module.
|
||||
|
||||
# module.
|
||||
build.classify_renpy("module/", "source")
|
||||
build.classify_renpy("module/*.c", "source")
|
||||
build.classify_renpy("module/gen/", "source")
|
||||
@@ -283,8 +287,8 @@ init python:
|
||||
build.classify_renpy("editra/Editra-mac.app/**", "editra-mac")
|
||||
build.classify_renpy("editra/lib/**", "editra-windows")
|
||||
build.classify_renpy("editra/editra.exe", "editra-windows")
|
||||
|
||||
|
||||
|
||||
|
||||
# Executable rules.
|
||||
build.executable("editra/Editra/Editra")
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python in distribute:
|
||||
|
||||
|
||||
import time
|
||||
import zipfile
|
||||
import tarfile
|
||||
import zlib
|
||||
import struct
|
||||
import stat
|
||||
import shutil
|
||||
|
||||
from zipfile import crc32
|
||||
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
|
||||
|
||||
class ZipFile(zipfile.ZipFile):
|
||||
|
||||
def write_with_info(self, zinfo, filename):
|
||||
@@ -80,25 +81,29 @@ init python in distribute:
|
||||
self.fp.seek(position, 0)
|
||||
self.filelist.append(zinfo)
|
||||
self.NameToInfo[zinfo.filename] = zinfo
|
||||
|
||||
|
||||
|
||||
|
||||
class ZipPackage(object):
|
||||
"""
|
||||
A class that creates a zip file.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, filename):
|
||||
self.zipfile = ZipFile(filename, "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
|
||||
def add_file(self, name, path, xbit):
|
||||
|
||||
|
||||
if path is None:
|
||||
raise Exception("path for " + name + " must not be None.")
|
||||
|
||||
zi = zipfile.ZipInfo(name)
|
||||
|
||||
s = os.stat(path)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
try:
|
||||
s = os.stat(path)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
except:
|
||||
zi.date_time = time.gmtime()[:6]
|
||||
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
@@ -120,7 +125,7 @@ init python in distribute:
|
||||
zi.compress_type = zipfile.ZIP_STORED
|
||||
zi.create_system = 3
|
||||
zi.external_attr = (long(0040755) << 16) | 0x10
|
||||
|
||||
|
||||
self.zipfile.write_with_info(zi, path)
|
||||
|
||||
def close(self):
|
||||
@@ -128,15 +133,15 @@ init python in distribute:
|
||||
|
||||
|
||||
class TarPackage(object):
|
||||
|
||||
|
||||
def __init__(self, filename, mode, notime=False):
|
||||
"""
|
||||
notime
|
||||
If true, times will be forced to the epoch.
|
||||
"""
|
||||
|
||||
|
||||
self.tarfile = tarfile.open(filename, mode)
|
||||
self.tarfile.dereference = True
|
||||
self.tarfile.dereference = True
|
||||
self.notime = notime
|
||||
|
||||
def add_file(self, name, path, xbit):
|
||||
@@ -173,3 +178,31 @@ init python in distribute:
|
||||
|
||||
def close(self):
|
||||
self.tarfile.close()
|
||||
|
||||
class DirectoryPackage(object):
|
||||
|
||||
def mkdir(self, path):
|
||||
if not os.path.isdir(path):
|
||||
os.mkdir(path, 0755)
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.mkdir(path)
|
||||
|
||||
def add_file(self, name, path, xbit):
|
||||
fn = os.path.join(self.path, name)
|
||||
shutil.copy2(path, fn)
|
||||
|
||||
if xbit:
|
||||
os.chmod(fn, 0755)
|
||||
else:
|
||||
os.chmod(fn, 0644)
|
||||
|
||||
def add_directory(self, name, path):
|
||||
fn = os.path.join(self.path, name)
|
||||
self.mkdir(fn)
|
||||
|
||||
def close(self):
|
||||
return
|
||||
|
||||
|
||||
|
||||
+887
-887
File diff suppressed because it is too large
Load Diff
@@ -4,93 +4,93 @@
|
||||
init python:
|
||||
if persistent.gl_enable is None:
|
||||
persistent.gl_enable = True
|
||||
|
||||
|
||||
config.gl_enable = persistent.gl_enable
|
||||
|
||||
|
||||
if persistent.windows_console is None:
|
||||
persistent.windows_console = False
|
||||
|
||||
def scan_translations():
|
||||
|
||||
|
||||
languages = renpy.known_languages()
|
||||
|
||||
|
||||
if not languages:
|
||||
return None
|
||||
|
||||
|
||||
rv = [ ( "English", None) ]
|
||||
|
||||
|
||||
for i in languages:
|
||||
rv.append((i.title(), i))
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
screen preferences:
|
||||
|
||||
|
||||
$ translations = scan_translations()
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Launcher Preferences")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
hbox:
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONETHIRD
|
||||
xfill True
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
# Projects directory selection.
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Projects Directory:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
|
||||
frame style "l_indent":
|
||||
if persistent.projects_directory:
|
||||
textbutton _("[persistent.projects_directory!q]") action Jump("projects_directory_preference")
|
||||
else:
|
||||
textbutton _("Not Set") action Jump("projects_directory_preference")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
add SPACER
|
||||
|
||||
# Text editor selection.
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Text Editor:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
frame style "l_indent":
|
||||
if persistent.editor:
|
||||
textbutton persistent.editor action Jump("editor_preference")
|
||||
else:
|
||||
textbutton _("Not Set") action Jump("editor_preference")
|
||||
|
||||
|
||||
add SPACER
|
||||
|
||||
if ability.can_update:
|
||||
@@ -102,48 +102,49 @@ screen preferences:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Update Channel:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame style "l_indent":
|
||||
|
||||
frame style "l_indent":
|
||||
textbutton persistent.update_channel action Jump("update_preference")
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
xmaximum ONETHIRD
|
||||
xfill True
|
||||
|
||||
|
||||
has vbox
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Navigation Options:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
textbutton _("Include private names") style "l_checkbox" action ToggleField(persistent, "navigate_private")
|
||||
textbutton _("Include library names") style "l_checkbox" action ToggleField(persistent, "navigate_library")
|
||||
|
||||
add SPACER
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Launcher Options:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
textbutton _("Hardware rendering") style "l_checkbox" action ToggleField(persistent, "gl_enable")
|
||||
|
||||
textbutton _("Show templates") style "l_checkbox" action ToggleField(persistent, "show_templates")
|
||||
|
||||
if renpy.windows:
|
||||
textbutton _("Console output") style "l_checkbox" action ToggleField(persistent, "windows_console")
|
||||
|
||||
@@ -156,39 +157,39 @@ screen preferences:
|
||||
has vbox
|
||||
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Actions:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
textbutton _("Open launcher project") style "l_nonbox" action [ project.Select("launcher"), Jump("front_page") ]
|
||||
|
||||
|
||||
if translations:
|
||||
|
||||
add SPACER
|
||||
|
||||
|
||||
# Text editor selection.
|
||||
add SEPARATOR2
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
yminimum 75
|
||||
has vbox
|
||||
|
||||
|
||||
text _("Language:")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
# frame style "l_indent":
|
||||
|
||||
|
||||
# frame style "l_indent":
|
||||
|
||||
for tlname, tlvalue in translations:
|
||||
textbutton tlname action Language(tlvalue) style "l_list"
|
||||
|
||||
|
||||
|
||||
textbutton _("Back") action Jump("front_page") style "l_left_button"
|
||||
|
||||
|
||||
+141
-118
@@ -22,9 +22,9 @@ init python in project:
|
||||
import subprocess
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
|
||||
class Project(object):
|
||||
|
||||
|
||||
def __init__(self, path):
|
||||
|
||||
while path.endswith("/"):
|
||||
@@ -32,30 +32,30 @@ init python in project:
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise Exception("{} does not exist.".format(path))
|
||||
|
||||
|
||||
# The name of the project.
|
||||
self.name = os.path.basename(path)
|
||||
|
||||
|
||||
# The path to the project.
|
||||
self.path = path
|
||||
|
||||
|
||||
# The path to the game directory.
|
||||
gamedir = os.path.join(path, "game")
|
||||
if os.path.isdir(gamedir):
|
||||
self.gamedir = gamedir
|
||||
else:
|
||||
self.gamedir = path
|
||||
|
||||
|
||||
# Load the data.
|
||||
self.load_data()
|
||||
|
||||
# The project's temporary directory.
|
||||
self.tmp = None
|
||||
|
||||
self.tmp = None
|
||||
|
||||
# This contains the result of dumping information about the game
|
||||
# to disk.
|
||||
self.dump = { }
|
||||
|
||||
|
||||
# The mtime of the last dump file loaded.
|
||||
self.dump_mtime = 0
|
||||
|
||||
@@ -87,57 +87,60 @@ init python in project:
|
||||
|
||||
def update_data(self):
|
||||
data = self.data
|
||||
|
||||
|
||||
data.setdefault("build_update", False)
|
||||
data.setdefault("packages", [ "all" ])
|
||||
|
||||
def make_tmp(self):
|
||||
"""
|
||||
Makes the project's temporary directory, if it doesn't exist
|
||||
Makes the project's temporary directory, if it doesn't exist
|
||||
yet.
|
||||
"""
|
||||
|
||||
|
||||
if self.tmp and os.path.isdir(self.tmp):
|
||||
return
|
||||
|
||||
|
||||
tmp = os.path.join(self.path, "tmp")
|
||||
|
||||
|
||||
try:
|
||||
os.mkdir(tmp)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
if os.path.isdir(tmp):
|
||||
self.tmp = tmp
|
||||
return
|
||||
|
||||
|
||||
self.tmp = tempfile.mkdtemp()
|
||||
|
||||
|
||||
def temp_filename(self, filename):
|
||||
"""
|
||||
Returns a filename in the temporary directory.
|
||||
"""
|
||||
|
||||
|
||||
self.make_tmp()
|
||||
return os.path.join(self.tmp, filename)
|
||||
|
||||
def launch(self, args=[], wait=False):
|
||||
|
||||
def launch(self, args=[], wait=False, env={}):
|
||||
"""
|
||||
Launches the project.
|
||||
|
||||
Launches the project.
|
||||
|
||||
`args`
|
||||
Additional arguments to give to the project.
|
||||
|
||||
|
||||
`wait`
|
||||
If true, waits for the launched project to terminate before
|
||||
continuing.
|
||||
|
||||
`env`
|
||||
Additional variables to include in the environment.
|
||||
"""
|
||||
|
||||
self.make_tmp()
|
||||
|
||||
# Find the python executable to run.
|
||||
executable_path = os.path.dirname(sys.executable)
|
||||
|
||||
|
||||
if renpy.renpy.windows:
|
||||
extension = ".exe"
|
||||
else:
|
||||
@@ -147,7 +150,7 @@ init python in project:
|
||||
executables = [ "python" + extension ]
|
||||
else:
|
||||
executables = [ "pythonw" + extension ]
|
||||
|
||||
|
||||
executables.append(sys.executable)
|
||||
|
||||
for i in executables:
|
||||
@@ -156,51 +159,56 @@ init python in project:
|
||||
break
|
||||
else:
|
||||
raise Exception("Python interpreter not found: %r", executables)
|
||||
|
||||
|
||||
# Put together the basic command line.
|
||||
cmd = [ executable, "-EOO", sys.argv[0] ]
|
||||
|
||||
cmd = [ executable, "-EO", sys.argv[0] ]
|
||||
|
||||
cmd.append(self.path)
|
||||
cmd.extend(args)
|
||||
|
||||
|
||||
# Add flags to dump game info.
|
||||
cmd.append("--json-dump")
|
||||
cmd.append(self.get_dump_filename())
|
||||
|
||||
if persistent.navigate_private:
|
||||
cmd.append("--json-dump-private")
|
||||
|
||||
|
||||
if persistent.navigate_library:
|
||||
cmd.append("--json-dump-common")
|
||||
|
||||
environ = dict(os.environ)
|
||||
environ.update(env)
|
||||
|
||||
for k in environ:
|
||||
environ[k] = renpy.fsencode(environ[k])
|
||||
|
||||
# Launch the project.
|
||||
with interface.error_handling("launching the project"):
|
||||
cmd = [ renpy.fsencode(i) for i in cmd ]
|
||||
|
||||
p = subprocess.Popen(cmd)
|
||||
|
||||
if wait:
|
||||
p.wait()
|
||||
|
||||
cmd = [ renpy.fsencode(i) for i in cmd ]
|
||||
|
||||
p = subprocess.Popen(cmd, env=environ)
|
||||
|
||||
if wait:
|
||||
p.wait()
|
||||
|
||||
def update_dump(self, force=False, gui=True):
|
||||
"""
|
||||
If the dumpfile does not exist, runs Ren'Py to create it. Otherwise,
|
||||
If the dumpfile does not exist, runs Ren'Py to create it. Otherwise,
|
||||
loads it in iff it's newer than the one that's already loaded.
|
||||
"""
|
||||
|
||||
dump_filename = self.get_dump_filename()
|
||||
|
||||
if force or not os.path.exists(dump_filename):
|
||||
|
||||
|
||||
if gui:
|
||||
interface.processing(_("Ren'Py is scanning the project..."))
|
||||
|
||||
|
||||
self.launch(["quit"], wait=True)
|
||||
|
||||
|
||||
if not os.path.exists(dump_filename):
|
||||
self.dump["error"] = True
|
||||
return
|
||||
|
||||
|
||||
file_mtime = os.path.getmtime(dump_filename)
|
||||
if file_mtime == self.dump_mtime:
|
||||
return
|
||||
@@ -212,7 +220,7 @@ init python in project:
|
||||
self.dump = json.load(f)
|
||||
# add todo list to dump data
|
||||
self.update_todos()
|
||||
|
||||
|
||||
except:
|
||||
self.dump["error"] = True
|
||||
|
||||
@@ -223,7 +231,7 @@ init python in project:
|
||||
"""
|
||||
|
||||
todos = self.dump.setdefault("location", {})["todo"] = {}
|
||||
|
||||
|
||||
files = self.script_files()
|
||||
|
||||
for f in files:
|
||||
@@ -232,12 +240,17 @@ init python in project:
|
||||
|
||||
for l, line in enumerate(data):
|
||||
l += 1
|
||||
|
||||
|
||||
try:
|
||||
line = line.decode("utf-8")
|
||||
except:
|
||||
continue
|
||||
|
||||
m = re.search(r".*#\s*TODO(\s*:\s*|\s+)(.*)", line, re.I)
|
||||
|
||||
|
||||
if m is None:
|
||||
continue
|
||||
|
||||
|
||||
raw_todo_text = m.group(2).strip()
|
||||
todo_text = raw_todo_text
|
||||
|
||||
@@ -246,7 +259,7 @@ init python in project:
|
||||
while not todo_text or todo_text in todos:
|
||||
index += 1
|
||||
todo_text = "{0} ({1})".format(raw_todo_text, index)
|
||||
|
||||
|
||||
todos[todo_text] = [f, l]
|
||||
|
||||
|
||||
@@ -254,7 +267,7 @@ init python in project:
|
||||
"""
|
||||
Unelides the filename relative to the project base.
|
||||
"""
|
||||
|
||||
|
||||
fn1 = os.path.join(self.path, fn)
|
||||
if os.path.exists(fn1):
|
||||
return fn1
|
||||
@@ -262,90 +275,90 @@ init python in project:
|
||||
fn2 = os.path.join(config.renpy_base, fn)
|
||||
if os.path.exists(fn2):
|
||||
return fn2
|
||||
|
||||
|
||||
return fn
|
||||
|
||||
|
||||
def script_files(self):
|
||||
"""
|
||||
Return a list of the script files that make up the project. These
|
||||
are elided, and so need to be passed to unelide_filename before they
|
||||
can be included in the project.
|
||||
"""
|
||||
|
||||
|
||||
rv = [ ]
|
||||
rv.extend(i for i, isdir in util.walk(self.path) if (not isdir) and (i.endswith(".rpy") or i.endswith(".rpym")) )
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
class ProjectManager(object):
|
||||
"""
|
||||
This maintains a list of the various types of projects that
|
||||
we know about.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# The projects directory.
|
||||
self.projects_directory = ""
|
||||
|
||||
|
||||
# Normal projects, in alphabetical order by lowercase name.
|
||||
self.projects = [ ]
|
||||
|
||||
|
||||
# Template projects.
|
||||
self.templates = [ ]
|
||||
|
||||
# All projects - normal, template, and hidden.
|
||||
self.all_projects = [ ]
|
||||
|
||||
|
||||
# Directories that have been scanned.
|
||||
self.scanned = set()
|
||||
|
||||
|
||||
self.scan()
|
||||
|
||||
|
||||
def scan(self):
|
||||
"""
|
||||
Scans for projects.
|
||||
"""
|
||||
|
||||
|
||||
if (persistent.projects_directory is not None) and not os.path.isdir(persistent.projects_directory):
|
||||
persistent.projects_directory = None
|
||||
|
||||
|
||||
self.projects_directory = persistent.projects_directory
|
||||
|
||||
self.projects = [ ]
|
||||
self.templates = [ ]
|
||||
self.all_projects = [ ]
|
||||
self.scanned = set()
|
||||
|
||||
|
||||
if self.projects_directory is not None:
|
||||
self.scan_directory(self.projects_directory)
|
||||
|
||||
|
||||
self.scan_directory(config.renpy_base)
|
||||
self.scan_directory(os.path.join(config.renpy_base, "templates"))
|
||||
|
||||
self.projects.sort(key=lambda p : p.name.lower())
|
||||
self.templates.sort(key=lambda p : p.name.lower())
|
||||
|
||||
|
||||
self.projects.sort(key=lambda p : p.name.lower())
|
||||
self.templates.sort(key=lambda p : p.name.lower())
|
||||
|
||||
def scan_directory(self, d):
|
||||
"""
|
||||
Scans for projects in directories directly underneath `d`.
|
||||
"""
|
||||
|
||||
|
||||
global current
|
||||
|
||||
|
||||
d = os.path.abspath(d)
|
||||
|
||||
|
||||
if not os.path.isdir(d):
|
||||
return
|
||||
|
||||
|
||||
for pdir in os.listdir(d):
|
||||
ppath = os.path.join(d, pdir)
|
||||
|
||||
|
||||
# A project must be a directory.
|
||||
if not os.path.isdir(ppath):
|
||||
continue
|
||||
|
||||
|
||||
# A project has either a game/ directory, or a project.json
|
||||
# file.
|
||||
if (not os.path.isdir(os.path.join(ppath, "game"))) and (not os.path.exists(os.path.join(ppath, "project.json"))):
|
||||
@@ -354,52 +367,52 @@ init python in project:
|
||||
if ppath in self.scanned:
|
||||
continue
|
||||
self.scanned.add(ppath)
|
||||
|
||||
|
||||
# We have a project directory, so create a Project.
|
||||
p = Project(ppath)
|
||||
|
||||
|
||||
project_type = p.data.get("type", "normal")
|
||||
|
||||
|
||||
if project_type == "hidden":
|
||||
pass
|
||||
elif project_type == "template":
|
||||
self.templates.append(p)
|
||||
else:
|
||||
self.projects.append(p)
|
||||
|
||||
self.projects.append(p)
|
||||
|
||||
self.all_projects.append(p)
|
||||
|
||||
|
||||
# Select the default project.
|
||||
if persistent.active_project is not None:
|
||||
p = self.get(persistent.active_project)
|
||||
|
||||
|
||||
if p is not None:
|
||||
current = p
|
||||
return
|
||||
|
||||
|
||||
p = self.get("tutorial")
|
||||
if p is not None:
|
||||
current = p
|
||||
return
|
||||
|
||||
|
||||
current = None
|
||||
|
||||
|
||||
|
||||
|
||||
def get(self, name):
|
||||
"""
|
||||
Gets the project with the given name.
|
||||
|
||||
|
||||
Returns None if the project doesn't exist.
|
||||
"""
|
||||
|
||||
|
||||
for p in self.all_projects:
|
||||
if p.name == name:
|
||||
return p
|
||||
|
||||
|
||||
return None
|
||||
|
||||
manager = ProjectManager()
|
||||
|
||||
|
||||
manager = ProjectManager()
|
||||
|
||||
# The current project.
|
||||
current = None
|
||||
|
||||
@@ -409,38 +422,38 @@ init python in project:
|
||||
An action that causes p to become the selected project when it was
|
||||
clicked. If label is not None, jumps to the given label.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, p, label=None):
|
||||
"""
|
||||
`p`
|
||||
Either a project object, or a string giving the name of a
|
||||
Either a project object, or a string giving the name of a
|
||||
project.
|
||||
|
||||
|
||||
`label`
|
||||
The label to jump to when clicked.
|
||||
"""
|
||||
|
||||
|
||||
if isinstance(p, basestring):
|
||||
p = manager.get(p)
|
||||
|
||||
|
||||
self.project = p
|
||||
self.label = label
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
if self.project is None:
|
||||
return False
|
||||
|
||||
if current is None:
|
||||
return False
|
||||
|
||||
|
||||
return current.path == self.project.path
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return self.project is not None
|
||||
|
||||
|
||||
def __call__(self):
|
||||
global current
|
||||
|
||||
|
||||
current = self.project
|
||||
persistent.active_project = self.project.name
|
||||
|
||||
@@ -448,14 +461,14 @@ init python in project:
|
||||
|
||||
if self.label is not None:
|
||||
renpy.jump(self.label)
|
||||
|
||||
|
||||
|
||||
|
||||
class Launch(Action):
|
||||
"""
|
||||
An action that launches the supplied project, or the current
|
||||
project if no project is supplied.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, p=None):
|
||||
if p is None:
|
||||
self.project = current
|
||||
@@ -463,13 +476,23 @@ init python in project:
|
||||
self.project = manager.get(p)
|
||||
else:
|
||||
self.project = p
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return self.project is not None
|
||||
|
||||
|
||||
def __call__(self):
|
||||
self.project.launch()
|
||||
|
||||
class Rescan(Action):
|
||||
def __call__(self):
|
||||
"""
|
||||
Rescans the projects directory.
|
||||
"""
|
||||
|
||||
manager.scan()
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
manager.scan()
|
||||
|
||||
if isinstance(persistent.projects_directory, str):
|
||||
@@ -477,13 +500,13 @@ init python in project:
|
||||
|
||||
###############################################################################
|
||||
# Code to choose the projects directory.
|
||||
|
||||
|
||||
label choose_projects_directory:
|
||||
|
||||
|
||||
python hide:
|
||||
|
||||
interface.interaction(_("PROJECTS DIRECTORY"), _("Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"), _("This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."),)
|
||||
|
||||
|
||||
path = persistent.projects_directory
|
||||
|
||||
if path:
|
||||
@@ -493,34 +516,34 @@ label choose_projects_directory:
|
||||
default_path = os.path.dirname(os.path.abspath(config.renpy_base))
|
||||
except:
|
||||
default_path = os.path.abspath(config.renpy_base)
|
||||
|
||||
|
||||
|
||||
if EasyDialogs:
|
||||
|
||||
choice = EasyDialogs.AskFolder(defaultLocation=default_path, wanted=unicode)
|
||||
|
||||
if choice is not None:
|
||||
path = choice
|
||||
path = choice
|
||||
else:
|
||||
path = None
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
|
||||
cmd = [ "/usr/bin/python", os.path.join(config.gamedir, "tkaskdir.py"), renpy.fsencode(default_path) ]
|
||||
|
||||
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
choice = p.stdout.read()
|
||||
choice = p.stdout.read()
|
||||
p.wait()
|
||||
|
||||
if choice:
|
||||
path = renpy.fsdecode(choice)
|
||||
|
||||
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
path = None
|
||||
interface.error(_("Ren'Py was unable to run python with tkinter to choose the projects directory."), label=None)
|
||||
|
||||
@@ -530,7 +553,7 @@ label choose_projects_directory:
|
||||
|
||||
path = renpy.fsdecode(path)
|
||||
|
||||
persistent.projects_directory = path
|
||||
persistent.projects_directory = path
|
||||
project.manager.scan()
|
||||
|
||||
|
||||
return
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
init -999:
|
||||
$ config.script_version = (6, 15, 7)
|
||||
|
||||
|
||||
$ config.script_version = (6, 16, 2)
|
||||
|
||||
+46
-38
@@ -19,14 +19,14 @@ init -1 python:
|
||||
# Colors for the scrollbar thumb.
|
||||
SCROLLBAR_IDLE = "#dfdfdf"
|
||||
SCROLLBAR_HOVER = "#d86b45"
|
||||
|
||||
|
||||
# An image used as a separator pattern.
|
||||
PATTERN = "pattern.png"
|
||||
|
||||
|
||||
# A displayable used for the background of everything.
|
||||
BACKGROUND = "background.png"
|
||||
|
||||
# A displayable used for the background of windows
|
||||
BACKGROUND = "background.png"
|
||||
|
||||
# A displayable used for the background of windows
|
||||
# containing commands, preferences, and navigation info.
|
||||
WINDOW = Frame("window.png", 0, 0, tile=True)
|
||||
|
||||
@@ -35,7 +35,7 @@ init -1 python:
|
||||
|
||||
# A displayable used the background of information boxes.
|
||||
INFO_WINDOW = "#f9f9f9"
|
||||
|
||||
|
||||
# Colors for the titles of information boxes.
|
||||
ERROR_COLOR = "#d15353"
|
||||
INFO_COLOR = "#545454"
|
||||
@@ -65,7 +65,7 @@ init 1 python:
|
||||
LIGHT = "Roboto-Light.ttf"
|
||||
REGULAR = "Roboto-Regular.ttf"
|
||||
DARK = "Roboto-Medium.ttf"
|
||||
|
||||
|
||||
# DIVIDING THE SCREEN
|
||||
ONETHIRD = 258
|
||||
TWOTHIRDS = 496
|
||||
@@ -78,7 +78,7 @@ init 1 python:
|
||||
style.l_default.idle_color = IDLE
|
||||
style.l_default.hover_color = HOVER
|
||||
style.l_default.size = 18
|
||||
|
||||
|
||||
style.l_text = Style(style.l_default)
|
||||
|
||||
style.l_button = Style(style.l_default)
|
||||
@@ -104,8 +104,8 @@ init 1 python:
|
||||
style.l_left_button = Style(style.l_right_button)
|
||||
style.l_left_button.xalign = 0.0
|
||||
style.l_left_button_text = Style(style.l_right_button_text)
|
||||
|
||||
|
||||
|
||||
|
||||
# The root frame. This contains everything but the bottom navigation, back
|
||||
# button, and tooltip button.
|
||||
style.l_root = Style(style.l_default)
|
||||
@@ -113,24 +113,24 @@ init 1 python:
|
||||
style.l_root.xpadding = 10
|
||||
style.l_root.top_padding = 64
|
||||
style.l_root.bottom_padding = 128
|
||||
|
||||
|
||||
# An inner window.
|
||||
style.l_window = Style(style.l_default)
|
||||
|
||||
style.l_window.background = WINDOW
|
||||
|
||||
style.l_window.background = WINDOW
|
||||
|
||||
style.l_window.left_padding = 6
|
||||
style.l_window.xfill = True
|
||||
style.l_window.yfill = True
|
||||
|
||||
|
||||
|
||||
|
||||
# Normal-sized labels.
|
||||
style.l_label = Style(style.l_default)
|
||||
style.l_label.xfill = True
|
||||
style.l_label.top_padding = 10
|
||||
style.l_label.bottom_padding = 8
|
||||
style.l_label.bottom_margin = 12
|
||||
style.l_label.background = SEPARATOR
|
||||
style.l_label.background = SEPARATOR
|
||||
style.l_label_text = Style(style.l_default)
|
||||
style.l_label_text.size = 24
|
||||
style.l_label_text.xpos = INDENT
|
||||
@@ -141,12 +141,12 @@ init 1 python:
|
||||
style.l_label_small.xfill = True
|
||||
style.l_label_small.bottom_padding = 8
|
||||
style.l_label_small.bottom_margin = HALF_SPACER_HEIGHT
|
||||
style.l_label_small.background = SEPARATOR
|
||||
style.l_label_small.background = SEPARATOR
|
||||
style.l_label_small_text = Style(style.l_default)
|
||||
style.l_label_small_text.xpos = INDENT
|
||||
style.l_label_small_text.yoffset = 6
|
||||
style.l_label_small_text.size = 20
|
||||
|
||||
|
||||
# Alternate labels. This nests inside an l_label, and gives a button
|
||||
# or label that's nested inside another label.
|
||||
style.l_alternate = Style(style.l_default)
|
||||
@@ -158,21 +158,21 @@ init 1 python:
|
||||
style.l_alternate_text.size = 14
|
||||
style.l_alternate_text.font = LIGHT
|
||||
style.l_alternate_text.text_align = 1.0
|
||||
|
||||
|
||||
style.l_small_button = Style(style.l_button)
|
||||
style.l_small_button_text = Style(style.l_button_text)
|
||||
style.l_small_button_text.size = 14
|
||||
style.l_small_text = Style(style.l_text)
|
||||
style.l_small_text.size = 14
|
||||
|
||||
|
||||
# Indents its contents.
|
||||
style.l_indent = Style(style.l_default)
|
||||
style.l_indent.left_margin = INDENT
|
||||
|
||||
|
||||
# Indents its contents and pads them vertically.
|
||||
style.l_indent_margin = Style(style.l_indent)
|
||||
style.l_indent_margin.ymargin = 6
|
||||
|
||||
style.l_indent_margin.ymargin = 6
|
||||
|
||||
# List button.
|
||||
style.l_list = Style(style.l_default)
|
||||
style.l_list.left_padding = HALF_INDENT
|
||||
@@ -205,14 +205,14 @@ init 1 python:
|
||||
style.l_vscrollbar.bar_vertical = True
|
||||
style.l_vscrollbar.bar_invert = True
|
||||
style.l_vscrollbar.unscrollable = "hide"
|
||||
|
||||
|
||||
|
||||
|
||||
# Information window.
|
||||
style.l_info_vbox = Style(style.vbox)
|
||||
style.l_info_vbox.yalign = 0.5
|
||||
style.l_info_vbox.xalign = 0.5
|
||||
style.l_info_vbox.xfill = True
|
||||
|
||||
|
||||
style.l_info_frame = Style(style.l_default)
|
||||
style.l_info_frame.ypadding = 21
|
||||
style.l_info_frame.xfill = True
|
||||
@@ -221,25 +221,28 @@ init 1 python:
|
||||
INFO_WINDOW,
|
||||
Frame(PATTERN, 0, 0, tile=True, ymaximum=5, yalign=0.0, yoffset=8),
|
||||
Frame(PATTERN, 0, 0, tile=True, ymaximum=5, yalign=1.0, yoffset=-8),
|
||||
)
|
||||
)
|
||||
|
||||
style.l_info_frame.yminimum = 180
|
||||
style.l_info_frame.ypos = 100
|
||||
|
||||
style.l_info_frame.ypos = 75
|
||||
|
||||
style.l_info_label = Style(style.l_default)
|
||||
style.l_info_label.xalign = 0.5
|
||||
style.l_info_label.ypos = 100
|
||||
style.l_info_label.ypos = 75
|
||||
style.l_info_label.yanchor = 1.0
|
||||
style.l_info_label.yoffset = 12
|
||||
style.l_info_label_text = Style(style.l_default)
|
||||
style.l_info_label_text.size = 36
|
||||
|
||||
|
||||
style.l_info_text = Style(style.l_default)
|
||||
style.l_info_text.xalign = 0.5
|
||||
|
||||
|
||||
style.l_info_button = Style(style.l_button)
|
||||
style.l_info_button.xalign = 0.5
|
||||
style.l_info_button.xmargin = 50
|
||||
style.l_info_button_text = Style(style.l_button_text)
|
||||
style.l_info_button_text.text_align = 0.5
|
||||
style.l_info_button_text.layout = "subtitle"
|
||||
|
||||
# Code navigation
|
||||
style.l_navigation_button = Style(style.l_button)
|
||||
@@ -258,33 +261,33 @@ init 1 python:
|
||||
# Check boxes
|
||||
style.l_checkbox = Style(style.l_button)
|
||||
style.l_checkbox.left_padding = INDENT
|
||||
|
||||
|
||||
def checkbox(full, color):
|
||||
if full:
|
||||
return im.Twocolor("checkbox_full.png", color, color, yalign=0.5)
|
||||
else:
|
||||
return im.Twocolor("checkbox_empty.png", color, color, yalign=0.5)
|
||||
|
||||
|
||||
style.l_checkbox.background = checkbox(False, IDLE)
|
||||
style.l_checkbox.hover_background = checkbox(False, HOVER)
|
||||
style.l_checkbox.selected_idle_background = checkbox(True, IDLE)
|
||||
style.l_checkbox.selected_hover_background = checkbox(True, HOVER)
|
||||
style.l_checkbox.insensitive_background = checkbox(False, DISABLED)
|
||||
|
||||
|
||||
style.l_checkbox_text = Style(style.l_button_text)
|
||||
style.l_checkbox_text.selected_font = LIGHT
|
||||
|
||||
|
||||
# A normal button that lines up with checkboxes.
|
||||
style.l_nonbox = Style(style.l_button)
|
||||
style.l_nonbox.xpadding = INDENT
|
||||
style.l_nonbox_text = Style(style.l_button_text)
|
||||
style.l_nonbox_text.selected_font = LIGHT
|
||||
|
||||
|
||||
# A progress bar and its frame.
|
||||
style.l_progress_frame = Style(style.l_default)
|
||||
style.l_progress_frame.background = Frame(PATTERN, 0, 0, tile=True)
|
||||
style.l_progress_frame.ypadding = 5
|
||||
|
||||
|
||||
style.l_progress_bar = Style(style.l_default)
|
||||
style.l_progress_bar.left_bar = REVERSE_IDLE
|
||||
style.l_progress_bar.right_bar = Null()
|
||||
@@ -293,3 +296,8 @@ init 1 python:
|
||||
# The projects window.
|
||||
style.l_projects = Style(style.l_default)
|
||||
style.l_projects.background = PROJECTS_WINDOW
|
||||
|
||||
style.hyperlink_text.size = 18
|
||||
style.hyperlink_text.font = LIGHT
|
||||
style.hyperlink_text.color = IDLE
|
||||
style.hyperlink_text.hover_color = HOVER
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
|
||||
init python:
|
||||
|
||||
class FileTail(object):
|
||||
|
||||
def __init__(self, filename, lines=8):
|
||||
self.filename = filename
|
||||
self.text = ""
|
||||
self.lines = lines
|
||||
|
||||
def update(self):
|
||||
|
||||
try:
|
||||
with open(self.filename) as f:
|
||||
text = f.read()
|
||||
text = text.strip()
|
||||
text = text.split("\n")
|
||||
|
||||
newtext = [ ]
|
||||
for l in text:
|
||||
|
||||
if "\r" in l:
|
||||
_head, _sep, l = l.rpartition("\r")
|
||||
|
||||
while l:
|
||||
newtext.append(l[:100])
|
||||
l = l[100:]
|
||||
|
||||
text = newtext
|
||||
text = text[-self.lines:]
|
||||
text = "\n".join(text)
|
||||
|
||||
if text != self.text:
|
||||
self.text = text
|
||||
renpy.restart_interaction()
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@ init python in theme_data:
|
||||
|
||||
x = 0
|
||||
correct_section = False
|
||||
|
||||
|
||||
while x < len(lines):
|
||||
l = lines[x]
|
||||
|
||||
m = re.match(r'^screen\s+\w+\s*:\s*$', l)
|
||||
if m:
|
||||
correct_section = False
|
||||
|
||||
|
||||
m = re.match(r'^screen\s+file_picker\s*:\s*$', l)
|
||||
if m:
|
||||
correct_section = True
|
||||
|
||||
|
||||
if correct_section:
|
||||
m = re.match(r'^\s+\$\s*columns\s*=\s*(\d+)\s*$', l)
|
||||
if m:
|
||||
@@ -28,7 +28,7 @@ init python in theme_data:
|
||||
m = re.match(r'^\s+\$\s*rows\s*=\s*(\d+)\s*$', l)
|
||||
if m:
|
||||
l = l.replace(str(m.group(1)), str(file_picker_rows))
|
||||
|
||||
|
||||
lines[x] = l
|
||||
|
||||
x = x + 1
|
||||
@@ -37,7 +37,7 @@ init python in theme_data:
|
||||
|
||||
def roundrect_screen_ops(lines):
|
||||
return __PerformScreenOperations(lines)
|
||||
|
||||
|
||||
def awt_screen_ops(lines):
|
||||
return __PerformScreenOperations(lines, file_picker_rows=3)
|
||||
|
||||
@@ -49,12 +49,12 @@ init python in theme_data:
|
||||
|
||||
# The set of theme functions.
|
||||
THEME_FUNCTIONS = set()
|
||||
|
||||
|
||||
# theme name -> function name to call to munge screens.rpy as appropriate
|
||||
# for that theme.
|
||||
THEME_SCREEN_OPERATIONS = { }
|
||||
|
||||
# Color schemes that work (technically - some are eye-melting) with the
|
||||
|
||||
# Color schemes that work (technically - some are eye-melting) with the
|
||||
# roundrect-style themes.
|
||||
ROUNDRECT_SCHEMES = {
|
||||
'Basic Blue': {'disabled': '#404040',
|
||||
@@ -337,7 +337,7 @@ init python in theme_data:
|
||||
'widget_hover': '#b38698',
|
||||
'widget_selected': '#fffeed',
|
||||
'widget_text': '#ffffff'},
|
||||
|
||||
|
||||
'Watermelon': {'disabled': '#f9cdad',
|
||||
'disabled_text': '#fc9d9a',
|
||||
'frame': '#f9cdad',
|
||||
@@ -462,11 +462,11 @@ init python in theme_data:
|
||||
("Marker", "marker"),
|
||||
("Crayon", "crayon"),
|
||||
]
|
||||
|
||||
|
||||
ROUNDRECT_CODE = """theme.%(function)s(
|
||||
## Theme: %(theme)s
|
||||
## Color scheme: %(scheme)s
|
||||
|
||||
|
||||
## The color of an idle widget face.
|
||||
widget = "%(widget)s",
|
||||
|
||||
@@ -480,7 +480,7 @@ init python in theme_data:
|
||||
## example, the current value of a preference.)
|
||||
widget_selected = "%(widget_selected)s",
|
||||
|
||||
## The color of a disabled widget face.
|
||||
## The color of a disabled widget face.
|
||||
disabled = "%(disabled)s",
|
||||
|
||||
## The color of disabled widget text.
|
||||
@@ -508,9 +508,9 @@ init python in theme_data:
|
||||
|
||||
## And we're done with the theme. The theme will customize
|
||||
## various styles, so if we want to change them, we should
|
||||
## do so below.
|
||||
## do so below.
|
||||
)"""
|
||||
|
||||
|
||||
for theme, function in ROUNDRECT_VARIANTS:
|
||||
THEME[theme] = { }
|
||||
THEME_FUNCTIONS.add(function)
|
||||
@@ -521,13 +521,13 @@ init python in theme_data:
|
||||
subs["function"] = function
|
||||
subs["theme"] = theme
|
||||
subs["scheme"] = scheme
|
||||
|
||||
|
||||
THEME[theme][scheme] = ROUNDRECT_CODE % (subs)
|
||||
|
||||
AWT_CODE = """theme.a_white_tulip(
|
||||
## Theme: A White Tulip
|
||||
## Scheme %(scheme)s
|
||||
|
||||
|
||||
## The color of an idle widget face.
|
||||
widget = "%(widget)s",
|
||||
|
||||
@@ -538,7 +538,7 @@ init python in theme_data:
|
||||
## example, the current value of a preference.)
|
||||
widget_selected = "%(widget_selected)s",
|
||||
|
||||
## The color of a disabled widget face.
|
||||
## The color of a disabled widget face.
|
||||
disabled = "%(disabled)s",
|
||||
|
||||
## The color of a frame containing widgets.
|
||||
@@ -556,9 +556,9 @@ init python in theme_data:
|
||||
|
||||
## And we're done with the theme. The theme will customize
|
||||
## various styles, so if we want to change them, we should
|
||||
## do so below.
|
||||
## do so below.
|
||||
)"""
|
||||
|
||||
|
||||
THEME["A White Tulip"] = { }
|
||||
THEME_FUNCTIONS.add("a_white_tulip")
|
||||
THEME_SCREEN_OPERATIONS["A White Tulip"] = awt_screen_ops
|
||||
@@ -567,7 +567,7 @@ init python in theme_data:
|
||||
for scheme, colors in ROUNDRECT_SCHEMES.iteritems():
|
||||
subs = dict(colors)
|
||||
subs["scheme"] = scheme
|
||||
|
||||
|
||||
THEME["A White Tulip"][scheme] = AWT_CODE % (subs)
|
||||
|
||||
THEME["A White Tulip"]["A White Tulip"] = AWT_CODE % dict(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# This is used on Linux and Mac to prompt the user for the projects
|
||||
# This is used on Linux and Mac to prompt the user for the projects
|
||||
# directory.
|
||||
|
||||
import sys
|
||||
@@ -18,9 +18,9 @@ except ImportError:
|
||||
|
||||
# Create the TK canvas.
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == "__main__":
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
|
||||
result = askdirectory(initialdir=sys.argv[1], parent=root, title="Select Ren'Py Projects Directory")
|
||||
sys.stdout.write(result)
|
||||
sys.stdout.write(result)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
MTLc3m.ttf is destributed under Apache License 2.0.
|
||||
--------------------------------
|
||||
|
||||
Copyright (C) 2008 The Android Open Source Project
|
||||
Copyright (C) 2010 MOTOYA CO.,LTD.
|
||||
|
||||
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.
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
|
||||
translate japanese 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 japanese 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"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# game/android.rpy:12
|
||||
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パッケージをビルドするためには{a=http://www.renpy.org/dl/android}RAPT{/a}をダウンロードして解凍し、Ren'Py ディレクトリーに配置してからランチャーを再起動してください。"
|
||||
|
||||
# game/android.rpy:13
|
||||
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パッケージをビルドする前に Android SDK もインストールする必要があります。このためにSDKをインストールしてください。"
|
||||
|
||||
# game/android.rpy:14
|
||||
old "RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore."
|
||||
new "RAPT はインストールされましたが、キーが設定されていません。新しいキーを作成するか、android.keystore を復帰させてください。"
|
||||
|
||||
# game/android.rpy:15
|
||||
old "The current project has not been configured. Use \"Configure\" to configure it before building."
|
||||
new "現在のプロジェクトは設定されていません。「設定」を利用してビルド前に設定してください。"
|
||||
|
||||
# game/android.rpy:16
|
||||
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:18
|
||||
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 Phoneをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみです。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
|
||||
|
||||
# game/android.rpy:19
|
||||
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 tabletをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみです。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
|
||||
|
||||
# game/android.rpy:20
|
||||
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 "Android OUYAをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
|
||||
|
||||
# game/android.rpy:22
|
||||
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:23
|
||||
old "Configures the package name, version, and other information about this project."
|
||||
new "このプロジェクトについてパッケージ名、バージョン、その他の情報を設定してください。"
|
||||
|
||||
# game/android.rpy:24
|
||||
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 key を含むファイルをエディターで開いてください。\n\nこれはアプリが拡張APKを使用する場合のみ必要となります。詳細はドキュメントを参照してください。"
|
||||
|
||||
# game/android.rpy:25
|
||||
old "Builds the Android package."
|
||||
new "Androidパッケージをビルドします。"
|
||||
|
||||
# game/android.rpy:26
|
||||
old "Builds the Android package, and installs it on an Android device connected to your computer."
|
||||
new "Androidパッケージをビルドし、コンピューターに接続されたAndroidデバイスにインストールします。"
|
||||
|
||||
# game/android.rpy:142
|
||||
old "{a=%s}%s{/a}"
|
||||
new "{a=%s}%s{/a}"
|
||||
|
||||
# game/android.rpy:151
|
||||
old "QUESTION"
|
||||
new "質問"
|
||||
|
||||
# game/android.rpy:351
|
||||
old "Android: [project.current.name!q]"
|
||||
new "Android: [project.current.name!q]"
|
||||
|
||||
# game/android.rpy:371
|
||||
old "Emulation:"
|
||||
new "エミュレーター:"
|
||||
|
||||
# game/android.rpy:379
|
||||
old "Phone"
|
||||
new "Phone"
|
||||
|
||||
# game/android.rpy:383
|
||||
old "Tablet"
|
||||
new "Tablet"
|
||||
|
||||
# game/android.rpy:387
|
||||
old "Television / OUYA"
|
||||
new "Television / OUYA"
|
||||
|
||||
# game/android.rpy:399
|
||||
old "Build:"
|
||||
new "ビルド:"
|
||||
|
||||
# game/android.rpy:407
|
||||
old "Install SDK & Create Keys"
|
||||
new "SDKのインストール & キーの作成"
|
||||
|
||||
# game/android.rpy:411
|
||||
old "Configure"
|
||||
new "設定"
|
||||
|
||||
# game/android.rpy:415
|
||||
old "Build Package"
|
||||
new "パッケージのビルド"
|
||||
|
||||
# game/android.rpy:419
|
||||
old "Build & Install"
|
||||
new "ビルド & インストール"
|
||||
|
||||
# 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 "Windowsでは、Androidパッケージのビルドに32-bitのJava開発キットが必要です。JDKはJREとは異なるため、JDKが無くてもJavaが利用できます。\n\n{a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}JDKのダウンロードとインストール{/a}を行い、Ren'Pyランチャーを再起動して下さい。"
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
translate japanese 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,312 @@
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# renpy/common/00action_file.rpy:124
|
||||
old "%b %d, %H:%M"
|
||||
new "%m月%d日, %H:%M"
|
||||
|
||||
# renpy/common/00action_file.rpy:587
|
||||
old "Quick save complete."
|
||||
new "クイックセーブ完了。"
|
||||
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# renpy/common/00gallery.rpy:521
|
||||
old "Image [index] of [count] locked."
|
||||
new "画像 [index] / [count] はロックされています。"
|
||||
|
||||
# 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 japanese 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の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 japanese strings:
|
||||
|
||||
# renpy/common/00keymap.rpy:168
|
||||
old "Saved screenshot as %s."
|
||||
new "スクリーンショットを %s に保存しました。"
|
||||
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# renpy/common/00layout.rpy:421
|
||||
old "Are you sure?"
|
||||
new "本当にいいですか?"
|
||||
|
||||
# renpy/common/00layout.rpy:422
|
||||
old "Are you sure you want to delete this save?"
|
||||
new "この保存データを本当に削除しますか?"
|
||||
|
||||
# renpy/common/00layout.rpy:423
|
||||
old "Are you sure you want to overwrite your save?"
|
||||
new "本当に保存データを上書きしますか?"
|
||||
|
||||
# renpy/common/00layout.rpy:424
|
||||
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
|
||||
new "読み込みによって未保存のゲームが失われます。\n本当に読み込みますか?"
|
||||
|
||||
# renpy/common/00layout.rpy:425
|
||||
old "Are you sure you want to quit?"
|
||||
new "本当にゲームを終了しますか?"
|
||||
|
||||
# renpy/common/00layout.rpy:426
|
||||
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
|
||||
new "本当にメインメニューに戻りますか?\nこれによって未保存のゲームが失われます。"
|
||||
|
||||
# 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 japanese strings:
|
||||
|
||||
# renpy/common/00library.rpy:77
|
||||
old "Skip Mode"
|
||||
new "スキップモード"
|
||||
|
||||
# renpy/common/00library.rpy:80
|
||||
old "Fast Skip Mode"
|
||||
new "高速スキップモード"
|
||||
|
||||
|
||||
translate japanese 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 japanese 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 japanese strings:
|
||||
|
||||
# renpy/common/_compat/preferences.rpym:411
|
||||
old "Joystick Mapping"
|
||||
new "ジョイスティックのマッピング"
|
||||
|
||||
|
||||
translate japanese 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 japanese 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"
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# game/distribute.rpy:335
|
||||
old "Nothing to do."
|
||||
new "何もしません。"
|
||||
|
||||
# game/distribute.rpy:339
|
||||
old "Scanning project files..."
|
||||
new "プロジェクトをスキャンしています…"
|
||||
|
||||
# game/distribute.rpy:346
|
||||
old "Scanning Ren'Py files..."
|
||||
new "Ren'Pyファイルをスキャンしています…"
|
||||
|
||||
# game/distribute.rpy:496
|
||||
old "Archiving files..."
|
||||
new "ファイルをアーカイブしています…"
|
||||
|
||||
# game/distribute.rpy:747
|
||||
old "Writing the [variant] [format] package."
|
||||
new "[variant] [format] パッケージを書き出しています。."
|
||||
|
||||
# game/distribute.rpy:760
|
||||
old "Making the [variant] update zsync file."
|
||||
new "[variant] のアップデート用 zsync ファイルを書き出しています。"
|
||||
|
||||
# game/distribute.rpy:856
|
||||
old "Processed {b}[complete]{/b} of {b}[total]{/b} files."
|
||||
new "{b}[total]{/b} 中 {b}[complete]{/b} ファイルが処理されました。"
|
||||
|
||||
# game/distribute.rpy:917
|
||||
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やMacintosh用の配布物の解凍、再圧縮はサポートされません。"
|
||||
|
||||
# game/distribute.rpy:358
|
||||
old "No packages are selected, so there's nothing to do."
|
||||
new "パッケージが選択されていないため、何もすることがありません。"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
translate japanese 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,58 @@
|
||||
|
||||
translate japanese 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は現在中国、韓国、日本語の入力に必要な IME のサポートに欠陥があります。LinuxではEditraはwxpythonを必要とします。"
|
||||
|
||||
# game/editor.rpy:137
|
||||
old "This 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 "22MB までのダウンロードが必要です。"
|
||||
|
||||
# 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:423
|
||||
old "Select Editor"
|
||||
new "エディターを選択"
|
||||
|
||||
# game/editor.rpy:438
|
||||
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:460
|
||||
old "Cancel"
|
||||
new "キャンセル"
|
||||
|
||||
|
||||
translate japanese 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のテキストエディターの実行を停止します。"
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# game/front_page.rpy:67
|
||||
old "refresh"
|
||||
new "更新"
|
||||
|
||||
# game/front_page.rpy:94
|
||||
old "+ Create New Project"
|
||||
new "+ 新規プロジェクトの作成"
|
||||
|
||||
# game/front_page.rpy:106
|
||||
old "Launch Project"
|
||||
new "プロジェクトの起動"
|
||||
|
||||
# game/front_page.rpy:127
|
||||
old "Tutorial"
|
||||
new "Tutorial"
|
||||
|
||||
# game/front_page.rpy:128
|
||||
old "The Question"
|
||||
new "The Question"
|
||||
|
||||
# game/front_page.rpy:144
|
||||
old "Active Project"
|
||||
new "アクティブなプロジェクト"
|
||||
|
||||
# game/front_page.rpy:152
|
||||
old "Open Directory"
|
||||
new "ディレクトリーを開く"
|
||||
|
||||
# game/front_page.rpy:157
|
||||
old "game"
|
||||
new "game"
|
||||
|
||||
# game/front_page.rpy:158
|
||||
old "base"
|
||||
new "base"
|
||||
|
||||
# game/front_page.rpy:164
|
||||
old "Edit File"
|
||||
new "ファイル編集"
|
||||
|
||||
# game/front_page.rpy:172
|
||||
old "All script files"
|
||||
new "すべてのスクリプト"
|
||||
|
||||
# game/front_page.rpy:181
|
||||
old "Navigate Script"
|
||||
new "スクリプトのナビゲート"
|
||||
|
||||
# game/front_page.rpy:192
|
||||
old "Check Script (Lint)"
|
||||
new "スクリプトチェック(Lint)"
|
||||
|
||||
# game/front_page.rpy:193
|
||||
old "Change Theme"
|
||||
new "テーマ変更"
|
||||
|
||||
# game/front_page.rpy:194
|
||||
old "Delete Persistent"
|
||||
new "永続データ削除"
|
||||
|
||||
# game/front_page.rpy:202
|
||||
old "Build Distributions"
|
||||
new "配布物のビルド"
|
||||
|
||||
# game/front_page.rpy:204
|
||||
old "Android"
|
||||
new "Android"
|
||||
|
||||
# game/front_page.rpy:205
|
||||
old "Generate Translations"
|
||||
new "翻訳の生成"
|
||||
|
||||
# game/front_page.rpy:206
|
||||
old "Extract Dialogue"
|
||||
new "台詞の抽出"
|
||||
|
||||
# game/front_page.rpy:222
|
||||
old "Checking script for potential problems..."
|
||||
new "潜在的な問題のためにスクリプトをチェックしています…"
|
||||
|
||||
# game/front_page.rpy:237
|
||||
old "Deleting persistent data..."
|
||||
new "永続データを削除しています…"
|
||||
|
||||
# game/front_page.rpy:122
|
||||
old "[p.name!q] (template)"
|
||||
new "[p.name!q] (テンプレート)"
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
translate japanese 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 "About"
|
||||
|
||||
# game/interface.rpy:99
|
||||
old "update"
|
||||
new "アップデート"
|
||||
|
||||
# game/interface.rpy:101
|
||||
old "preferences"
|
||||
new "設定"
|
||||
|
||||
# game/interface.rpy:102
|
||||
old "quit"
|
||||
new "終了"
|
||||
|
||||
# game/interface.rpy:174
|
||||
old "Yes"
|
||||
new "Yes"
|
||||
|
||||
# game/interface.rpy:176
|
||||
old "No"
|
||||
new "No"
|
||||
|
||||
# game/interface.rpy:211
|
||||
old "Due to package format limitations, non-ASCII file and directory names are not allowed."
|
||||
new "パッケージフォーマットの制限により、アスキーコード以外のファイル、ディレクトリー名は許可されません。"
|
||||
|
||||
# game/interface.rpy:213
|
||||
old "[title]"
|
||||
new "[title]"
|
||||
|
||||
# game/interface.rpy:299
|
||||
old "ERROR"
|
||||
new "エラー"
|
||||
|
||||
# game/interface.rpy:328
|
||||
old "While [what!q], an error occured:"
|
||||
new "[what!q] 中にエラーが発生しました。:"
|
||||
|
||||
# game/interface.rpy:329
|
||||
old "[exception!q]"
|
||||
new "[exception!q]"
|
||||
|
||||
# game/interface.rpy:347
|
||||
old "Text input may not contain the {{ or [[ characters."
|
||||
new "{{ または [[ はテキスト入力出来ません。"
|
||||
|
||||
# game/interface.rpy:352
|
||||
old "File and directory names may not contain / or \\."
|
||||
new "ファイル、ディレクトリーが / または \\. を含んでいるかもしれません。"
|
||||
|
||||
# game/interface.rpy:358
|
||||
old "File and directory names must consist of ASCII characters."
|
||||
new "ファイル、ディレクトリー名はアスキーコードの文字列で構成される必要があります。"
|
||||
|
||||
# game/interface.rpy:379
|
||||
old "INFORMATION"
|
||||
new "情報"
|
||||
|
||||
# game/interface.rpy:422
|
||||
old "PROCESSING"
|
||||
new "処理中"
|
||||
|
||||
# game/interface.rpy:452
|
||||
old "CHOICE"
|
||||
new "選択"
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
translate japanese 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: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 "TODO"
|
||||
|
||||
# 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 "TODOコメントは見つかりません。\n\n作成には \"# TODO\" をスクリプトに加えてください。"
|
||||
|
||||
# game/navigation.rpy:238
|
||||
old "The list of names is empty."
|
||||
new "名前のリストは空です。"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
translate japanese 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. The template sets the default font and the user interface language. If your language is not supported, choose 'english'."
|
||||
new "新しいプロジェクトで使用するテンプレートを選択してください。Ren'Pyはデフォルトのフォントとユーザーインターフェイスの言語を設定します。あなたの言語がサポートされていないなら 'english' を選択してください。"
|
||||
|
||||
# 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] は既に存在します。違う名前を選択してください。"
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
translate japanese 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 "言語:"
|
||||
|
||||
# game/preferences.rpy:146
|
||||
old "Show templates"
|
||||
new "テンプレートの表示"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
translate japanese strings:
|
||||
|
||||
# game/project.rpy:204
|
||||
old "Ren'Py is scanning the project..."
|
||||
new "Ren'Py プロジェクトをスキャンしています…"
|
||||
|
||||
# game/project.rpy:503
|
||||
old "PROJECTS DIRECTORY"
|
||||
new "プロジェクトディレクトリー"
|
||||
|
||||
# game/project.rpy:503
|
||||
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:503
|
||||
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:543
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory."
|
||||
new "Ren'Py はプロジェクトディレクトリーを選択するために tkinter でpythonを実行することは出来ません。"
|
||||
|
||||
# game/project.rpy:547
|
||||
old "Ren'Py has set the projects directory to:"
|
||||
new "Ren'Py は以下にプロジェクトディレクトリーを設定します:"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
translate japanese python:
|
||||
MTLC = "tl/japanese/MTLc3m.ttf"
|
||||
style.l_default.font = MTLC
|
||||
style.l_default.size = 16
|
||||
style.l_button_text.selected_font = MTLC
|
||||
style.l_button_text.selected_bold = True
|
||||
style.l_link_text.font = MTLC
|
||||
style.l_alternate_text.font = MTLC
|
||||
style.l_navigation_button_text.font = MTLC
|
||||
style.l_navigation_text.font = MTLC
|
||||
style.l_navigation_text.bold = True
|
||||
style.l_checkbox_text.selected_font = MTLC
|
||||
style.l_nonbox_text.selected_font = MTLC
|
||||
style.hyperlink_text.font = MTLC
|
||||
make_style_backup()
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
translate japanese 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] の翻訳ファイルを生成しました。"
|
||||
|
||||
# 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,87 @@
|
||||
|
||||
translate japanese 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の次期バージョンのプレビューですが、\nゲームの最終リリースには向きません。"
|
||||
|
||||
# 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の試験的なバージョンです。開発者に頼まれない限りこのバージョンを使用するべきではありません。"
|
||||
|
||||
# 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 "続行"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/about.rpy:21
|
||||
old "[version!q]"
|
||||
new "[version!q]"
|
||||
|
||||
# game/about.rpy:25
|
||||
old "View license"
|
||||
new "Ver licencia"
|
||||
@@ -0,0 +1,21 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/add_file.rpy:7
|
||||
old "FILENAME"
|
||||
new "Nombre del archivo"
|
||||
|
||||
# game/add_file.rpy:7
|
||||
old "Enter the name of the script file to create."
|
||||
new "Introduce el nombre del archivo de script para crearlo."
|
||||
|
||||
# game/add_file.rpy:10
|
||||
old "The filename must have the .rpy extension."
|
||||
new "El nombre del archivo debe tener la extensión .rpy."
|
||||
|
||||
# game/add_file.rpy:18
|
||||
old "The file already exists."
|
||||
new "El archivo ya existe."
|
||||
|
||||
# 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 carga automaticamente todos los archivos que terminan en .rpy. Para usar este\n# archivo, defina una etiqueta y salte a el desde otro archivo\n"
|
||||
@@ -0,0 +1,105 @@
|
||||
translate spanish 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 "Se necesita Java Development Kit de 32-bit para construir paquetes de Android en Windows. El JDK es diferente al JRE, es posible que tenga Java sin tener el JDK.\n\nPor favor {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}descarga e instala el JDK{/a}, después, reinicia 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 "Para construir paquetes de Android, por favor descarga RAPT (desde {a=http://www.renpy.org/dl/android}aquí{/a}), descomprímelo y cópialo dentro de la carpeta de Ren'Py. Después reinicia el launcher de 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 está instalado, pero tendrás que instalar el SDK de Android para poder construir paquetes de Android. Selecciona instalar SDK para instalarlo."
|
||||
|
||||
# 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 está instalado, pero la clave aun no se ha configurado. Por favor crea una nueva clave, o restaura android.keystore."
|
||||
|
||||
# game/android.rpy:17
|
||||
old "The current project has not been configured. Use \"Configure\" to configure it before building."
|
||||
new "El proyecto actual no se ha configurado. Usa \"Configurar\" para configurarlo antes de construirlo."
|
||||
|
||||
# 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 "Selecciona \"Construir\" para construir el proyecto actual, o conecta un dispositivo Android y selecciona \"Construir & instalar\" para construirlo e instalarlo en el dispositivo."
|
||||
|
||||
# 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 "Al intentar emular un teléfono Android. \n\nLa entrada táctil se emula mediante el ratón, pero sólo cuando el botón se mantiene pulsado. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
|
||||
|
||||
# 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 "Al intentar emular una tablet Android. \n\nLa entrada táctil se emula mediante el ratón, pero sólo cuando el botón se mantiene pulsado. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
|
||||
|
||||
# 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 "Al intentar emular una consola OUYA. \n\nPara el control se usan las flechas, Intro está asignado al botón select. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
|
||||
|
||||
# game/android.rpy:23
|
||||
old "Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package."
|
||||
new "Descarga e instala el SDK de android y los paquetes de soporte. Opcionalmente, genera la clave necesaria para firmar el paquete."
|
||||
|
||||
# game/android.rpy:24
|
||||
old "Configures the package name, version, and other information about this project."
|
||||
new "Configura el nombre del paquete, la versión, y otra información de este proyecto."
|
||||
|
||||
# game/android.rpy:25
|
||||
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 "Abre el archivo que contiene las claves de Google Play en el editor. \n\nEsto sólo es necesario si la aplicación usa una expansión APK. Para más información lee la documentación."
|
||||
|
||||
# game/android.rpy:26
|
||||
old "Builds the Android package."
|
||||
new "Construir el paquete de Android."
|
||||
|
||||
# game/android.rpy:27
|
||||
old "Builds the Android package, and installs it on an Android device connected to your computer."
|
||||
new "Construye el paquete de Android, e instálalo en un dispositivo Android connectado a tu ordenador."
|
||||
|
||||
# game/android.rpy:148
|
||||
old "{a=%s}%s{/a}"
|
||||
new "{a=%s}%s{/a}"
|
||||
|
||||
# game/android.rpy:157
|
||||
old "QUESTION"
|
||||
new "PREGUNTA"
|
||||
|
||||
# game/android.rpy:367
|
||||
old "Android: [project.current.name!q]"
|
||||
new "Android: [project.current.name!q]"
|
||||
|
||||
# game/android.rpy:387
|
||||
old "Emulation:"
|
||||
new "Emulación:"
|
||||
|
||||
# game/android.rpy:395
|
||||
old "Phone"
|
||||
new "Teléfono"
|
||||
|
||||
# game/android.rpy:399
|
||||
old "Tablet"
|
||||
new "Tablet"
|
||||
|
||||
# game/android.rpy:403
|
||||
old "Television / OUYA"
|
||||
new "Televisión / OUYA"
|
||||
|
||||
# game/android.rpy:415
|
||||
old "Build:"
|
||||
new "Construir:"
|
||||
|
||||
# game/android.rpy:423
|
||||
old "Install SDK & Create Keys"
|
||||
new "Instalar SDK y Crear claves"
|
||||
|
||||
# game/android.rpy:427
|
||||
old "Configure"
|
||||
new "Configurar"
|
||||
|
||||
# game/android.rpy:431
|
||||
old "Build Package"
|
||||
new "Construir Paquete"
|
||||
|
||||
# game/android.rpy:435
|
||||
old "Build & Install"
|
||||
new "Construir & Instalar"
|
||||
@@ -0,0 +1,37 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/choose_theme.rpy:274
|
||||
old "Could not change the theme. Perhaps options.rpy was changed too much."
|
||||
new "No se puede cambiar el tema. Quizás options.rpy ha sufrido muchos cambios."
|
||||
|
||||
# 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 "Elegir Tema"
|
||||
|
||||
# game/choose_theme.rpy:389
|
||||
old "Theme"
|
||||
new "Tema"
|
||||
|
||||
# game/choose_theme.rpy:413
|
||||
old "Color Scheme"
|
||||
new "Combinación de colores"
|
||||
@@ -0,0 +1,322 @@
|
||||
#translation: renpy/common/00action_file.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00action_file.rpy:124
|
||||
old "%b %d, %H:%M"
|
||||
new "%d %b, %H:%M"
|
||||
|
||||
# renpy/common/00action_file.rpy:587
|
||||
old "Quick save complete."
|
||||
new "Guardado rapido completado"
|
||||
|
||||
|
||||
#translation: renpy/common/00gallery.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00gallery.rpy:521
|
||||
old "Image [index] of [count] locked."
|
||||
new "Imagen [index] de [count] bloqueada."
|
||||
|
||||
# renpy/common/00gallery.rpy:539
|
||||
old "prev"
|
||||
new "prev"
|
||||
|
||||
# renpy/common/00gallery.rpy:540
|
||||
old "next"
|
||||
new "siguiente"
|
||||
|
||||
# renpy/common/00gallery.rpy:541
|
||||
old "slideshow"
|
||||
new "presentación"
|
||||
|
||||
# renpy/common/00gallery.rpy:542
|
||||
old "return"
|
||||
new "volver"
|
||||
|
||||
|
||||
#translation: renpy/common/00gltest.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00gltest.rpy:50
|
||||
old "Graphics Acceleration"
|
||||
new "Aceleración Gráfica"
|
||||
|
||||
# renpy/common/00gltest.rpy:54
|
||||
old "Automatically Choose"
|
||||
new "Seleccionar automaticamente"
|
||||
|
||||
# renpy/common/00gltest.rpy:59
|
||||
old "Force Angle/DirectX Renderer"
|
||||
new "Forzar Angle/DirectX Renderer"
|
||||
|
||||
# renpy/common/00gltest.rpy:63
|
||||
old "Force OpenGL Renderer"
|
||||
new "Forzar OpenGL Renderer"
|
||||
|
||||
# renpy/common/00gltest.rpy:67
|
||||
old "Force Software Renderer"
|
||||
new "Forzar renderización por software"
|
||||
|
||||
# renpy/common/00gltest.rpy:73
|
||||
old "Changes will take effect the next time this program is run."
|
||||
new "Los cambios tendrán efecto la próxima vez que este programa se ejecute."
|
||||
|
||||
# renpy/common/00gltest.rpy:77
|
||||
old "Quit"
|
||||
new "Salir"
|
||||
|
||||
# renpy/common/00gltest.rpy:82
|
||||
old "Return"
|
||||
new "Volver"
|
||||
|
||||
# renpy/common/00gltest.rpy:112
|
||||
old "Performance Warning"
|
||||
new "Advertencia de rendimiento"
|
||||
|
||||
# renpy/common/00gltest.rpy:117
|
||||
old "This computer is using software rendering."
|
||||
new "Este equipo usa renderización por software."
|
||||
|
||||
# renpy/common/00gltest.rpy:119
|
||||
old "This computer is not using shaders."
|
||||
new "Este equipo no utiliza shaders."
|
||||
|
||||
# renpy/common/00gltest.rpy:121
|
||||
old "This computer is displaying graphics slowly."
|
||||
new "Este equipo está mostrando gráficos lentamente."
|
||||
|
||||
# renpy/common/00gltest.rpy:123
|
||||
old "This computer has a problem displaying graphics: [problem]."
|
||||
new "Este equipo tiene un problema monstrando gráficos: [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 "Sus drivers gráficos pueden estar desactualizados o no funcionar correctamente. Esto puede ocasionar visualización de gráficos lenta o incorrecta. Actualizar DirectX podría solucionar este problema."
|
||||
|
||||
# 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 "Sus drivers gráficos pueden estar desactualizados o no funcionar correctamente. Esto puede ocasionar visualización de gráficos lenta o incorrecta."
|
||||
|
||||
# renpy/common/00gltest.rpy:135
|
||||
old "Update DirectX"
|
||||
new "Actualizar DirectX"
|
||||
|
||||
# renpy/common/00gltest.rpy:141
|
||||
old "Continue, Show this warning again"
|
||||
new "Continuar, Mostrar este aviso otra vez"
|
||||
|
||||
# renpy/common/00gltest.rpy:145
|
||||
old "Continue, Don't show warning again"
|
||||
new "Continuar, No mostrar este aviso otra vezn"
|
||||
|
||||
# renpy/common/00gltest.rpy:171
|
||||
old "Updating DirectX."
|
||||
new "Actualizando 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 "Se ha iniciado DirectX web setup. Puede inciiar minimizado en la barra de tareas. Por favor siga las instrucciones para instalar 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}Nota:{/b} Programa de instalación web de Microsoft DirectX, por defecto, instala la barra de herramientas de Bing. Si no quieres que se instale, desactiva la casilla correspondiente."
|
||||
|
||||
# renpy/common/00gltest.rpy:183
|
||||
old "When setup finishes, please click below to restart this program."
|
||||
new "Cuando finalize la configuración, por favor haga click abajo para reiniciar el programa."
|
||||
|
||||
# renpy/common/00gltest.rpy:185
|
||||
old "Restart"
|
||||
new "Reiniciar"
|
||||
|
||||
|
||||
#translation: renpy/common/00keymap.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00keymap.rpy:168
|
||||
old "Saved screenshot as %s."
|
||||
new "Screenshot guardada como %s."
|
||||
|
||||
|
||||
#translation: renpy/common/00layout.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00layout.rpy:421
|
||||
old "Are you sure?"
|
||||
new "¿Estás seguro?"
|
||||
|
||||
# renpy/common/00layout.rpy:422
|
||||
old "Are you sure you want to delete this save?"
|
||||
new "¿Seguro que quieres eliminar esta partida guardada?"
|
||||
|
||||
# renpy/common/00layout.rpy:423
|
||||
old "Are you sure you want to overwrite your save?"
|
||||
new "¿Seguro que quieres sobreescribir esta partida guardada?"
|
||||
|
||||
# renpy/common/00layout.rpy:424
|
||||
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
|
||||
new "Cargando, perderas el progreso no guardado. \n¿Seguro que quieres hacer esto?"
|
||||
|
||||
# renpy/common/00layout.rpy:425
|
||||
old "Are you sure you want to quit?"
|
||||
new "¿Seguro que quieres salir?"
|
||||
|
||||
# renpy/common/00layout.rpy:426
|
||||
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
|
||||
new "Seguro que quieres volver al menu principal?\nPerderas el progreso no guardado."
|
||||
|
||||
# renpy/common/00layout.rpy:427
|
||||
old "Are you sure you want to begin skipping?"
|
||||
new "Seguro que quieres comenzar a omitir?"
|
||||
|
||||
# renpy/common/00layout.rpy:428
|
||||
old "Are you sure you want to skip to the next choice?"
|
||||
new "¿Seguro que quieres saltarte la siguiente eleccion?"
|
||||
|
||||
# renpy/common/00layout.rpy:429
|
||||
old "Are you sure you want to skip to unseen dialogue or the next choice?"
|
||||
new "¿Seugro que quieres saltarte los diálogos no vistos o la sigueinte elección?"
|
||||
|
||||
|
||||
#translation: renpy/common/00library.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00library.rpy:77
|
||||
old "Skip Mode"
|
||||
new "Modo Salto"
|
||||
|
||||
# renpy/common/00library.rpy:80
|
||||
old "Fast Skip Mode"
|
||||
new "Modo de salto rápido"
|
||||
|
||||
|
||||
#translation: renpy/common/00updater.rpy
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/00updater.rpy:1258
|
||||
old "Updater"
|
||||
new "Actualizador"
|
||||
|
||||
# renpy/common/00updater.rpy:1267
|
||||
old "This program is up to date."
|
||||
new "Este programa está actualizado."
|
||||
|
||||
# renpy/common/00updater.rpy:1269
|
||||
old "[u.version] is available. Do you want to install it?"
|
||||
new "[u.version] está disponible. ¿Quieres instalarla?"
|
||||
|
||||
# renpy/common/00updater.rpy:1271
|
||||
old "Preparing to download the updates."
|
||||
new "Preparando para descargar las actualizaciones."
|
||||
|
||||
# renpy/common/00updater.rpy:1273
|
||||
old "Downloading the updates."
|
||||
new "Descargando actualizaciones."
|
||||
|
||||
# renpy/common/00updater.rpy:1275
|
||||
old "Unpacking the updates."
|
||||
new "Desempaquetando las actualizaciones."
|
||||
|
||||
# renpy/common/00updater.rpy:1279
|
||||
old "The updates have been installed. The program will restart."
|
||||
new "Se han instalado las actualizaciones. El programa se reiniciará."
|
||||
|
||||
# renpy/common/00updater.rpy:1281
|
||||
old "The updates have been installed."
|
||||
new "se han instalado las actualizaciones."
|
||||
|
||||
# renpy/common/00updater.rpy:1283
|
||||
old "The updates were cancelled."
|
||||
new "Se han cancelado las actualizaciones."
|
||||
|
||||
|
||||
#translation: renpy/common/_compat/gamemenu.rpym
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:180
|
||||
old "Empty Slot."
|
||||
new "Ranura vacía."
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:337
|
||||
old "Previous"
|
||||
new "Anterior"
|
||||
|
||||
# renpy/common/_compat/gamemenu.rpym:344
|
||||
old "Next"
|
||||
new "Siguiente"
|
||||
|
||||
|
||||
#translation: renpy/common/_compat/preferences.rpym
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/_compat/preferences.rpym:411
|
||||
old "Joystick Mapping"
|
||||
new "Asignar Joystick"
|
||||
|
||||
|
||||
#translation: renpy/common/_errorhandling.rpym
|
||||
translate spanish strings:
|
||||
|
||||
# renpy/common/_errorhandling.rpym:408
|
||||
old "An exception has occurred."
|
||||
new "Se ha producido una excepción."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:434
|
||||
old "Rollback"
|
||||
new "Regresar"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:436
|
||||
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
|
||||
new "Intente volver atŕas, le permitirá guardar o elegir una opción diferente."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:439
|
||||
old "Ignore"
|
||||
new "Ignorar"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:441
|
||||
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
|
||||
new "Ignora la excepción, le permite continuar. Esto suele conducir a errores adicionales."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:444
|
||||
old "Reload"
|
||||
new "recargar"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:446
|
||||
old "Reloads the game from disk, saving and restoring game state if possible."
|
||||
new "Vuelve a cargar el juego desde el disco. guarda y restaura el estado del juego si es posible."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:448
|
||||
old "Open Traceback"
|
||||
new "Abrir Traceback"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:450
|
||||
old "Opens the traceback.txt file in a text editor."
|
||||
new "Abrir el archivo traceback.txt en un editor de texto."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:456
|
||||
old "Quits the game."
|
||||
new "Salir del juego."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:483
|
||||
old "Parsing the script failed."
|
||||
new "Analizando el script fallido."
|
||||
|
||||
# renpy/common/_errorhandling.rpym:510
|
||||
old "Open Parse Errors"
|
||||
new "Abrir Analisis de Errores"
|
||||
|
||||
# renpy/common/_errorhandling.rpym:512
|
||||
old "Opens the errors.txt file in a text editor."
|
||||
new "Abre el archivo errors.txt en un editor de texto."
|
||||
|
||||
|
||||
#translation: renpy/common/_layout/classic_load_save.rpym
|
||||
translate spanish 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"
|
||||
@@ -0,0 +1,33 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/distribute.rpy:358
|
||||
old "No packages are selected, so there's nothing to do."
|
||||
new "Ningún paquete seleccionado. No hay nada que hacer."
|
||||
|
||||
# game/distribute.rpy:363
|
||||
old "Scanning project files..."
|
||||
new "Escaneando archivos del proyecto..."
|
||||
|
||||
# game/distribute.rpy:373
|
||||
old "Scanning Ren'Py files..."
|
||||
new "Escaneando los archivos de Ren'Py..."
|
||||
|
||||
# game/distribute.rpy:421
|
||||
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 "Se han construido todos los paquetes.\n\nDebido a la presencia de información de permisos, desempaquetar y reempaquetar las distribuciones para Linux y Macintosh no es compatible en Windows."
|
||||
|
||||
# game/distribute.rpy:545
|
||||
old "Archiving files..."
|
||||
new "Archivando archivos..."
|
||||
|
||||
# game/distribute.rpy:801
|
||||
old "Writing the [variant] [format] package."
|
||||
new "Escribiendo el paquete [format] para [variant]."
|
||||
|
||||
# game/distribute.rpy:814
|
||||
old "Making the [variant] update zsync file."
|
||||
new "Creando el archivo de actualización zsync para [variant]."
|
||||
|
||||
# game/distribute.rpy:910
|
||||
old "Processed {b}[complete]{/b} of {b}[total]{/b} files."
|
||||
new "Procesados {b}[complete]{/b} de {b}[total]{/b} archivos."
|
||||
@@ -0,0 +1,45 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/distribute_gui.rpy:139
|
||||
old "Build Distributions: [project.current.name!q]"
|
||||
new "Construir Distibuciones: [project.current.name!q]"
|
||||
|
||||
# game/distribute_gui.rpy:154
|
||||
old "Directory Name:"
|
||||
new "Nombre de la carpeta:"
|
||||
|
||||
# game/distribute_gui.rpy:158
|
||||
old "Executable Name:"
|
||||
new "Nombre del ejecutable:"
|
||||
|
||||
# game/distribute_gui.rpy:167
|
||||
old "Actions:"
|
||||
new "Acciones:"
|
||||
|
||||
# game/distribute_gui.rpy:175
|
||||
old "Edit options.rpy"
|
||||
new "Editar options.rpy"
|
||||
|
||||
# game/distribute_gui.rpy:176
|
||||
old "Refresh"
|
||||
new "Recargar"
|
||||
|
||||
# game/distribute_gui.rpy:193
|
||||
old "Build Packages:"
|
||||
new "Construir Paquetes:"
|
||||
|
||||
# game/distribute_gui.rpy:208
|
||||
old "Build Updates"
|
||||
new "Construir Actualizaciones"
|
||||
|
||||
# game/distribute_gui.rpy:212
|
||||
old "Build"
|
||||
new "Construir"
|
||||
|
||||
# game/distribute_gui.rpy:219
|
||||
old "Errors were detected when running the project. Please ensure the project runs without errors before building distributions."
|
||||
new "Se detectaron errores al ejecutar el proyecto. Por favor asegúrese de que el proyecto se ejecuta sin errores antes de construir distibuciones."
|
||||
|
||||
# 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 "Tu proyecto no tiene información de construcción. ¿Te gustaría añadir la información de construcción al final del archivo options.rpy?"
|
||||
@@ -0,0 +1,64 @@
|
||||
translate spanish strings:
|
||||
|
||||
# description for the option: "Editra"
|
||||
# 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}Recomendado.{/b} Un editor beta con una interfaz fácil de usar y funciones que ayudan en el desarrollo, como la corrección ortográfica. Editra actualmente carece de soporte IME necesario para la introducción de texto Chino, Japonés y Coreano."
|
||||
|
||||
# description for "Editra" on Linux
|
||||
# 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}Recomendado.{/b} Un editor beta con una interfaz fácil de usar y funciones que ayudan en el desarrollo, como la corrección ortográfica. Editra actualmente carece de soporte IME necesario para la introducción de texto Chino, Japonés y Coreano. En Linux, Editra requiere wxPython."
|
||||
|
||||
# game/editor.rpy:137
|
||||
old "This may have occured because wxPython is not installed on this system."
|
||||
new "Esto puede haber ocurrido porque wxPython no está instalado en este sistema."
|
||||
|
||||
# game/editor.rpy:144
|
||||
old "Up to 22 MB download required."
|
||||
new "Requiere descargar hasta 22 MB."
|
||||
|
||||
# description for the option: "JEdit"
|
||||
# game/editor.rpy:155
|
||||
old "A mature editor that requires Java."
|
||||
new "Un editor muy maduro que requiere Java."
|
||||
|
||||
# game/editor.rpy:157
|
||||
old "1.8 MB download required."
|
||||
new "Requiere descargar 1.8 MB."
|
||||
|
||||
# game/editor.rpy:158
|
||||
old "This may have occured because Java is not installed on this system."
|
||||
new "Esto puede haber ocurrido porque Java no está instalado en este sistema"
|
||||
|
||||
# option: "System Editor"
|
||||
# game/editor.rpy:163
|
||||
old "System Editor"
|
||||
new "Editor del sistema"
|
||||
|
||||
# description for the option: "System Editor"
|
||||
# game/editor.rpy:164
|
||||
old "Invokes the editor your operating system has associated with .rpy files."
|
||||
new "Usar el editor de su sistema operativo para que se asocie con los archivos .rpy."
|
||||
|
||||
# option: "None"
|
||||
# game/editor.rpy:179
|
||||
old "None"
|
||||
new "Ninguno"
|
||||
|
||||
# description for the option: "None"
|
||||
# game/editor.rpy:180
|
||||
old "Prevents Ren'Py from opening a text editor."
|
||||
new "Evita que Ren'Py abra un editor de texto."
|
||||
|
||||
# game/editor.rpy:327
|
||||
old "An exception occured while launching the text editor:\n[exception!q]"
|
||||
new "Ha ocurrido una excepción mientras se ejecutaba el editor de texto:\[exception!q]"
|
||||
|
||||
# game/editor.rpy:423
|
||||
old "Select Editor"
|
||||
new "Seleccionar Editor"
|
||||
|
||||
# game/editor.rpy:438
|
||||
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 "Un editor de texto es el programa que vas a utilizar para editar los scripts de Ren'Py. Aquí, puedes seleccionar el editor que Ren'Py usará. Si no está disponible, el editor se descargará e instalará automáticamente."
|
||||
@@ -0,0 +1,93 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/font_page.rpy 65
|
||||
old "PROJECTS:"
|
||||
new "PROYECTOS:"
|
||||
|
||||
# game/front_page.rpy:67
|
||||
old "refresh"
|
||||
new "recargar"
|
||||
|
||||
# game/front_page.rpy:94
|
||||
old "+ Create New Project"
|
||||
new "+ Crear Un Proyecto Nuevo"
|
||||
|
||||
# game/front_page.rpy:106
|
||||
old "Launch Project"
|
||||
new "Ejecutar Proyecto"
|
||||
|
||||
# game/front_page.rpy:122
|
||||
old "[p.name!q] (template)"
|
||||
new "[p.name!q] (plantilla)"
|
||||
|
||||
# game/front_page.rpy:127
|
||||
old "Tutorial"
|
||||
new "Tutorial"
|
||||
|
||||
# game/front_page.rpy:128
|
||||
old "The Question"
|
||||
new "The Question"
|
||||
|
||||
# game/front_page.rpy:144
|
||||
old "Active Project"
|
||||
new "Proyecto Activo"
|
||||
|
||||
# game/front_page.rpy:152
|
||||
old "Open Directory"
|
||||
new "Abrir Carpeta"
|
||||
|
||||
# game/front_page.rpy:157
|
||||
old "game"
|
||||
new "game"
|
||||
|
||||
# game/front_page.rpy:158
|
||||
old "base"
|
||||
new "base"
|
||||
|
||||
# game/front_page.rpy:164
|
||||
old "Edit File"
|
||||
new "Editar Archivo"
|
||||
|
||||
# game/front_page.rpy:172
|
||||
old "All script files"
|
||||
new "Todos los scripts"
|
||||
|
||||
# game/front_page.rpy:181
|
||||
old "Navigate Script"
|
||||
new "Navegar por los Scripts"
|
||||
|
||||
# game/front_page.rpy:192
|
||||
old "Check Script (Lint)"
|
||||
new "Comprobar Script (Lint)"
|
||||
|
||||
# game/front_page.rpy:193
|
||||
old "Change Theme"
|
||||
new "Cambiar Tema"
|
||||
|
||||
# game/front_page.rpy:194
|
||||
old "Delete Persistent"
|
||||
new "Eliminar Datos Persistentes"
|
||||
|
||||
# game/front_page.rpy:202
|
||||
old "Build Distributions"
|
||||
new "Construir Distibuciones"
|
||||
|
||||
# game/front_page.rpy:204
|
||||
old "Android"
|
||||
new "Android"
|
||||
|
||||
# game/front_page.rpy:205
|
||||
old "Generate Translations"
|
||||
new "Generar Traducciones"
|
||||
|
||||
# game/front_page.rpy:206
|
||||
old "Extract Dialogue"
|
||||
new "Extraer Diálogos"
|
||||
|
||||
# game/front_page.rpy:222
|
||||
old "Checking script for potential problems..."
|
||||
new "Comprobando script por problemas potenciales..."
|
||||
|
||||
# game/front_page.rpy:237
|
||||
old "Deleting persistent data..."
|
||||
new "Eliminando datos persistentes..."
|
||||
@@ -0,0 +1,93 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/interface.rpy:89
|
||||
old "Documentation"
|
||||
new "Documentación"
|
||||
|
||||
# game/interface.rpy:90
|
||||
old "Ren'Py Website"
|
||||
new "Web de Ren'Py"
|
||||
|
||||
# game/interface.rpy:91
|
||||
old "Ren'Py Games List"
|
||||
new "Lista de juegos Ren'Py"
|
||||
|
||||
# game/interface.rpy:92
|
||||
old "About"
|
||||
new "Acerca de"
|
||||
|
||||
# game/interface.rpy:99
|
||||
old "update"
|
||||
new "actualizar"
|
||||
|
||||
# game/interface.rpy:101
|
||||
old "preferences"
|
||||
new "preferencias"
|
||||
|
||||
# game/interface.rpy:102
|
||||
old "quit"
|
||||
new "salir"
|
||||
|
||||
# game/interface.rpy:174
|
||||
old "Yes"
|
||||
new "Sí"
|
||||
|
||||
# game/interface.rpy:176
|
||||
old "No"
|
||||
new "No"
|
||||
|
||||
# game/interface.rpy:182
|
||||
old "Back"
|
||||
new "Atrás"
|
||||
|
||||
# game/interface.rpy:184
|
||||
old "Cancel"
|
||||
new "Cancelar"
|
||||
|
||||
# game/interface.rpy:187
|
||||
old "Continue"
|
||||
new "Continuar"
|
||||
|
||||
# game/interface.rpy:211
|
||||
old "Due to package format limitations, non-ASCII file and directory names are not allowed."
|
||||
new "Debido a las limitaciones del formato de paquete, no se permite el uso de nombres de archivos y carpetas que no sean ASCII"
|
||||
|
||||
# game/interface.rpy:213
|
||||
old "[title]"
|
||||
new "[title]"
|
||||
|
||||
# game/interface.rpy:299
|
||||
old "ERROR"
|
||||
new "ERROR"
|
||||
|
||||
# game/interface.rpy:328
|
||||
old "While [what!q], an error occured:"
|
||||
new "Mientras [what!q], se produjo un error:"
|
||||
|
||||
# game/interface.rpy:329
|
||||
old "[exception!q]"
|
||||
new "[exception!q]"
|
||||
|
||||
# game/interface.rpy:347
|
||||
old "Text input may not contain the {{ or [[ characters."
|
||||
new "La entrada de texto no puede contener los caracteres {{ o [[."
|
||||
|
||||
# game/interface.rpy:352
|
||||
old "File and directory names may not contain / or \\."
|
||||
new "Los nombres de archivos y carpetas no pueden contener / o \\."
|
||||
|
||||
# game/interface.rpy:358
|
||||
old "File and directory names must consist of ASCII characters."
|
||||
new "Los nombres de archivos y carpetas deben ser caracteres ASCII."
|
||||
|
||||
# game/interface.rpy:379
|
||||
old "INFORMATION"
|
||||
new "INFORMACIÓN"
|
||||
|
||||
# game/interface.rpy:422
|
||||
old "PROCESSING"
|
||||
new "PROCESANDO"
|
||||
|
||||
# game/interface.rpy:452
|
||||
old "CHOICE"
|
||||
new "SELECCIONA"
|
||||
@@ -0,0 +1,65 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/navigation.rpy:150
|
||||
old "Navigate: [project.current.name]"
|
||||
new "Navegando por: [project.current.name]"
|
||||
|
||||
# game/navigation.rpy:159
|
||||
old "Order: "
|
||||
new "Orden: "
|
||||
|
||||
# game/navigation.rpy:160
|
||||
old "alphabetical"
|
||||
new "alfabético"
|
||||
|
||||
# game/navigation.rpy:162
|
||||
old "by-file"
|
||||
new "por archivo"
|
||||
|
||||
# game/navigation.rpy:164
|
||||
old "natural"
|
||||
new "natural"
|
||||
|
||||
# game/navigation.rpy:176
|
||||
old "Category:"
|
||||
new "Categoría:"
|
||||
|
||||
# game/navigation.rpy:178
|
||||
old "files"
|
||||
new "archivos"
|
||||
|
||||
# game/navigation.rpy:179
|
||||
old "labels"
|
||||
new "Etiquetas"
|
||||
|
||||
# game/navigation.rpy:180
|
||||
old "defines"
|
||||
new "defines"
|
||||
|
||||
# game/navigation.rpy:181
|
||||
old "transforms"
|
||||
new "transforms"
|
||||
|
||||
# game/navigation.rpy:182
|
||||
old "screens"
|
||||
new "pantallas"
|
||||
|
||||
# game/navigation.rpy:183
|
||||
old "callables"
|
||||
new "callables"
|
||||
|
||||
# game/navigation.rpy:184
|
||||
old "TODOs"
|
||||
new "TODO"
|
||||
|
||||
# game/navigation.rpy:223
|
||||
old "+ Add script file"
|
||||
new "+ Añadir archivo de script"
|
||||
|
||||
# game/navigation.rpy:231
|
||||
old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
|
||||
new "No se han encontrado comentarios \"TODO\". Para crear uno, incluye \"# TODO\" en tu script."
|
||||
|
||||
# game/navigation.rpy:238
|
||||
old "The list of names is empty."
|
||||
new "La lista de nombres está vacía."
|
||||
@@ -0,0 +1,29 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/new_project.rpy:22
|
||||
old "Choose Project Template"
|
||||
new "Elige una plantilla para el proyecto"
|
||||
|
||||
# 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 "Por favor selecciona una plantilla para usar en tu nuevo proyecto. La plantilla establece la fuente predeterminada y el idioma de la interfaz de usuario, Si tu idioma no está soportado, elige \"English\"."
|
||||
|
||||
# game/new_project.rpy:55
|
||||
old "PROJECT NAME"
|
||||
new "NOMBRE DEL PROYECTO"
|
||||
|
||||
# game/new_project.rpy:56
|
||||
old "Please enter the name of your project:"
|
||||
new "Por favor introduce el nombre de tu proyecto:"
|
||||
|
||||
# game/new_project.rpy:62
|
||||
old "The project name may not be empty."
|
||||
new "El nombre del proyecto no puede estar vacío."
|
||||
|
||||
# game/new_project.rpy:67
|
||||
old "[project_name!q] already exists. Please choose a different project name."
|
||||
new "[project_name!q] ya existe. Por favor elige un nombre diferente para el proyecto."
|
||||
|
||||
# game/new_project.rpy:70
|
||||
old "[project_dir!q] already exists. Please choose a different project name."
|
||||
new "[project_dir!q] ya existe. Por favor elige un nombre diferente para el proyecto."
|
||||
@@ -0,0 +1,61 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/preferences.rpy:40
|
||||
old "Launcher Preferences"
|
||||
new "Preferencias del Launcher"
|
||||
|
||||
# game/preferences.rpy:61
|
||||
old "Projects Directory:"
|
||||
new "Carpeta de Proyectos:"
|
||||
|
||||
# game/preferences.rpy:68
|
||||
old "[persistent.projects_directory!q]"
|
||||
new "[persistent.projects_directory!q]"
|
||||
|
||||
# game/preferences.rpy:70
|
||||
old "Not Set"
|
||||
new "No establecido"
|
||||
|
||||
# game/preferences.rpy:84
|
||||
old "Text Editor:"
|
||||
new "Editor de texto:"
|
||||
|
||||
# game/preferences.rpy:106
|
||||
old "Update Channel:"
|
||||
new "Canal de actualización"
|
||||
|
||||
# game/preferences.rpy:126
|
||||
old "Navigation Options:"
|
||||
new "Opciones de navegación:"
|
||||
|
||||
# game/preferences.rpy:130
|
||||
old "Include private names"
|
||||
new "Incluir nombres privados"
|
||||
|
||||
# game/preferences.rpy:131
|
||||
old "Include library names"
|
||||
new "Incluir nombres de bibliotecas"
|
||||
|
||||
# game/preferences.rpy:141
|
||||
old "Launcher Options:"
|
||||
new "Opciones del Launcher:"
|
||||
|
||||
# game/preferences.rpy:145
|
||||
old "Hardware rendering"
|
||||
new "Renderización por hardware"
|
||||
|
||||
# game/preferences.rpy:146
|
||||
old "Show templates"
|
||||
new "Mostrar plantillas"
|
||||
|
||||
# game/preferences.rpy:148
|
||||
old "Console output"
|
||||
new "Salida de la consola"
|
||||
|
||||
# game/preferences.rpy:169
|
||||
old "Open launcher project"
|
||||
new "Abrir el launcher"
|
||||
|
||||
# game/preferences.rpy:183
|
||||
old "Language:"
|
||||
new "Idioma:"
|
||||
@@ -0,0 +1,25 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/project.rpy:204
|
||||
old "Ren'Py is scanning the project..."
|
||||
new "Ren'Py está escaneando el proyecto..."
|
||||
|
||||
# game/project.rpy:503
|
||||
old "PROJECTS DIRECTORY"
|
||||
new "CARPETA DEL PROYECTO"
|
||||
|
||||
# game/project.rpy:503
|
||||
old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
|
||||
new "Por favor elige la carpeta del proyecto usando el selector de proyecto. \n{b}El selector de carpetas puede haberse abierto detrás de esta ventana."
|
||||
|
||||
# game/project.rpy:503
|
||||
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 "El launcher buscará proyectos en esta carpeta, creará nuevos proyectos en esta carpeta, y colocará los proyectos en este directorio."
|
||||
|
||||
# game/project.rpy:543
|
||||
old "Ren'Py was unable to run python with tkinter to choose the projects directory."
|
||||
new "Ren'Py ha podido ejecutar python con tkinter para elegir el directorio de proyectos."
|
||||
|
||||
# game/project.rpy:547
|
||||
old "Ren'Py has set the projects directory to:"
|
||||
new "Ren'Py ha establecido el directorio de proyectos:"
|
||||
@@ -0,0 +1,3 @@
|
||||
translate spanish python:
|
||||
|
||||
make_style_backup()
|
||||
@@ -0,0 +1,33 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/translations.rpy:10
|
||||
old "Create or Update Translations"
|
||||
new "Crear o Actualizar Traducciones"
|
||||
|
||||
# game/translations.rpy:10
|
||||
old "Please enter the name of the language for which you want to create or update translations."
|
||||
new "Por favor introduce el nombre del idioma para el que desea crear o actualizar una traducción."
|
||||
|
||||
# game/translations.rpy:15
|
||||
old "The language name can not be the empty string."
|
||||
new "El nombre del idioma no puede estar vacío."
|
||||
|
||||
# game/translations.rpy:26
|
||||
old "Ren'Py is generating translations...."
|
||||
new "Ren'Py está generando las traducciones..."
|
||||
|
||||
# game/translations.rpy:30
|
||||
old "Ren'Py has finished generating [language] translations."
|
||||
new "Ren'Py ha terminado de generar las traducciones [language]"
|
||||
|
||||
# game/translations.rpy:44
|
||||
old "What format would you like for the extracted dialogue?"
|
||||
new "¿Qué formato te gustaría para los diálogos extraidos?"
|
||||
|
||||
# game/translations.rpy:56
|
||||
old "Ren'Py is extracting dialogue...."
|
||||
new "Ren'Py está extrayendo los diálogos..."
|
||||
|
||||
# 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 ha terminado de extraer los diálogos. Los diálogo extraídos se pueden encontrar en el dialogue.[format] en el directorio base."
|
||||
@@ -0,0 +1,85 @@
|
||||
translate spanish strings:
|
||||
|
||||
# game/updater.rpy:54
|
||||
old "Select Update Channel"
|
||||
new "Selecciona el Canal de Actualización"
|
||||
|
||||
# game/updater.rpy:65
|
||||
old "The update channel controls the version of Ren'Py the updater will download. Please select an update channel:"
|
||||
new "El canal de actualización controla la versión de Ren'Py que el actualizador descargará. Por favor selecciona un canal de actualización:"
|
||||
|
||||
# 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}Recomendado.{/b} La versión the Ren'Py que se recomienda usar en todos los juegos recién liberados."
|
||||
|
||||
# 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 "Una vista previa de la próxima versión de Ren'Py que puede ser utilizada para probar y aprovechar las nuevas características, pero no para las versiones finales de los juegos."
|
||||
|
||||
# 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 "Versiones experimentales de Ren'Py. No debes seleccionar el canal a menos que te lo pida un desarrollador de Ren'Py."
|
||||
|
||||
# game/updater.rpy:119
|
||||
old "An error has occured:"
|
||||
new "Ha ocurrido un error:"
|
||||
|
||||
# game/updater.rpy:121
|
||||
old "Checking for updates."
|
||||
new "Comprobando actualizaciones."
|
||||
|
||||
# game/updater.rpy:123
|
||||
old "Ren'Py is up to date."
|
||||
new "Ren'Py está actualizado."
|
||||
|
||||
# game/updater.rpy:125
|
||||
old "[u.version] is now available. Do you want to install it?"
|
||||
new "[u.version] ahora está disponible. ¿Quieres instalarla?"
|
||||
|
||||
# game/updater.rpy:127
|
||||
old "Preparing to download the update."
|
||||
new "Preparando para descargar la actualización."
|
||||
|
||||
# game/updater.rpy:129
|
||||
old "Downloading the update."
|
||||
new "Descargando la actualización."
|
||||
|
||||
# game/updater.rpy:131
|
||||
old "Unpacking the update."
|
||||
new "Descomprimiendo la actualización."
|
||||
|
||||
# game/updater.rpy:133
|
||||
old "Finishing up."
|
||||
new "Finalizar."
|
||||
|
||||
# game/updater.rpy:135
|
||||
old "The update has been installed. Ren'Py will restart."
|
||||
new "La actualización se ha instalado. Ren'Py se reiniciará."
|
||||
|
||||
# game/updater.rpy:137
|
||||
old "The update has been installed."
|
||||
new "La actualización se ha instalado."
|
||||
|
||||
# game/updater.rpy:139
|
||||
old "The update was cancelled."
|
||||
new "Se ha cancelado la actualización."
|
||||
|
||||
# game/updater.rpy:156
|
||||
old "Ren'Py Update"
|
||||
new "Actualizar Ren'Py"
|
||||
|
||||
# game/updater.rpy:162
|
||||
old "Proceed"
|
||||
new "Seguir"
|
||||
@@ -8,27 +8,56 @@ label translate:
|
||||
python:
|
||||
|
||||
language = interface.input(_("Create or Update Translations"), _("Please enter the name of the language for which you want to create or update translations."), filename=True, default=persistent.translate_language, cancel=Jump("front_page"))
|
||||
|
||||
|
||||
language = language.strip()
|
||||
|
||||
|
||||
if not language:
|
||||
interface.error(_("The language name can not be the empty string."))
|
||||
|
||||
|
||||
persistent.translate_language = language
|
||||
|
||||
|
||||
args = [ "translate", language ]
|
||||
|
||||
if language == "rot13":
|
||||
args.append("--rot13")
|
||||
else:
|
||||
args.append("--empty")
|
||||
|
||||
|
||||
interface.processing(_("Ren'Py is generating translations...."))
|
||||
project.current.launch(args, wait=True)
|
||||
project.current.update_dump(force=True)
|
||||
|
||||
interface.info(_("Ren'Py has finished generating [language] translations."))
|
||||
|
||||
|
||||
jump front_page
|
||||
|
||||
label extract_dialogue:
|
||||
|
||||
python:
|
||||
|
||||
CHOICES = [
|
||||
("tab", "Tab-delimited Spreadsheet (dialogue.tab)"),
|
||||
("txt", "Dialogue Text Only (dialogue.txt)"),
|
||||
]
|
||||
|
||||
format = interface.choice(
|
||||
_("What format would you like for the extracted dialogue?"),
|
||||
CHOICES,
|
||||
persistent.dialogue_format,
|
||||
cancel=Jump("front_page"))
|
||||
|
||||
persistent.dialogue_format = format
|
||||
|
||||
args = [ "dialogue" ]
|
||||
|
||||
if format == "txt":
|
||||
args.append("--text")
|
||||
|
||||
interface.processing(_("Ren'Py is extracting dialogue...."))
|
||||
project.current.launch(args, wait=True)
|
||||
project.current.update_dump(force=True)
|
||||
|
||||
interface.info(_("Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[format] in the base directory."))
|
||||
|
||||
|
||||
jump front_page
|
||||
|
||||
|
||||
+32
-32
@@ -6,80 +6,80 @@ init python:
|
||||
#
|
||||
# It must be None for a release.
|
||||
UPDATE_SIMULATE = None
|
||||
|
||||
|
||||
PUBLIC_KEY = "renpy_public.pem"
|
||||
|
||||
|
||||
UPDATE_URLS = {
|
||||
"Release" : "http://update.renpy.org/release/updates.json",
|
||||
"Prerelease" : "http://update.renpy.org/prerelease/updates.json",
|
||||
"Experimental" : "http://update.renpy.org/experimental/updates.json"
|
||||
"Experimental" : "http://update.renpy.org/experimental/updates.json"
|
||||
}
|
||||
|
||||
|
||||
version_tuple = renpy.version(tuple=True)
|
||||
|
||||
|
||||
DLC_URL = "http://update.renpy.org/{0}.{1}.{2}/updates.json".format(version_tuple[0], version_tuple[1], version_tuple[2])
|
||||
|
||||
|
||||
if persistent.update_channel not in UPDATE_URLS:
|
||||
persistent.update_channel = "Release"
|
||||
|
||||
def check_dlc(name):
|
||||
|
||||
def check_dlc(name):
|
||||
"""
|
||||
Returns true if the named dlc package is present.
|
||||
"""
|
||||
|
||||
|
||||
return name in updater.get_installed_packages()
|
||||
|
||||
|
||||
def add_dlc(name):
|
||||
"""
|
||||
Adds the DLC package, if it doesn't already exist.
|
||||
|
||||
|
||||
Returns True if the DLC is installed, False otherwise.
|
||||
"""
|
||||
|
||||
|
||||
if check_dlc(name):
|
||||
return True
|
||||
|
||||
|
||||
return renpy.invoke_in_new_context(updater.update, DLC_URL, add=[name], public_key=PUBLIC_KEY, simulate=UPDATE_SIMULATE, restart=False)
|
||||
|
||||
screen update_channel:
|
||||
|
||||
|
||||
frame:
|
||||
style_group "l"
|
||||
style "l_root"
|
||||
|
||||
|
||||
window:
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
label _("Select Update Channel")
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
hbox:
|
||||
frame:
|
||||
style "l_indent"
|
||||
xfill True
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
text _("The update channel controls the version of Ren'Py the updater will download. Please select an update channel:") style "l_small_text"
|
||||
|
||||
# Release
|
||||
add SPACER
|
||||
|
||||
|
||||
textbutton _("Release") action [ SetField(persistent, "update_channel", "Release"), Jump("preferences") ]
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
text _("{b}Recommended.{/b} The version of Ren'Py that should be used in all newly-released games.") style "l_small_text"
|
||||
|
||||
# Prerelease
|
||||
add SPACER
|
||||
|
||||
|
||||
textbutton _("Prerelease") action [ SetField(persistent, "update_channel", "Prerelease"), Jump("preferences") ]
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame:
|
||||
@@ -91,14 +91,14 @@ screen update_channel:
|
||||
add SPACER
|
||||
|
||||
textbutton _("Experimental") action [ SetField(persistent, "update_channel", "Experimental"), Jump("preferences") ]
|
||||
|
||||
|
||||
add HALF_SPACER
|
||||
|
||||
frame:
|
||||
style "l_indent"
|
||||
text _("Experimental versions of Ren'Py. You shouldn't select this channel unless asked by a Ren'Py developer.") style "l_small_text"
|
||||
|
||||
|
||||
|
||||
textbutton _("Cancel") action Jump("preferences") style "l_left_button"
|
||||
|
||||
label update_preference:
|
||||
@@ -106,13 +106,13 @@ label update_preference:
|
||||
return
|
||||
|
||||
screen updater:
|
||||
|
||||
|
||||
frame:
|
||||
style "l_root"
|
||||
|
||||
frame:
|
||||
style_group "l_info"
|
||||
|
||||
|
||||
has vbox
|
||||
|
||||
if u.state == u.ERROR:
|
||||
@@ -144,10 +144,10 @@ screen updater:
|
||||
|
||||
if u.progress is not None:
|
||||
add SPACER
|
||||
|
||||
|
||||
frame:
|
||||
style "l_progress_frame"
|
||||
|
||||
|
||||
bar:
|
||||
range 1.0
|
||||
value u.progress
|
||||
@@ -157,15 +157,15 @@ screen updater:
|
||||
|
||||
if u.can_cancel:
|
||||
textbutton _("Cancel") action u.cancel style "l_left_button"
|
||||
|
||||
|
||||
if u.can_proceed:
|
||||
textbutton _("Proceed") action u.proceed style "l_right_button"
|
||||
|
||||
label update:
|
||||
|
||||
|
||||
python:
|
||||
updater.update(UPDATE_URLS[persistent.update_channel], simulate=UPDATE_SIMULATE, public_key=PUBLIC_KEY)
|
||||
|
||||
|
||||
# This should never happen.
|
||||
jump front_page
|
||||
|
||||
|
||||
@@ -3,28 +3,28 @@
|
||||
|
||||
init python in util:
|
||||
import os
|
||||
|
||||
|
||||
def walk(directory, base=None):
|
||||
"""
|
||||
Walks through the directories and files underneath `directory`,
|
||||
yielding (name, isdir) tuples. The names are given relative to
|
||||
Walks through the directories and files underneath `directory`,
|
||||
yielding (name, isdir) tuples. The names are given relative to
|
||||
`base`, which defaults to `directory` if None.
|
||||
"""
|
||||
|
||||
directory = renpy.fsdecode(directory)
|
||||
|
||||
|
||||
if base is None:
|
||||
base = directory
|
||||
else:
|
||||
base = renpy.fsdecode(base)
|
||||
|
||||
|
||||
for subdir, directories, files in os.walk(directory):
|
||||
for fn in directories:
|
||||
fullfn = os.path.join(subdir, fn)
|
||||
relfn = os.path.relpath(fullfn, base)
|
||||
|
||||
|
||||
relfn = relfn.replace("\\", "/")
|
||||
|
||||
|
||||
yield relfn, True
|
||||
|
||||
for fn in files:
|
||||
@@ -32,6 +32,6 @@ init python in util:
|
||||
relfn = os.path.relpath(fullfn, base)
|
||||
|
||||
relfn = relfn.replace("\\", "/")
|
||||
|
||||
|
||||
yield relfn, False
|
||||
|
||||
|
||||
|
||||
+23
-23
@@ -36,34 +36,34 @@ cdef extern from "renpy.h":
|
||||
void core_init()
|
||||
|
||||
void save_png_core(object, SDL_RWops *, int)
|
||||
|
||||
|
||||
void pixellate32_core(object, object, int, int, int, int)
|
||||
void pixellate24_core(object, object, int, int, int, int)
|
||||
|
||||
void map32_core(object, object,
|
||||
char *,
|
||||
char *,
|
||||
char *,
|
||||
char *,
|
||||
char *,
|
||||
char *)
|
||||
|
||||
void map24_core(object, object,
|
||||
char *,
|
||||
char *,
|
||||
char *,
|
||||
char *)
|
||||
|
||||
void linmap32_core(object, object,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int)
|
||||
|
||||
void linmap24_core(object, object,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int)
|
||||
|
||||
void xblur32_core(object, object, int)
|
||||
|
||||
|
||||
void alphamunge_core(object, object, int, int, int, char *)
|
||||
|
||||
void scale32_core(object, object,
|
||||
@@ -93,9 +93,9 @@ cdef extern from "renpy.h":
|
||||
int, int, int, int, int, char *)
|
||||
|
||||
int subpixel32(object, object, float, float, int)
|
||||
|
||||
|
||||
void PyErr_Clear()
|
||||
|
||||
|
||||
|
||||
import pygame
|
||||
|
||||
@@ -108,7 +108,7 @@ def save_png(surf, file, compress=-1):
|
||||
|
||||
save_png_core(surf, RWopsFromPython(file), compress)
|
||||
|
||||
|
||||
|
||||
def pixellate(pysrc, pydst, avgwidth, avgheight, outwidth, outheight):
|
||||
|
||||
if not isinstance(pysrc, PygameSurface):
|
||||
@@ -231,7 +231,7 @@ def alpha_munge(pysrc, pydst, srcchan, dstchan, amap):
|
||||
# pydst.unlock()
|
||||
# pysrc.unlock()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# def xblur(pysrc, pydst, radius):
|
||||
@@ -283,7 +283,7 @@ def alpha_munge(pysrc, pydst, srcchan, dstchan, amap):
|
||||
# w, h = pysrc.get_size()
|
||||
|
||||
# return stretch_core(pysrc, pydst, x, y, w, h)
|
||||
|
||||
|
||||
|
||||
def bilinear(pysrc, pydst,
|
||||
source_xoff=0.0, source_yoff=0.0, source_width=None, source_height=None,
|
||||
@@ -298,7 +298,7 @@ def bilinear(pysrc, pydst,
|
||||
|
||||
if pysrc.get_bitsize() not in (24, 32):
|
||||
raise Exception("bilinear requires a 24 or 32 bit surface.")
|
||||
|
||||
|
||||
if pydst.get_bitsize() != pysrc.get_bitsize():
|
||||
raise Exception("bilinear requires both surfaces have the same bitsize.")
|
||||
|
||||
@@ -332,15 +332,15 @@ def check(surf):
|
||||
|
||||
if surf.get_bitsize() != 32:
|
||||
raise Exception("Surface must be 32-bit.")
|
||||
|
||||
|
||||
|
||||
|
||||
def transform(pysrc, pydst,
|
||||
corner_x, corner_y,
|
||||
xdx, ydx, xdy, ydy, a=1.0, precise=0):
|
||||
|
||||
check(pysrc)
|
||||
check(pydst)
|
||||
|
||||
|
||||
# pysrc.lock()
|
||||
# pydst.lock()
|
||||
|
||||
@@ -359,7 +359,7 @@ def blend(pysrca, pysrcb, pydst, alpha):
|
||||
check(pysrca)
|
||||
check(pysrcb)
|
||||
check(pydst)
|
||||
|
||||
|
||||
# pysrca.lock()
|
||||
# pysrcb.lock()
|
||||
# pydst.lock()
|
||||
@@ -375,14 +375,14 @@ def imageblend(pysrca, pysrcb, pydst, pyimg, aoff, amap):
|
||||
check(pysrcb)
|
||||
check(pydst)
|
||||
check(pyimg)
|
||||
|
||||
|
||||
# pysrca.lock()
|
||||
# pysrcb.lock()
|
||||
# pydst.lock()
|
||||
# pyimg.lock()
|
||||
|
||||
imageblend32_core(pysrca, pysrcb, pydst, pyimg, aoff, amap)
|
||||
|
||||
|
||||
# pyimg.unlock()
|
||||
# pydst.unlock()
|
||||
# pysrcb.unlock()
|
||||
@@ -399,7 +399,7 @@ def colormatrix(pysrc, pydst,
|
||||
|
||||
# pysrc.lock()
|
||||
# pydst.lock()
|
||||
|
||||
|
||||
colormatrix32_core(pysrc, pydst,
|
||||
c00, c01, c02, c03, c04,
|
||||
c10, c11, c12, c13, c14,
|
||||
@@ -421,8 +421,8 @@ def subpixel(pysrc, pydst, xoffset, yoffset, shift):
|
||||
return
|
||||
|
||||
pydst.blit(pysrc, (int(xoffset), int(yoffset)))
|
||||
|
||||
|
||||
|
||||
|
||||
# Be sure to update scale.py when adding something new here!
|
||||
|
||||
import_pygame_rwobject()
|
||||
|
||||
@@ -16,7 +16,7 @@ RTL = FRIBIDI_TYPE_RTL
|
||||
WRTL = FRIBIDI_TYPE_WR
|
||||
|
||||
def log2vis(s, int direction=FRIBIDI_TYPE_ON):
|
||||
|
||||
|
||||
s = s.encode("utf8")
|
||||
s = renpybidi_log2vis(s, &direction)
|
||||
return s.decode("utf8"), direction
|
||||
|
||||
@@ -57,13 +57,13 @@ print "CLASSES = {"
|
||||
for i, j in enumerate((lines[0] + other_classes).split()):
|
||||
print " \"{}\" : {},".format(j, i)
|
||||
cl[j] = i
|
||||
|
||||
|
||||
print "}"
|
||||
|
||||
|
||||
rules = [ ]
|
||||
|
||||
for l in lines[1:]:
|
||||
for c in l.split()[1:]:
|
||||
for c in l.split()[1:]:
|
||||
rules.append(c)
|
||||
|
||||
print
|
||||
@@ -76,46 +76,46 @@ for l in file("LineBreak.txt"):
|
||||
if m:
|
||||
start = int(m.group(1), 16)
|
||||
end = int(m.group(2), 16)
|
||||
|
||||
if start > 65535:
|
||||
continue
|
||||
|
||||
if end > 65535:
|
||||
end = 65535
|
||||
|
||||
for i in range(start, end + 1):
|
||||
cc[i] = m.group(3)
|
||||
|
||||
continue
|
||||
|
||||
m = re.match("(\w+);(\w\w)", l)
|
||||
if m:
|
||||
start = int(m.group(1), 16)
|
||||
|
||||
if start > 65535:
|
||||
continue
|
||||
|
||||
cc[start] = m.group(2)
|
||||
|
||||
if end > 65535:
|
||||
end = 65535
|
||||
|
||||
for i in range(start, end + 1):
|
||||
cc[i] = m.group(3)
|
||||
|
||||
continue
|
||||
|
||||
m = re.match("(\w+);(\w\w)", l)
|
||||
if m:
|
||||
start = int(m.group(1), 16)
|
||||
|
||||
if start > 65535:
|
||||
continue
|
||||
|
||||
cc[start] = m.group(2)
|
||||
continue
|
||||
|
||||
def generate(name, func):
|
||||
|
||||
|
||||
ncc = [ ]
|
||||
|
||||
|
||||
for i, ccl in enumerate(cc):
|
||||
ncc.append(func(i, ccl))
|
||||
|
||||
|
||||
assert "CJ" not in ncc
|
||||
assert "AI" not in ncc
|
||||
|
||||
|
||||
print "cdef char *break_" + name + " = \"" + "".join("\\x%02x" % cl[i] for i in ncc) + "\""
|
||||
|
||||
|
||||
def western(i, cl):
|
||||
if cl == "CJ":
|
||||
return "ID"
|
||||
elif cl == "AI":
|
||||
return "AL"
|
||||
|
||||
|
||||
return cl
|
||||
|
||||
hyphens = [ 0x2010, 0x2013, 0x301c, 0x30a0 ]
|
||||
@@ -128,28 +128,28 @@ postfixes = [ 0x0025, 0x00A2, 0x00B0, 0x2030, 0x2032, 0x2033, 0x2103, 0xff05, 0x
|
||||
prefixes = [ 0x0024, 0x00a3, 0x00a5, 0x20ac, 0x2116, 0xff04, 0xffe1, 0xffe5 ]
|
||||
|
||||
def cjk_strict(i, cl):
|
||||
|
||||
|
||||
if cl == "CJ":
|
||||
return "NS"
|
||||
if cl == "AI":
|
||||
return "ID"
|
||||
|
||||
|
||||
return cl
|
||||
|
||||
def cjk_normal(i, cl):
|
||||
|
||||
|
||||
if i in hyphens:
|
||||
return "ID"
|
||||
|
||||
|
||||
if cl == "CJ":
|
||||
return "ID"
|
||||
if cl == "AI":
|
||||
return "ID"
|
||||
|
||||
|
||||
return cl
|
||||
|
||||
|
||||
def cjk_loose(i, cl):
|
||||
|
||||
|
||||
if i in hyphens:
|
||||
return "ID"
|
||||
if i in iteration:
|
||||
@@ -162,14 +162,14 @@ def cjk_loose(i, cl):
|
||||
return "ID"
|
||||
if i in prefixes:
|
||||
return "ID"
|
||||
|
||||
|
||||
if cl == "CJ":
|
||||
return "ID"
|
||||
if cl == "AI":
|
||||
return "ID"
|
||||
|
||||
|
||||
return cl
|
||||
|
||||
|
||||
generate("western", western)
|
||||
generate("cjk_strict", cjk_strict)
|
||||
generate("cjk_normal", cjk_normal)
|
||||
|
||||
+35
-35
@@ -10,7 +10,7 @@ cdef extern from "pyfreetype.h":
|
||||
#Some tweaking may be needed on a platform-by-platform basis
|
||||
DEF FT_SIZEOF_INT = 4
|
||||
DEF FT_SIZEOF_LONG = 4
|
||||
|
||||
|
||||
ctypedef signed short FT_Int16
|
||||
ctypedef unsigned short FT_UInt16
|
||||
IF FT_SIZEOF_INT == 4:
|
||||
@@ -26,9 +26,9 @@ cdef extern from "pyfreetype.h":
|
||||
ELIF FT_SIZEOF_LONG >= 4:
|
||||
ctypedef long FT_Fast
|
||||
ctypedef unsigned long FT_UFast
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#fttypes.h
|
||||
ctypedef unsigned char FT_Bool
|
||||
ctypedef signed short FT_FWord
|
||||
@@ -140,15 +140,15 @@ cdef extern from "pyfreetype.h":
|
||||
(<unsigned long>c'l' << 16) |
|
||||
(<unsigned long>c'o' << 8) |
|
||||
(<unsigned long>c't'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#freetype.h
|
||||
ctypedef struct FT_Glyph_Metrics:
|
||||
FT_Pos width, height
|
||||
FT_Pos horiBearingX, horiBearingY, horiAdvance
|
||||
FT_Pos vertBearingX, vertBearingY, vertAdvance
|
||||
|
||||
|
||||
ctypedef struct FT_Bitmap_Size:
|
||||
FT_Short height, width
|
||||
FT_Pos size
|
||||
@@ -322,7 +322,7 @@ cdef extern from "pyfreetype.h":
|
||||
FT_Library library
|
||||
FT_Face face
|
||||
FT_GlyphSlot next
|
||||
FT_UInt reserved
|
||||
FT_UInt reserved
|
||||
FT_Generic generic
|
||||
|
||||
FT_Glyph_Metrics metrics
|
||||
@@ -361,7 +361,7 @@ cdef extern from "pyfreetype.h":
|
||||
FT_SIZE_REQUEST_TYPE_SCALES,
|
||||
|
||||
FT_SIZE_REQUEST_TYPE_MAX
|
||||
|
||||
|
||||
ctypedef struct FT_Size_RequestRec:
|
||||
FT_Size_Request_Type type
|
||||
FT_Long width, height
|
||||
@@ -397,7 +397,7 @@ cdef extern from "pyfreetype.h":
|
||||
|
||||
|
||||
void FT_Set_Transform(FT_Face face, FT_Matrix *matrix, FT_Vector *delta)
|
||||
|
||||
|
||||
ctypedef enum FT_Render_Mode:
|
||||
FT_RENDER_MODE_NORMAL = 0,
|
||||
FT_RENDER_MODE_LIGHT,
|
||||
@@ -438,7 +438,7 @@ cdef extern from "pyfreetype.h":
|
||||
void FT_Library_Version(FT_Library, FT_Int *major, FT_Int *minor, FT_Int *patch)
|
||||
FT_Bool FT_Face_CheckTrueTypePatents(FT_Face face)
|
||||
FT_Bool FT_Face_SetUnpatentedHinting(FT_Face face, FT_Bool value)
|
||||
|
||||
|
||||
|
||||
|
||||
#ftglyph.h
|
||||
@@ -447,7 +447,7 @@ cdef extern from "pyfreetype.h":
|
||||
FT_Glyph_Format format
|
||||
FT_Vector advance
|
||||
ctypedef FT_GlyphRec* FT_Glyph
|
||||
|
||||
|
||||
ctypedef struct FT_BitmapGlyphRec:
|
||||
FT_GlyphRec root
|
||||
FT_Int left, top
|
||||
@@ -475,7 +475,7 @@ cdef extern from "pyfreetype.h":
|
||||
void FT_Done_Glyph(FT_Glyph glyph)
|
||||
|
||||
void FT_Matrix_Multiply(FT_Matrix *a, FT_Matrix *b)
|
||||
FT_Error FT_Matrix_Invert(FT_Matrix *matrix)
|
||||
FT_Error FT_Matrix_Invert(FT_Matrix *matrix)
|
||||
|
||||
|
||||
|
||||
@@ -485,7 +485,7 @@ cdef extern from "pyfreetype.h":
|
||||
FT_Error FT_Outline_Done(FT_Library lib, FT_Outline *outline)
|
||||
FT_Error FT_Outline_Copy(FT_Outline *source, FT_Outline *target)
|
||||
FT_Error FT_Outline_Check(FT_Outline *outline)
|
||||
|
||||
|
||||
void FT_Outline_Get_CBox(FT_Outline *outline, FT_BBox *cbox)
|
||||
void FT_Outline_Translate(FT_Outline *outline, FT_Pos xOffset, FT_Pos yOffset)
|
||||
void FT_Outline_Transform(FT_Outline *outline, FT_Matrix *matrix)
|
||||
@@ -509,32 +509,32 @@ cdef extern from "pyfreetype.h":
|
||||
FT_Error FT_Bitmap_Copy(FT_Library lib, FT_Bitmap *source, FT_Bitmap *target)
|
||||
FT_Error FT_Bitmap_Embolden(FT_Library lib, FT_Bitmap *bitmap, FT_Pos xStrength, FT_Pos yStrength)
|
||||
FT_Error FT_Bitmap_Convert(FT_Library lib, FT_Bitmap *source, FT_Bitmap *target, FT_Int alignment)
|
||||
|
||||
|
||||
# Additions by Tom Rothame.
|
||||
|
||||
cdef struct FT_MemoryRec_
|
||||
cdef struct FT_MemoryRec_
|
||||
ctypedef FT_MemoryRec_ *FT_Memory
|
||||
|
||||
|
||||
ctypedef void * (*FT_AllocFunc)(FT_Memory, long)
|
||||
ctypedef void (*FT_FreeFunc)(FT_Memory, void *)
|
||||
ctypedef void * (*FT_Realloc_Func)(FT_Memory, long, long, void*)
|
||||
|
||||
|
||||
cdef struct FT_StreamRec_
|
||||
ctypedef FT_StreamRec_* FT_Stream
|
||||
|
||||
|
||||
cdef union FT_StreamDesc:
|
||||
long value
|
||||
void *pointer
|
||||
|
||||
|
||||
ctypedef unsigned long (*FT_Stream_IoFunc)(
|
||||
FT_Stream,
|
||||
unsigned long,
|
||||
unsigned char *,
|
||||
unsigned long)
|
||||
|
||||
|
||||
ctypedef void (*FT_Stream_CloseFunc)(
|
||||
FT_Stream stream)
|
||||
|
||||
|
||||
cdef struct FT_StreamRec_:
|
||||
unsigned char *base
|
||||
unsigned long size
|
||||
@@ -543,36 +543,36 @@ cdef extern from "pyfreetype.h":
|
||||
FT_StreamDesc pathname
|
||||
FT_Stream_IoFunc read
|
||||
FT_Stream_CloseFunc close
|
||||
|
||||
|
||||
FT_Memory memory
|
||||
unsigned char *cursor
|
||||
unsigned char *limit
|
||||
|
||||
|
||||
ctypedef FT_StreamRec_ FT_StreamRec
|
||||
|
||||
|
||||
cdef struct FT_ModuleRec_
|
||||
ctypedef FT_ModuleRec_ *FT_Module
|
||||
cdef struct FT_ParameterRec_
|
||||
cdef struct FT_ParameterRec_
|
||||
ctypedef struct FT_Parameter
|
||||
|
||||
|
||||
ctypedef struct FT_Open_Args:
|
||||
FT_UInt flags
|
||||
FT_Byte *memory_base
|
||||
FT_Long memory_size
|
||||
FT_String *pathname
|
||||
FT_Stream stream
|
||||
|
||||
|
||||
FT_Module driver
|
||||
FT_Int num_params
|
||||
FT_Parameter *params
|
||||
|
||||
|
||||
cdef enum:
|
||||
FT_OPEN_MEMORY
|
||||
FT_OPEN_STREAM
|
||||
FT_OPEN_PATHNAME
|
||||
FT_OPEN_DRIVER
|
||||
FT_OPEN_PARAMS
|
||||
|
||||
|
||||
FT_Error FT_Open_Face(
|
||||
FT_Library library,
|
||||
FT_Open_Args *args,
|
||||
@@ -581,10 +581,10 @@ cdef extern from "pyfreetype.h":
|
||||
|
||||
cdef struct FT_Stroker_Rec_
|
||||
ctypedef FT_Stroker_Rec_ *FT_Stroker
|
||||
|
||||
|
||||
FT_Error FT_Stroker_New( FT_Library library,
|
||||
FT_Stroker *astroker )
|
||||
|
||||
|
||||
cdef enum FT_Stroker_LineCap:
|
||||
FT_STROKER_LINECAP_ROUND
|
||||
cdef enum FT_Stroker_LineJoin:
|
||||
@@ -595,11 +595,11 @@ cdef extern from "pyfreetype.h":
|
||||
FT_Stroker_LineCap line_cap,
|
||||
FT_Stroker_LineJoin line_join,
|
||||
FT_Fixed miter_limit )
|
||||
|
||||
|
||||
void FT_Glyph_StrokeBorder(FT_Glyph *, FT_Stroker, FT_Bool, FT_Bool)
|
||||
|
||||
|
||||
void FT_Stroker_Done(FT_Stroker)
|
||||
|
||||
|
||||
cdef FT_Long FT_MulFix(FT_Long, FT_Long)
|
||||
cdef FT_Long FT_CEIL(FT_Long)
|
||||
cdef FT_Long FT_FLOOR(FT_Long)
|
||||
|
||||
@@ -5,19 +5,17 @@ cdef extern from "pygame/pygame.h":
|
||||
int pitch
|
||||
int flags
|
||||
void *pixels
|
||||
|
||||
|
||||
struct SDL_Rect:
|
||||
int x
|
||||
int y
|
||||
int w
|
||||
int h
|
||||
|
||||
|
||||
SDL_Surface *PySurface_AsSurface(object)
|
||||
int SDL_SetAlpha(SDL_Surface *surface, unsigned int flag, char alpha)
|
||||
|
||||
|
||||
enum:
|
||||
SDL_SRCALPHA
|
||||
|
||||
|
||||
cdef extern int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect) nogil
|
||||
|
||||
|
||||
+10
-10
@@ -1805,7 +1805,7 @@ def generate_tegl():
|
||||
constant("DOT3_RGB")
|
||||
constant("DOT3_RGBA")
|
||||
constant("CLAMP_TO_BORDER")
|
||||
|
||||
|
||||
if GL_ARB_MULTITEXTURE:
|
||||
constant("TEXTURE0_ARB")
|
||||
constant("TEXTURE1_ARB")
|
||||
@@ -2537,7 +2537,7 @@ class gltype(object):
|
||||
|
||||
def __init__(self, s):
|
||||
self.type = s
|
||||
|
||||
|
||||
def __getitem__(self, n):
|
||||
return gltype(self.type + " *")
|
||||
|
||||
@@ -2546,7 +2546,7 @@ class gltype(object):
|
||||
|
||||
def __str__(self):
|
||||
return self.type
|
||||
|
||||
|
||||
GLenum = gltype("GLenum")
|
||||
GLboolean = gltype("GLboolean")
|
||||
GLbitfield = gltype("GLbitfield")
|
||||
@@ -2573,7 +2573,7 @@ GLcharARB = gltype("GLchar")
|
||||
def declare(*args):
|
||||
global is_enum
|
||||
is_enum = False
|
||||
|
||||
|
||||
args = list(args)
|
||||
|
||||
if isinstance(args[0], gltype):
|
||||
@@ -2587,7 +2587,7 @@ def declare(*args):
|
||||
type,
|
||||
name,
|
||||
", ".join(str(i) for i in args))
|
||||
|
||||
|
||||
constants = [ ]
|
||||
|
||||
def constant(name):
|
||||
@@ -2628,24 +2628,24 @@ cdef inline gl_check(where):
|
||||
renpy.display.log.write("GL error 0x%X at %s", error, where)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
out = sys.stdout
|
||||
out.write(HEADER)
|
||||
|
||||
generate_tegl()
|
||||
constant("BGRA")
|
||||
|
||||
|
||||
constants.sort()
|
||||
constants.append("RENPY_THIRD_TEXTURE")
|
||||
|
||||
print
|
||||
|
||||
print
|
||||
print " enum:"
|
||||
for i in constants:
|
||||
print " %s" % i
|
||||
|
||||
print
|
||||
print FOOTER
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#@PydevCodeAnalysisIgnore
|
||||
from ossaudiodev import * #@UnusedWildImport
|
||||
mixer = openmixer()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- python -*-
|
||||
# -*- python -*-
|
||||
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
@@ -50,7 +50,7 @@ cdef extern from "pss.h":
|
||||
void PSS_periodic()
|
||||
void PSS_alloc_event(object)
|
||||
int PSS_refresh_event()
|
||||
|
||||
|
||||
char *PSS_get_error()
|
||||
|
||||
int ffpy_needs_alloc
|
||||
@@ -120,7 +120,7 @@ def unpause(channel):
|
||||
|
||||
def unpause_all():
|
||||
PSS_unpause_all()
|
||||
|
||||
|
||||
def fadeout(channel, ms):
|
||||
PSS_fadeout(channel, ms)
|
||||
check_error()
|
||||
@@ -132,7 +132,7 @@ def get_pos(channel):
|
||||
return PSS_get_pos(channel)
|
||||
|
||||
def set_volume(channel, volume):
|
||||
if volume == 0:
|
||||
if volume == 0:
|
||||
PSS_set_volume(channel, 0)
|
||||
else:
|
||||
PSS_set_volume(channel, 10 ** volume / 10 )
|
||||
@@ -180,9 +180,9 @@ def needs_alloc():
|
||||
|
||||
def movie_size():
|
||||
return ffpy_movie_width, ffpy_movie_height
|
||||
|
||||
|
||||
def check_version(version):
|
||||
if version < 2 or version > 4:
|
||||
raise Exception("pysdlsound version mismatch.")
|
||||
|
||||
import_pygame_rwobject()
|
||||
import_pygame_rwobject()
|
||||
|
||||
+8
-8
@@ -13,7 +13,7 @@ from setuplib import android, include, library, cython, cmodule, pymodule, copyf
|
||||
# These control the level of optimization versus debugging.
|
||||
setuplib.extra_compile_args = [ "-Wno-unused-function" ]
|
||||
setuplib.extra_link_args = [ ]
|
||||
|
||||
|
||||
# Detect win32.
|
||||
if platform.win32_ver()[0]:
|
||||
windows = True
|
||||
@@ -40,7 +40,7 @@ library("avutil")
|
||||
has_avresample = library("avresample", optional=True)
|
||||
has_swscale = library("swscale", optional=True)
|
||||
library("freetype")
|
||||
has_fribidi = library("fribidi", optional=True)
|
||||
has_fribidi = library("fribidi", optional=True)
|
||||
library("z")
|
||||
has_libglew = library("GLEW", optional=True)
|
||||
has_libglew32 = library("glew32", optional=True)
|
||||
@@ -54,13 +54,13 @@ else:
|
||||
|
||||
# Modules directory.
|
||||
cython(
|
||||
"_renpy",
|
||||
"_renpy",
|
||||
[ "IMG_savepng.c", "core.c", "subpixel.c"],
|
||||
sdl + [ 'png', 'z', 'm' ])
|
||||
|
||||
if has_fribidi and not android:
|
||||
cython(
|
||||
"_renpybidi",
|
||||
"_renpybidi",
|
||||
[ "renpybidicore.c" ],
|
||||
['fribidi'], define_macros=[ ("FRIBIDI_ENTRY", "") ])
|
||||
|
||||
@@ -78,7 +78,7 @@ if not android:
|
||||
|
||||
if has_swscale:
|
||||
sound.insert(0, "swscale")
|
||||
|
||||
|
||||
cython(
|
||||
"pysdlsound.sound",
|
||||
[ "pss.c", "ffdecode.c" ],
|
||||
@@ -110,9 +110,9 @@ cython("renpy.gl.glrtt_fbo", libs=glew_libs)
|
||||
def anglecopy(fn):
|
||||
if android:
|
||||
return
|
||||
|
||||
|
||||
copyfile("renpy/gl/" + fn, "renpy/angle/" + fn, "DEF ANGLE = False", "DEF ANGLE = True")
|
||||
|
||||
|
||||
anglecopy("glblacklist.py")
|
||||
anglecopy("gldraw.pxd")
|
||||
anglecopy("gldraw.pyx")
|
||||
@@ -139,7 +139,7 @@ cython("renpy.text.textsupport")
|
||||
cython("renpy.text.texwrap")
|
||||
|
||||
cython(
|
||||
"renpy.text.ftfont",
|
||||
"renpy.text.ftfont",
|
||||
[ "ftsupport.c", "ttgsubtable.c" ],
|
||||
libs = sdl + [ 'freetype', 'z', 'm' ])
|
||||
|
||||
|
||||
+62
-67
@@ -14,7 +14,7 @@ android = "RENPY_ANDROID" in os.environ
|
||||
cython_command = os.environ.get("RENPY_CYTHON", None)
|
||||
|
||||
# Note that the android build sets up CFLAGS for us, and ensures
|
||||
# that necessary libraries are present. So autoconfiguration is
|
||||
# that necessary libraries are present. So autoconfiguration is
|
||||
# unnecessary on that platform.
|
||||
|
||||
# The install variable is a list of directories that have Ren'Py
|
||||
@@ -25,7 +25,7 @@ if not android:
|
||||
install = [ os.path.abspath(i) for i in install ]
|
||||
else:
|
||||
install = [ ]
|
||||
|
||||
|
||||
# The include and library dirs that we compile against.
|
||||
include_dirs = [ "." ]
|
||||
library_dirs = [ ]
|
||||
@@ -33,78 +33,78 @@ library_dirs = [ ]
|
||||
# Extra arguments that will be given to the compiler.
|
||||
extra_compile_args = [ ]
|
||||
extra_link_args = [ ]
|
||||
|
||||
|
||||
def include(header, directory=None, optional=True):
|
||||
"""
|
||||
Searches the install paths for `header`. If `directory` is given, we
|
||||
will append that to each of the install paths when trying to find
|
||||
Searches the install paths for `header`. If `directory` is given, we
|
||||
will append that to each of the install paths when trying to find
|
||||
the header. The directory the header is found in is added to include_dirs
|
||||
if it's not present already.
|
||||
|
||||
if it's not present already.
|
||||
|
||||
`optional`
|
||||
If given, returns False rather than abandoning the process.
|
||||
"""
|
||||
|
||||
|
||||
if android:
|
||||
return True
|
||||
|
||||
|
||||
for i in install:
|
||||
|
||||
|
||||
if directory is not None:
|
||||
idir = os.path.join(i, "include", directory)
|
||||
else:
|
||||
idir = os.path.join(i, "include")
|
||||
|
||||
|
||||
fn = os.path.join(idir, header)
|
||||
|
||||
|
||||
if os.path.exists(fn):
|
||||
|
||||
|
||||
if idir not in include_dirs:
|
||||
include_dirs.append(idir)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if optional:
|
||||
return False
|
||||
|
||||
|
||||
if directory is None:
|
||||
print "Could not find required header {0}.".format(header)
|
||||
else:
|
||||
print "Could not find required header {0}/{1}.".format(directory, header)
|
||||
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
|
||||
|
||||
def library(name, optional=False):
|
||||
"""
|
||||
Searches for `library`.
|
||||
|
||||
Searches for `library`.
|
||||
|
||||
`optional`
|
||||
If true, this function will return False if a library is not found,
|
||||
rather than reporting an error.
|
||||
"""
|
||||
|
||||
|
||||
if android:
|
||||
return True
|
||||
|
||||
|
||||
for i in install:
|
||||
|
||||
|
||||
for ldir in [i, os.path.join(i, "lib") ]:
|
||||
|
||||
|
||||
for suffix in ( ".so", ".a", ".dll.a", ".dylib" ):
|
||||
|
||||
fn = os.path.join(ldir, "lib" + name + suffix)
|
||||
|
||||
|
||||
if os.path.exists(fn):
|
||||
|
||||
|
||||
if ldir not in library_dirs:
|
||||
library_dirs.append(ldir)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if optional:
|
||||
return False
|
||||
|
||||
|
||||
print "Could not find required library {0}.".format(name)
|
||||
sys.exit(-1)
|
||||
|
||||
@@ -113,10 +113,10 @@ extensions = [ ]
|
||||
|
||||
def cmodule(name, source, libs=[], define_macros=[]):
|
||||
"""
|
||||
Compiles the python module `name` from the files given in
|
||||
Compiles the python module `name` from the files given in
|
||||
`source`, and the libraries in `libs`.
|
||||
"""
|
||||
|
||||
|
||||
extensions.append(distutils.core.Extension(
|
||||
name,
|
||||
source,
|
||||
@@ -136,12 +136,12 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
|
||||
Compiles a cython module. This takes care of regenerating it as necessary
|
||||
when it, or any of the files it depends on, changes.
|
||||
"""
|
||||
|
||||
|
||||
# Find the pyx file.
|
||||
split_name = name.split(".")
|
||||
|
||||
|
||||
fn = "/".join(split_name) + ".pyx"
|
||||
|
||||
|
||||
if os.path.exists(os.path.join("..", fn)):
|
||||
fn = os.path.join("..", fn)
|
||||
elif os.path.exists(fn):
|
||||
@@ -151,18 +151,18 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
|
||||
sys.exit(-1)
|
||||
|
||||
module_dir = os.path.dirname(fn)
|
||||
|
||||
|
||||
# Figure out what it depends on.
|
||||
deps = [ fn ]
|
||||
|
||||
f = file(fn)
|
||||
for l in f:
|
||||
|
||||
|
||||
m = re.search(r'from\s*([\w.]+)\s*cimport', l)
|
||||
if m:
|
||||
deps.append(m.group(1).replace(".", "/") + ".pxd")
|
||||
continue
|
||||
|
||||
|
||||
m = re.search(r'cimport\s*([\w.]+)', l)
|
||||
if m:
|
||||
deps.append(m.group(1).replace(".", "/") + ".pxd")
|
||||
@@ -171,27 +171,27 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
|
||||
m = re.search(r'include\s*"(.*?)"', l)
|
||||
if m:
|
||||
deps.append(m.group(1))
|
||||
continue
|
||||
continue
|
||||
f.close()
|
||||
|
||||
# Filter out cython stdlib dependencies.
|
||||
deps = [ i for i in deps if (not i.startswith("cpython/")) and (not i.startswith("libc/")) ]
|
||||
|
||||
|
||||
# Determine if any of the dependencies are newer than the c file.
|
||||
c_fn = os.path.join("gen", name + ".c")
|
||||
necessary_gen.append(name + ".c")
|
||||
|
||||
|
||||
if os.path.exists(c_fn):
|
||||
c_mtime = os.path.getmtime(c_fn)
|
||||
else:
|
||||
c_mtime = 0
|
||||
|
||||
|
||||
out_of_date = False
|
||||
|
||||
|
||||
# print c_fn, "depends on", deps
|
||||
|
||||
|
||||
for dep_fn in deps:
|
||||
|
||||
|
||||
if os.path.exists(os.path.join(module_dir, dep_fn)):
|
||||
dep_fn = os.path.join(module_dir, dep_fn)
|
||||
elif os.path.exists(os.path.join("..", dep_fn)):
|
||||
@@ -215,8 +215,8 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
|
||||
if out_of_date:
|
||||
print name, "is out of date."
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
try:
|
||||
import subprocess
|
||||
subprocess.check_call([
|
||||
cython_command,
|
||||
"-Iinclude",
|
||||
@@ -230,22 +230,22 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
|
||||
print str(e)
|
||||
print
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
# Build the module normally once we have the c file.
|
||||
if compile_if:
|
||||
if compile_if:
|
||||
cmodule(name, [ c_fn ] + source, libs=libs, define_macros=define_macros)
|
||||
|
||||
def find_unnecessary_gen():
|
||||
|
||||
|
||||
for i in os.listdir("gen"):
|
||||
if not i.endswith(".c"):
|
||||
continue
|
||||
|
||||
|
||||
if i in necessary_gen:
|
||||
continue
|
||||
|
||||
|
||||
print "Unnecessary file", os.path.join("gen", i)
|
||||
|
||||
|
||||
|
||||
py_modules = [ ]
|
||||
|
||||
@@ -253,33 +253,33 @@ def pymodule(name):
|
||||
"""
|
||||
Causes a python module to be included in the build.
|
||||
"""
|
||||
|
||||
|
||||
py_modules.append(name)
|
||||
|
||||
def copyfile(source, dest, replace=None, replace_with=None):
|
||||
"""
|
||||
Copy `source` to `dest`, preserving the modification time.
|
||||
|
||||
|
||||
If `replace` is given, instances of `replace` in the file contents are
|
||||
replaced with `replace_with`.
|
||||
"""
|
||||
|
||||
|
||||
sfn = os.path.join("..", source)
|
||||
dfn = os.path.join("..", dest)
|
||||
|
||||
|
||||
sf = file(sfn, "rb")
|
||||
data = sf.read()
|
||||
sf.close()
|
||||
|
||||
|
||||
if replace:
|
||||
data = data.replace(replace, replace_with)
|
||||
|
||||
|
||||
df = file(dfn, "wb")
|
||||
df.write("# This file was automatically generated from " + source + "\n")
|
||||
df.write("# Modifications will be automatically overwritten.\n\n")
|
||||
df.write("# Modifications will be automatically overwritten.\n\n")
|
||||
df.write(data)
|
||||
df.close()
|
||||
|
||||
|
||||
import shutil
|
||||
shutil.copystat(sfn, dfn)
|
||||
|
||||
@@ -290,16 +290,11 @@ def setup(name, version):
|
||||
|
||||
distutils.core.setup(
|
||||
name = name,
|
||||
version = version,
|
||||
version = version,
|
||||
ext_modules = extensions,
|
||||
py_modules = py_modules,
|
||||
)
|
||||
|
||||
|
||||
# Ensure the gen directory exists.
|
||||
if not os.path.exists("gen"):
|
||||
os.mkdir("gen")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#@PydevCodeAnalysisIgnore
|
||||
|
||||
# This file is part of Ren'Py. The license below applies to Ren'Py only.
|
||||
# This file is part of Ren'Py. The license below applies to Ren'Py only.
|
||||
# Games and other projects that use Ren'Py may use a different license.
|
||||
|
||||
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
|
||||
@@ -40,7 +40,7 @@ def path_to_common(renpy_base):
|
||||
# the path to a directory that will hold save files.
|
||||
def path_to_saves(gamedir):
|
||||
import renpy #@UnresolvedImport
|
||||
|
||||
|
||||
# Android.
|
||||
if renpy.android:
|
||||
paths = [
|
||||
@@ -48,18 +48,18 @@ def path_to_saves(gamedir):
|
||||
os.path.join(os.environ["ANDROID_PRIVATE"], "saves"),
|
||||
os.path.join(os.environ["ANDROID_PUBLIC"], "saves"),
|
||||
]
|
||||
|
||||
|
||||
for rv in paths:
|
||||
if os.path.isdir(rv):
|
||||
break
|
||||
|
||||
print "Using savedir", rv
|
||||
|
||||
|
||||
# We return the last path as the default.
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
|
||||
# No save directory given.
|
||||
if not renpy.config.save_directory:
|
||||
return gamedir + "/saves"
|
||||
@@ -93,7 +93,7 @@ def path_to_saves(gamedir):
|
||||
rv = "~/.renpy/" + renpy.config.save_directory
|
||||
return os.path.expanduser(rv)
|
||||
|
||||
|
||||
|
||||
# Returns the path to the Ren'Py base directory (containing common and
|
||||
# the launcher, usually.)
|
||||
def path_to_renpy_base():
|
||||
@@ -128,9 +128,9 @@ if android:
|
||||
__main__.path_to_common = path_to_common
|
||||
__main__.path_to_saves = path_to_saves
|
||||
os.environ["RENPY_RENDERER"] = "gl"
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
renpy_base = path_to_renpy_base()
|
||||
|
||||
# Add paths.
|
||||
@@ -145,7 +145,7 @@ def main():
|
||||
|
||||
# Ignore warnings that happen.
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
|
||||
|
||||
# Start Ren'Py proper.
|
||||
try:
|
||||
import renpy.bootstrap
|
||||
@@ -157,10 +157,8 @@ def main():
|
||||
if android:
|
||||
renpy.linux = False
|
||||
renpy.android = True
|
||||
|
||||
|
||||
renpy.bootstrap.bootstrap(renpy_base)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
|
||||
# Resolve the chain of symlinks leading to this script.
|
||||
while [ -L "$SCRIPT" ] ; do
|
||||
LINK=$(readlink "$SCRIPT")
|
||||
|
||||
case "$LINK" in
|
||||
/*)
|
||||
SCRIPT="$LINK"
|
||||
;;
|
||||
*)
|
||||
SCRIPT="$(dirname "$SCRIPT")/$LINK"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# The directory containing this shell script - an absolute path.
|
||||
ROOT=$(dirname "$0")
|
||||
ROOT=$(dirname "$SCRIPT")
|
||||
ROOT=$(cd "$ROOT"; pwd)
|
||||
|
||||
# The name of this shell script without the .sh on the end.
|
||||
BASEFILE=$(basename "$0" .sh)
|
||||
BASEFILE=$(basename "$SCRIPT" .sh)
|
||||
|
||||
if [ -z "$RENPY_PLATFORM" ] ; then
|
||||
case "$(uname -s)-$(uname -m)" in
|
||||
@@ -13,7 +29,7 @@ if [ -z "$RENPY_PLATFORM" ] ; then
|
||||
RENPY_PLATFORM="darwin-x86_64"
|
||||
ROOT1="$ROOT/../Resources/autorun"
|
||||
ROOT2="$ROOT/../../.."
|
||||
;;
|
||||
;;
|
||||
*-x86_64|amd64)
|
||||
RENPY_PLATFORM="linux-x86_64"
|
||||
ROOT1="$ROOT"
|
||||
@@ -34,11 +50,11 @@ if [ -z "$RENPY_PLATFORM" ] ; then
|
||||
fi
|
||||
|
||||
|
||||
for BASE in "$ROOT" "$ROOT1" "$ROOT2"; do
|
||||
for BASE in "$ROOT" "$ROOT1" "$ROOT2"; do
|
||||
LIB="$BASE/lib/$RENPY_PLATFORM"
|
||||
if test -d "$LIB"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
exec $RENPY_GDB "$LIB/$BASEFILE" $RENPY_PYARGS -EOO "$BASE/$BASEFILE.py" "$@"
|
||||
exec $RENPY_GDB "$LIB/$BASEFILE" $RENPY_PYARGS -EO "$BASE/$BASEFILE.py" "$@"
|
||||
|
||||
+35
-28
@@ -32,11 +32,11 @@ except ImportError:
|
||||
vc_version = 0
|
||||
|
||||
# The tuple giving the version. This needs to be updated when
|
||||
# we bump the version.
|
||||
# we bump the version.
|
||||
#
|
||||
# Be sure to change script_version in launcher/game/script_version.rpy.
|
||||
# Be sure to change config.version in tutorial/game/options.rpy.
|
||||
version_tuple = (6, 15, 7, vc_version)
|
||||
version_tuple = (6, 16, 2, vc_version)
|
||||
|
||||
# A verbose string computed from that version.
|
||||
version = "Ren'Py " + ".".join(str(i) for i in version_tuple)
|
||||
@@ -51,12 +51,12 @@ bytecode_version = 1
|
||||
first_utter_start = True
|
||||
|
||||
def setup_modulefinder(modulefinder):
|
||||
import _renpy
|
||||
import _renpy
|
||||
|
||||
libexec = os.path.dirname(_renpy.__file__)
|
||||
|
||||
for i in [ "display", "gl", "angle", "text" ]:
|
||||
|
||||
|
||||
displaypath = os.path.join(libexec, "renpy", i)
|
||||
|
||||
if os.path.exists(displaypath):
|
||||
@@ -86,18 +86,19 @@ def import_cython():
|
||||
import renpy.angle.glrtt_copy #@UnresolvedImport
|
||||
import renpy.angle.glrtt_fbo #@UnresolvedImport
|
||||
import renpy.angle.gltexture #@UnresolvedImport
|
||||
|
||||
|
||||
|
||||
|
||||
def import_all():
|
||||
|
||||
import renpy.log #@UnresolvedImport
|
||||
|
||||
|
||||
import renpy.display #@UnresolvedImport
|
||||
|
||||
# Should probably be early, as we will add it as a base to serialized things.
|
||||
import renpy.object #@UnresolvedImport
|
||||
|
||||
import renpy.game #@UnresolvedImport
|
||||
import renpy.preferences #@UnresolvedImport
|
||||
|
||||
# Adds in the Ren'Py loader.
|
||||
import renpy.loader #@UnresolvedImport
|
||||
@@ -108,6 +109,8 @@ def import_all():
|
||||
import renpy.easy #@UnresolvedImport
|
||||
import renpy.execution #@UnresolvedImport
|
||||
import renpy.loadsave #@UnresolvedImport
|
||||
import renpy.savelocation # @UnresolvedImport
|
||||
import renpy.persistent #@UnresolvedImport
|
||||
import renpy.parser #@UnresolvedImport
|
||||
import renpy.python #@UnresolvedImport
|
||||
import renpy.script #@UnresolvedImport
|
||||
@@ -126,41 +129,41 @@ def import_all():
|
||||
Update the __path__ of package, to import binary modules from a libexec
|
||||
directory.
|
||||
"""
|
||||
|
||||
|
||||
name = package.__name__.split(".")
|
||||
|
||||
|
||||
import _renpy #@UnresolvedImport
|
||||
libexec = os.path.dirname(_renpy.__file__)
|
||||
package.__path__.append(os.path.join(libexec, *name))
|
||||
|
||||
|
||||
# Also find encodings, to deal with the way py2exe lays things out.
|
||||
import encodings
|
||||
libexec = os.path.dirname(encodings.__path__[0])
|
||||
package.__path__.append(os.path.join(libexec, *name))
|
||||
|
||||
update_path(renpy.display)
|
||||
|
||||
|
||||
import renpy.display.render # Most display stuff depends on this. @UnresolvedImport
|
||||
import renpy.display.core # object @UnresolvedImport
|
||||
|
||||
import renpy.text #@UnresolvedImport
|
||||
update_path(renpy.text)
|
||||
|
||||
|
||||
import renpy.text.ftfont #@UnresolvedImport
|
||||
import renpy.text.font #@UnresolvedImport
|
||||
import renpy.text.textsupport #@UnresolvedImport
|
||||
import renpy.text.texwrap #@UnresolvedImport
|
||||
import renpy.text.text #@UnresolvedImport
|
||||
import renpy.text.extras #@UnresolvedImport
|
||||
|
||||
|
||||
sys.modules['renpy.display.text'] = renpy.text.text
|
||||
|
||||
|
||||
import renpy.gl #@UnresolvedImport
|
||||
update_path(renpy.gl)
|
||||
|
||||
|
||||
import renpy.angle #@UnresolvedImport
|
||||
update_path(renpy.angle)
|
||||
|
||||
|
||||
import renpy.display.layout # core @UnresolvedImport
|
||||
import renpy.display.motion # layout @UnresolvedImport
|
||||
import renpy.display.behavior # layout @UnresolvedImport
|
||||
@@ -179,11 +182,12 @@ def import_all():
|
||||
import renpy.display.dragdrop #@UnresolvedImport
|
||||
import renpy.display.imagemap #@UnresolvedImport
|
||||
import renpy.display.predict #@UnresolvedImport
|
||||
|
||||
import renpy.display.emulator # @UnresolvedImport
|
||||
|
||||
import renpy.display.error #@UnresolvedImport
|
||||
|
||||
# Note: For windows to work, renpy.audio.audio needs to be after
|
||||
# renpy.display.module.
|
||||
# renpy.display.module.
|
||||
import renpy.audio.audio #@UnresolvedImport
|
||||
import renpy.audio.music #@UnresolvedImport
|
||||
import renpy.audio.sound #@UnresolvedImport
|
||||
@@ -208,14 +212,14 @@ def import_all():
|
||||
# Create the store.
|
||||
renpy.python.create_store("store")
|
||||
|
||||
# Import the contents of renpy.defaultstore into renpy.store, and set
|
||||
# Import the contents of renpy.defaultstore into renpy.store, and set
|
||||
# up an alias as we do.
|
||||
renpy.store = sys.modules['store']
|
||||
sys.modules['renpy.store'] = sys.modules['store']
|
||||
|
||||
import subprocess
|
||||
sys.modules['renpy.subprocess'] = subprocess
|
||||
|
||||
|
||||
for k, v in renpy.defaultstore.__dict__.iteritems():
|
||||
renpy.store.__dict__.setdefault(k, v)
|
||||
|
||||
@@ -230,23 +234,26 @@ if False:
|
||||
|
||||
# This reloads all modules.
|
||||
def reload_all():
|
||||
|
||||
|
||||
import renpy #@UnresolvedImport
|
||||
|
||||
# Shut down the cache thread.
|
||||
renpy.display.im.cache.quit()
|
||||
|
||||
|
||||
# Shut down the importer.
|
||||
renpy.loader.quit_importer()
|
||||
|
||||
blacklist = [ "renpy",
|
||||
"renpy.log",
|
||||
"renpy.bootstrap",
|
||||
"renpy.display",
|
||||
"renpy.display.pgrender",
|
||||
"renpy.display.scale" ]
|
||||
|
||||
|
||||
for i in sys.modules.keys():
|
||||
if i.startswith("renpy") and i not in blacklist:
|
||||
del sys.modules[i]
|
||||
|
||||
|
||||
if i.startswith("store"):
|
||||
del sys.modules[i]
|
||||
|
||||
@@ -254,9 +261,11 @@ def reload_all():
|
||||
gc.collect()
|
||||
|
||||
renpy.display.draw = None
|
||||
|
||||
|
||||
import_all()
|
||||
|
||||
renpy.loader.init_importer()
|
||||
|
||||
# Information about the platform we're running on. We break the platforms
|
||||
# up into 4 groups - windows-like, mac-like, linux-like, and android-like.
|
||||
windows = False
|
||||
@@ -272,7 +281,5 @@ elif platform.mac_ver()[0]:
|
||||
macintosh = True
|
||||
else:
|
||||
linux = True
|
||||
|
||||
|
||||
# The android init code in renpy.py will set linux=False and android=True.
|
||||
|
||||
|
||||
|
||||
@@ -29,21 +29,21 @@
|
||||
# - True to allow shader rendering.
|
||||
# - True to allow fixed-function rendering.
|
||||
|
||||
# If both of the last two entries are false, GL refuses to
|
||||
# If both of the last two entries are false, GL refuses to
|
||||
# start.
|
||||
|
||||
BLACKLIST = [
|
||||
|
||||
|
||||
# Crashes for Mugenjohncel.
|
||||
("S3 Graphics DeltaChrome", "1.4 20.00", False, False),
|
||||
|
||||
# A bug in Mesa 7.9 and 7.10 (before 7.10.3) causes the system to
|
||||
# fail to initialize the GLSL compiler.
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=35603
|
||||
# fail to initialize the GLSL compiler.
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=35603
|
||||
("Mesa", "Mesa 7.9", False, True),
|
||||
("Mesa", "Mesa 7.10.3", True, True),
|
||||
("Mesa", "Mesa 7.10.3", True, True),
|
||||
("Mesa", "Mesa 7.10", False, True),
|
||||
|
||||
# Default to allowing everything.
|
||||
# Default to allowing everything.
|
||||
("", "", True, True),
|
||||
]
|
||||
|
||||
+38
-43
@@ -19,15 +19,15 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# This file handles argument parsing. Argument parsing takes place in
|
||||
# This file handles argument parsing. Argument parsing takes place in
|
||||
# two phases. In the first phase, we only parse the arguments that are
|
||||
# necessary to load the game, and run the init phase. The init phase
|
||||
# can register commands and arguments. These arguments are parsed at
|
||||
# the end of the init phase, before the game begins running, and can
|
||||
# can register commands and arguments. These arguments are parsed at
|
||||
# the end of the init phase, before the game begins running, and can
|
||||
# decide if the game runs or some other action occurs.
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import argparse
|
||||
import renpy
|
||||
|
||||
try:
|
||||
@@ -38,50 +38,50 @@ except:
|
||||
|
||||
|
||||
# A map from command name to a (function, flag) tuple. The flag is true if the
|
||||
# function will parse command line arguments, and false otherwise.
|
||||
# function will parse command line arguments, and false otherwise.
|
||||
commands = { }
|
||||
|
||||
class ArgumentParser(argparse.ArgumentParser):
|
||||
"""
|
||||
Creates an argument parser that is capable of parsing the standard Ren'Py
|
||||
arguments, as well as arguments that are specific to a sub-command.
|
||||
arguments, as well as arguments that are specific to a sub-command.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, second_pass=True, description=None, require_command=True):
|
||||
"""
|
||||
Creates an argument parser.
|
||||
|
||||
|
||||
`second_pass`
|
||||
True if this is the second pass through argument parsing. (The pass
|
||||
that parses sub-commands.)
|
||||
|
||||
|
||||
`description`
|
||||
If supplied, this will be used as a description of the subcommand
|
||||
to run.
|
||||
"""
|
||||
|
||||
|
||||
self.group = self
|
||||
|
||||
argparse.ArgumentParser.__init__(self, description="The Ren'Py visual novel engine.", add_help=False)
|
||||
|
||||
|
||||
self.add_argument(
|
||||
"basedir", default=None,
|
||||
help="The base directory containing of the project to run. This defaults to the directory containing the Ren'Py executable.",
|
||||
nargs=1 if require_command else '?'
|
||||
)
|
||||
|
||||
|
||||
command_names = ", ".join(sorted(commands))
|
||||
|
||||
|
||||
self.add_argument(
|
||||
"command",
|
||||
help="The command to execute. Available commands are: " + command_names + ". Defaults to 'run'.",
|
||||
default="run",
|
||||
nargs=1 if require_command else '?')
|
||||
|
||||
|
||||
self.add_argument(
|
||||
"--savedir", dest='savedir', default=None, metavar="DIRECTORY",
|
||||
help="The directory where saves and persistent data are placed.")
|
||||
|
||||
|
||||
self.add_argument(
|
||||
'--trace', dest='trace', action='store', default=0, type=int, metavar="LEVEL",
|
||||
help="The level of trace Ren'Py will log to trace.txt. (1=per-call, 2=per-line)")
|
||||
@@ -89,7 +89,7 @@ class ArgumentParser(argparse.ArgumentParser):
|
||||
self.add_argument(
|
||||
"--version", action='version', version=renpy.version,
|
||||
help="Displays the version of Ren'Py in use.")
|
||||
|
||||
|
||||
self.add_argument("--lint", action="store_const", dest="command", const="lint", help=argparse.SUPPRESS)
|
||||
|
||||
dump = self.add_argument_group("JSON Dump Arguments", description="Ren'Py can dump information about the game to a JSON file. These options let you select the file, and choose what is dumped.")
|
||||
@@ -102,22 +102,22 @@ class ArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
command = renpy.game.args.command #@UndefinedVariable
|
||||
self.group = self.add_argument_group("{0} command".format(command), description)
|
||||
|
||||
|
||||
def add_argument(self, *args, **kwargs):
|
||||
if self.group is self:
|
||||
argparse.ArgumentParser.add_argument(self, *args, **kwargs)
|
||||
else:
|
||||
self.group.add_argument(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
The default command, that (when called) leads to normal game startup.
|
||||
"""
|
||||
|
||||
|
||||
ap = ArgumentParser(description="Runs the current project normally.", require_command=False)
|
||||
|
||||
|
||||
ap.add_argument(
|
||||
'--profile-display', dest='profile_display', action='store_true', default=False,
|
||||
help="If present, Ren'Py will report the amount of time it takes to draw the screen.")
|
||||
@@ -149,7 +149,7 @@ def compile(): #@ReservedAssignment
|
||||
"""
|
||||
|
||||
takes_no_arguments("Recompiles the game script.")
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ def quit(): #@ReservedAssignment
|
||||
"""
|
||||
|
||||
takes_no_arguments("Recompiles the game script.")
|
||||
|
||||
|
||||
return False
|
||||
|
||||
def rmpersistent():
|
||||
@@ -169,10 +169,7 @@ def rmpersistent():
|
||||
|
||||
takes_no_arguments("Deletes the persistent data.")
|
||||
|
||||
try:
|
||||
os.unlink(renpy.config.savedir + "/persistent")
|
||||
except:
|
||||
pass
|
||||
renpy.loadsave.location.unlink_persistent()
|
||||
|
||||
return False
|
||||
|
||||
@@ -181,15 +178,15 @@ def register_command(name, function):
|
||||
"""
|
||||
Registers a command that can be invoked when Ren'Py is run on the command
|
||||
line. When the command is run, `function` is called with no arguments.
|
||||
|
||||
|
||||
If `function` needs to take additional command-line arguments, it should
|
||||
instantiate a renpy.arguments.ArgumentParser(), and then call parse_args
|
||||
on it. Otherwise, it should call renpy.arguments.takes_no_arguments().
|
||||
|
||||
|
||||
If `function` returns true, Ren'Py startup proceeds normally. Otherwise,
|
||||
Ren'Py will terminate when function() returns.
|
||||
"""
|
||||
|
||||
|
||||
commands[name] = function
|
||||
|
||||
def bootstrap():
|
||||
@@ -197,9 +194,9 @@ def bootstrap():
|
||||
Called during bootstrap to perform an initial parse of the arguments, ignoring
|
||||
unknown arguments. Returns the parsed arguments, and a list of unknown arguments.
|
||||
"""
|
||||
|
||||
|
||||
global rest
|
||||
|
||||
|
||||
ap = ArgumentParser(False, require_command=False)
|
||||
args, _rest = ap.parse_known_args()
|
||||
return args
|
||||
@@ -208,35 +205,33 @@ def pre_init():
|
||||
"""
|
||||
Called before init, to set up argument parsing.
|
||||
"""
|
||||
|
||||
global subparsers
|
||||
|
||||
|
||||
global subparsers
|
||||
|
||||
register_command("run", run)
|
||||
register_command("lint", renpy.lint.lint)
|
||||
register_command("compile", compile)
|
||||
register_command("rmpersistent", rmpersistent)
|
||||
register_command("quit", quit)
|
||||
|
||||
|
||||
|
||||
|
||||
def post_init():
|
||||
"""
|
||||
Called after init, but before the game starts. This parses a command
|
||||
and its arguments. It then runs the command function, and returns True
|
||||
if execution should continue and False otherwise.
|
||||
if execution should continue and False otherwise.
|
||||
"""
|
||||
|
||||
command = renpy.game.args.command #@UndefinedVariable
|
||||
|
||||
if command not in commands:
|
||||
ArgumentParser().error("Command {0} is unknown.".format(command))
|
||||
|
||||
|
||||
return commands[command]()
|
||||
|
||||
def takes_no_arguments(description=None):
|
||||
"""
|
||||
Used to report that a command takes no arguments.
|
||||
Used to report that a command takes no arguments.
|
||||
"""
|
||||
|
||||
|
||||
ArgumentParser(description=description).parse_args()
|
||||
|
||||
|
||||
|
||||
+170
-170
@@ -34,7 +34,7 @@ import md5
|
||||
|
||||
def next_node(n):
|
||||
"""
|
||||
Indicates the next node that should be executed. When a statement
|
||||
Indicates the next node that should be executed. When a statement
|
||||
can crash, this should be set as early as possible, so that ignore
|
||||
can bring us there.
|
||||
"""
|
||||
@@ -81,12 +81,12 @@ class ArgumentInfo(object):
|
||||
|
||||
|
||||
def __newobj__(cls, *args):
|
||||
return cls.__new__(cls, *args)
|
||||
return cls.__new__(cls, *args)
|
||||
|
||||
# This represents a string containing python code.
|
||||
class PyExpr(unicode):
|
||||
|
||||
__slots__ = [
|
||||
__slots__ = [
|
||||
'filename',
|
||||
'linenumber',
|
||||
]
|
||||
@@ -99,7 +99,7 @@ class PyExpr(unicode):
|
||||
|
||||
def __getnewargs__(self):
|
||||
return (unicode(self), self.filename, self.linenumber) # E1101
|
||||
|
||||
|
||||
class PyCode(object):
|
||||
|
||||
__slots__ = [
|
||||
@@ -151,11 +151,11 @@ class PyCode(object):
|
||||
code = self.source
|
||||
if isinstance(code, renpy.python.ast.AST): #@UndefinedVariable
|
||||
code = renpy.python.ast.dump(code) #@UndefinedVariable
|
||||
|
||||
|
||||
self.hash = chr(renpy.bytecode_version) + md5.md5(repr(self.location) + code.encode("utf-8")).digest()
|
||||
return self.hash
|
||||
|
||||
|
||||
|
||||
|
||||
def chain_block(block, next): #@ReservedAssignment
|
||||
"""
|
||||
This is called to chain together all of the nodes in a block. Node
|
||||
@@ -188,7 +188,7 @@ class Scry(object):
|
||||
else:
|
||||
return self._next.scry()
|
||||
|
||||
|
||||
|
||||
class Node(object):
|
||||
"""
|
||||
A node in the abstract syntax tree of the program.
|
||||
@@ -198,7 +198,7 @@ class Node(object):
|
||||
@ivar filename: The filename where this node comes from.
|
||||
@ivar linenumber: The line number of the line on which this node is defined.
|
||||
"""
|
||||
|
||||
|
||||
__slots__ = [
|
||||
'name',
|
||||
'filename',
|
||||
@@ -213,12 +213,12 @@ class Node(object):
|
||||
# Called to set the state of a Node, when necessary.
|
||||
def __setstate__(self, state):
|
||||
for k, v in state[1].iteritems():
|
||||
try:
|
||||
try:
|
||||
setattr(self, k, v)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
def __init__(self, loc):
|
||||
"""
|
||||
Initializes this Node object.
|
||||
@@ -230,7 +230,7 @@ class Node(object):
|
||||
self.filename, self.linenumber = loc
|
||||
self.name = None
|
||||
self.next = None
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
"""
|
||||
Returns a tuple of diff info about ourself. This is used to
|
||||
@@ -259,14 +259,14 @@ class Node(object):
|
||||
"""
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def chain(self, next): #@ReservedAssignment
|
||||
"""
|
||||
This is called with the Node node that should be followed after
|
||||
executing this node, and all nodes that this node
|
||||
executes. (For example, if this node is a block label, the
|
||||
next is the node that should be executed after all nodes in
|
||||
the block.)
|
||||
the block.)
|
||||
"""
|
||||
|
||||
self.next = next
|
||||
@@ -274,7 +274,7 @@ class Node(object):
|
||||
def execute(self):
|
||||
"""
|
||||
Causes this node to execute, and any action it entails to be
|
||||
performed. The node should call next_node with the node to
|
||||
performed. The node should call next_node with the node to
|
||||
be executed after this one.
|
||||
"""
|
||||
|
||||
@@ -311,11 +311,11 @@ class Node(object):
|
||||
"""
|
||||
Called to restructure the AST.
|
||||
|
||||
When this method is called, callback is called once for each child
|
||||
When this method is called, callback is called once for each child
|
||||
block of the node. The block, a list, can be updated by the callback
|
||||
using slice assignment to the list.
|
||||
"""
|
||||
|
||||
|
||||
# Does nothing for nodes that do not contain child blocks.
|
||||
return
|
||||
|
||||
@@ -323,7 +323,7 @@ class Node(object):
|
||||
"""
|
||||
Returns the canonical form of the code corresponding to this statement.
|
||||
This only needs to be defined if the statement is translatable.
|
||||
|
||||
|
||||
`filter`
|
||||
If present, a filter that should be applied to human-readable
|
||||
text in the statement.
|
||||
@@ -349,7 +349,7 @@ def say_menu_with(expression, callback):
|
||||
if renpy.game.preferences.transitions:
|
||||
# renpy.game.interface.set_transition(what)
|
||||
callback(what)
|
||||
|
||||
|
||||
class Say(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -381,9 +381,9 @@ class Say(Node):
|
||||
else:
|
||||
self.who_fast = False
|
||||
else:
|
||||
self.who = None
|
||||
self.who = None
|
||||
self.who_fast = False
|
||||
|
||||
|
||||
self.what = what
|
||||
self.with_ = with_
|
||||
self.interact = interact
|
||||
@@ -394,36 +394,36 @@ class Say(Node):
|
||||
|
||||
def get_code(self, dialogue_filter=None):
|
||||
rv = [ ]
|
||||
|
||||
|
||||
if self.who:
|
||||
rv.append(self.who)
|
||||
|
||||
|
||||
if self.attributes is not None:
|
||||
rv.extend(self.attributes)
|
||||
|
||||
|
||||
what = self.what
|
||||
if dialogue_filter is not None:
|
||||
what = dialogue_filter(what)
|
||||
|
||||
|
||||
rv.append(renpy.translation.encode_say_string(what))
|
||||
|
||||
if not self.interact:
|
||||
rv.append("nointeract")
|
||||
|
||||
if self.with_:
|
||||
if self.with_:
|
||||
rv.append("with")
|
||||
rv.append(self.with_)
|
||||
|
||||
return " ".join(rv)
|
||||
|
||||
def execute(self):
|
||||
|
||||
|
||||
next_node(self.next)
|
||||
|
||||
try:
|
||||
|
||||
renpy.exports.say_attributes = self.attributes
|
||||
|
||||
|
||||
if self.who is not None:
|
||||
if self.who_fast:
|
||||
who = getattr(renpy.store, self.who, None)
|
||||
@@ -433,37 +433,39 @@ class Say(Node):
|
||||
who = renpy.python.py_eval(self.who)
|
||||
else:
|
||||
who = None
|
||||
|
||||
|
||||
if not (
|
||||
(who is None) or
|
||||
callable(who) or
|
||||
isinstance(who, basestring) ):
|
||||
|
||||
|
||||
raise Exception("Sayer %s is not a function or string." % self.who.encode("utf-8"))
|
||||
|
||||
|
||||
what = self.what
|
||||
if renpy.config.say_menu_text_filter:
|
||||
what = renpy.config.say_menu_text_filter(what) # E1102
|
||||
|
||||
|
||||
renpy.store._last_raw_what = what
|
||||
|
||||
if getattr(who, "record_say", True):
|
||||
renpy.store._last_say_who = self.who
|
||||
renpy.store._last_say_what = what
|
||||
|
||||
|
||||
say_menu_with(self.with_, renpy.game.interface.set_transition)
|
||||
renpy.exports.say(who, what, interact=self.interact)
|
||||
|
||||
finally:
|
||||
renpy.exports.say_attributes = None
|
||||
|
||||
|
||||
|
||||
|
||||
def predict(self):
|
||||
|
||||
old_attributes = renpy.exports.say_attributes
|
||||
|
||||
try:
|
||||
|
||||
|
||||
renpy.exports.say_attributes = self.attributes
|
||||
|
||||
|
||||
if self.who is not None:
|
||||
if self.who_fast:
|
||||
who = getattr(renpy.store, self.who)
|
||||
@@ -471,21 +473,21 @@ class Say(Node):
|
||||
who = renpy.python.py_eval(self.who)
|
||||
else:
|
||||
who = None
|
||||
|
||||
|
||||
def predict_with(trans):
|
||||
renpy.display.predict.displayable(trans(old_widget=None, new_widget=None))
|
||||
|
||||
|
||||
say_menu_with(self.with_, predict_with)
|
||||
|
||||
|
||||
what = self.what
|
||||
if renpy.config.say_menu_text_filter:
|
||||
what = renpy.config.say_menu_text_filter(what)
|
||||
|
||||
|
||||
renpy.exports.predict_say(who, what)
|
||||
|
||||
finally:
|
||||
renpy.exports.say_attributes = old_attributes
|
||||
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
def scry(self):
|
||||
@@ -499,13 +501,13 @@ class Say(Node):
|
||||
else:
|
||||
who = None
|
||||
|
||||
if self.interact:
|
||||
if self.interact:
|
||||
renpy.exports.scry_say(who, rv)
|
||||
else:
|
||||
rv.interacts = False
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# Copy the descriptor.
|
||||
setattr(Say, "with", Say.with_) # E1101
|
||||
|
||||
@@ -539,27 +541,27 @@ class Init(Node):
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
|
||||
|
||||
def restructure(self, callback):
|
||||
callback(self.block)
|
||||
|
||||
|
||||
def apply_arguments(params, args, kwargs):
|
||||
"""
|
||||
Applies arguments to parameters to update scope.
|
||||
|
||||
|
||||
`scope`
|
||||
A dict.
|
||||
|
||||
|
||||
`params`
|
||||
The parameters object.
|
||||
|
||||
|
||||
`args`, `kwargs`
|
||||
Positional and keyword arguments.
|
||||
"""
|
||||
|
||||
|
||||
values = { }
|
||||
rv = { }
|
||||
|
||||
|
||||
if args is None:
|
||||
args = ()
|
||||
|
||||
@@ -571,7 +573,7 @@ def apply_arguments(params, args, kwargs):
|
||||
raise Exception("Arguments supplied, but parameter list not present")
|
||||
else:
|
||||
return rv
|
||||
|
||||
|
||||
for name, value in zip(params.positional, args):
|
||||
if name in values:
|
||||
raise Exception("Parameter %s has two values." % name)
|
||||
@@ -593,11 +595,11 @@ def apply_arguments(params, args, kwargs):
|
||||
raise Exception("Required parameter %s has no value." % name)
|
||||
else:
|
||||
rv[name] = renpy.python.py_eval(default)
|
||||
|
||||
|
||||
else:
|
||||
rv[name] = values[name]
|
||||
del values[name]
|
||||
|
||||
|
||||
# Now, values has the left-over keyword arguments, and extrapos
|
||||
# has the left-over positional arguments.
|
||||
|
||||
@@ -613,7 +615,7 @@ def apply_arguments(params, args, kwargs):
|
||||
raise Exception("Unknown keyword arguments: %s" % ( ", ".join(values.keys())))
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
class Label(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -627,7 +629,7 @@ class Label(Node):
|
||||
self.parameters = None
|
||||
self.hide = False
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
|
||||
def __init__(self, loc, name, block, parameters, hide=False):
|
||||
"""
|
||||
Constructs a new Label node.
|
||||
@@ -648,7 +650,7 @@ class Label(Node):
|
||||
return (Label, self.name)
|
||||
|
||||
def get_children(self):
|
||||
return self.block
|
||||
return self.block
|
||||
|
||||
def chain(self, next): #@ReservedAssignment
|
||||
|
||||
@@ -657,12 +659,12 @@ class Label(Node):
|
||||
chain_block(self.block, next)
|
||||
else:
|
||||
self.next = next
|
||||
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
|
||||
renpy.game.context().mark_seen()
|
||||
|
||||
|
||||
values = apply_arguments(self.parameters, renpy.store._args, renpy.store._kwargs)
|
||||
|
||||
for k, v in values.iteritems():
|
||||
@@ -698,7 +700,7 @@ class Python(Node):
|
||||
@param hide: If True, the code will be executed with its
|
||||
own local dictionary.
|
||||
"""
|
||||
|
||||
|
||||
super(Python, self).__init__(loc)
|
||||
|
||||
self.hide = hide
|
||||
@@ -713,11 +715,11 @@ class Python(Node):
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
|
||||
finally:
|
||||
|
||||
|
||||
if not renpy.game.context().init_phase:
|
||||
for i in renpy.config.python_callbacks:
|
||||
i()
|
||||
@@ -746,7 +748,7 @@ class EarlyPython(Node):
|
||||
@param hide: If True, the code will be executed with its
|
||||
own local dictionary.
|
||||
"""
|
||||
|
||||
|
||||
super(EarlyPython, self).__init__(loc)
|
||||
|
||||
self.hide = hide
|
||||
@@ -761,7 +763,7 @@ class EarlyPython(Node):
|
||||
|
||||
def early_execute(self):
|
||||
renpy.python.create_store(self.store)
|
||||
|
||||
|
||||
if self.code.bytecode:
|
||||
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
|
||||
|
||||
@@ -782,7 +784,7 @@ class Image(Node):
|
||||
"""
|
||||
|
||||
super(Image, self).__init__(loc)
|
||||
|
||||
|
||||
self.imgname = name
|
||||
|
||||
if expr:
|
||||
@@ -791,8 +793,8 @@ class Image(Node):
|
||||
else:
|
||||
self.code = None
|
||||
self.atl = atl
|
||||
|
||||
def diff_info(self):
|
||||
|
||||
def diff_info(self):
|
||||
return (Image, tuple(self.imgname))
|
||||
|
||||
def execute(self):
|
||||
@@ -810,7 +812,7 @@ class Image(Node):
|
||||
renpy.exports.image(self.imgname, img)
|
||||
|
||||
|
||||
|
||||
|
||||
class Transform(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -822,20 +824,20 @@ class Transform(Node):
|
||||
'atl',
|
||||
|
||||
# The parameters associated with the transform, if any.
|
||||
'parameters',
|
||||
'parameters',
|
||||
]
|
||||
|
||||
default_parameters = ParameterInfo([ ], [ ], None, None)
|
||||
|
||||
|
||||
def __init__(self, loc, name, atl=None, parameters=default_parameters):
|
||||
|
||||
super(Transform, self).__init__(loc)
|
||||
|
||||
|
||||
self.varname = name
|
||||
self.atl = atl
|
||||
self.parameters = parameters
|
||||
|
||||
def diff_info(self):
|
||||
|
||||
def diff_info(self):
|
||||
return (Transform, self.varname)
|
||||
|
||||
def execute(self):
|
||||
@@ -851,7 +853,7 @@ class Transform(Node):
|
||||
renpy.dump.transforms.append((self.varname, self.filename, self.linenumber))
|
||||
setattr(renpy.store, self.varname, trans)
|
||||
|
||||
|
||||
|
||||
def predict_imspec(imspec, scene=False, atl=None):
|
||||
"""
|
||||
Call this to use the given callback to predict the image named
|
||||
@@ -866,8 +868,8 @@ def predict_imspec(imspec, scene=False, atl=None):
|
||||
|
||||
elif len(imspec) == 3:
|
||||
name, _at_list, layer = imspec
|
||||
|
||||
|
||||
|
||||
|
||||
if expression:
|
||||
try:
|
||||
img = renpy.python.py_eval(expression)
|
||||
@@ -886,36 +888,36 @@ def predict_imspec(imspec, scene=False, atl=None):
|
||||
|
||||
if scene:
|
||||
renpy.game.context().images.predict_scene(layer)
|
||||
|
||||
|
||||
renpy.game.context().images.predict_show(tag or name, layer)
|
||||
|
||||
|
||||
if atl is not None:
|
||||
try:
|
||||
img = renpy.display.motion.ATLTransform(atl, child=img)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
renpy.display.predict.displayable(img)
|
||||
|
||||
|
||||
|
||||
|
||||
def show_imspec(imspec, atl=None):
|
||||
|
||||
if len(imspec) == 7:
|
||||
name, expression, tag, at_list, layer, zorder, behind = imspec
|
||||
|
||||
|
||||
elif len(imspec) == 6:
|
||||
name, expression, tag, at_list, layer, zorder = imspec
|
||||
behind = [ ]
|
||||
|
||||
|
||||
elif len(imspec) == 3:
|
||||
name, at_list, layer = imspec
|
||||
expression = None
|
||||
tag = None
|
||||
zorder = None
|
||||
behind = [ ]
|
||||
|
||||
|
||||
if zorder is not None:
|
||||
zorder = renpy.python.py_eval(zorder)
|
||||
else:
|
||||
@@ -953,19 +955,19 @@ class Show(Node):
|
||||
|
||||
self.imspec = imspec
|
||||
self.atl = atl
|
||||
|
||||
def diff_info(self):
|
||||
|
||||
def diff_info(self):
|
||||
return (Show, tuple(self.imspec[0]))
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
|
||||
|
||||
show_imspec(self.imspec, atl=getattr(self, "atl", None))
|
||||
|
||||
def predict(self):
|
||||
predict_imspec(self.imspec, atl=getattr(self, "atl", None))
|
||||
return [ self.next ]
|
||||
|
||||
|
||||
|
||||
class Scene(Node):
|
||||
|
||||
@@ -988,7 +990,7 @@ class Scene(Node):
|
||||
self.layer = layer
|
||||
self.atl = atl
|
||||
|
||||
def diff_info(self):
|
||||
def diff_info(self):
|
||||
|
||||
if self.imspec:
|
||||
data = tuple(self.imspec[0])
|
||||
@@ -1005,15 +1007,15 @@ class Scene(Node):
|
||||
|
||||
if self.imspec:
|
||||
show_imspec(self.imspec, atl=getattr(self, "atl", None))
|
||||
|
||||
|
||||
def predict(self):
|
||||
|
||||
|
||||
if self.imspec:
|
||||
predict_imspec(self.imspec, atl=getattr(self, "atl", None), scene=True)
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
|
||||
|
||||
class Hide(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1031,7 +1033,7 @@ class Hide(Node):
|
||||
|
||||
self.imspec = imgspec
|
||||
|
||||
def diff_info(self):
|
||||
def diff_info(self):
|
||||
return (Hide, tuple(self.imspec[0]))
|
||||
|
||||
def predict(self):
|
||||
@@ -1051,11 +1053,11 @@ class Hide(Node):
|
||||
|
||||
if tag is None:
|
||||
tag = name[0]
|
||||
|
||||
|
||||
renpy.game.context().images.predict_hide(tag, layer)
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
|
||||
def execute(self):
|
||||
|
||||
next_node(self.next)
|
||||
@@ -1069,10 +1071,10 @@ class Hide(Node):
|
||||
name, _expression, tag, _at_list, layer, _zorder = self.imspec
|
||||
elif len(self.imspec) == 7:
|
||||
name, _expression, tag, _at_list, layer, _zorder, _behind = self.imspec
|
||||
|
||||
|
||||
renpy.config.hide(tag or name, layer)
|
||||
|
||||
|
||||
|
||||
class With(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1083,7 +1085,7 @@ class With(Node):
|
||||
def __setstate__(self, state):
|
||||
self.paired = None
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
|
||||
def __init__(self, loc, expr, paired=None):
|
||||
"""
|
||||
@param expr: An expression giving a transition or None.
|
||||
@@ -1095,7 +1097,7 @@ class With(Node):
|
||||
|
||||
def diff_info(self):
|
||||
return (With, self.expr)
|
||||
|
||||
|
||||
def execute(self):
|
||||
|
||||
next_node(self.next)
|
||||
@@ -1105,7 +1107,7 @@ class With(Node):
|
||||
if self.paired is not None:
|
||||
paired = renpy.python.py_eval(self.paired)
|
||||
else:
|
||||
paired = None
|
||||
paired = None
|
||||
|
||||
renpy.exports.with_statement(trans, paired)
|
||||
|
||||
@@ -1120,10 +1122,10 @@ class With(Node):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
|
||||
|
||||
|
||||
class Call(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1135,7 +1137,7 @@ class Call(Node):
|
||||
def __setstate__(self, state):
|
||||
self.arguments = None
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
|
||||
def __init__(self, loc, label, expression, arguments):
|
||||
|
||||
super(Call, self).__init__(loc)
|
||||
@@ -1186,7 +1188,7 @@ class Call(Node):
|
||||
|
||||
renpy.store._args = tuple(args)
|
||||
renpy.store._kwargs = kwargs
|
||||
|
||||
|
||||
def predict(self):
|
||||
if self.expression:
|
||||
return [ ]
|
||||
@@ -1206,11 +1208,11 @@ class Return(Node):
|
||||
def __setstate__(self, state):
|
||||
self.expression = None
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
|
||||
def __init__(self, loc, expression):
|
||||
super(Return, self).__init__(loc)
|
||||
self.expression = expression
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
return (Return, )
|
||||
|
||||
@@ -1227,7 +1229,7 @@ class Return(Node):
|
||||
renpy.store._return = None
|
||||
|
||||
renpy.game.context().pop_dynamic()
|
||||
|
||||
|
||||
next_node(renpy.game.context().lookup_return(pop=True))
|
||||
|
||||
def predict(self):
|
||||
@@ -1242,7 +1244,7 @@ class Return(Node):
|
||||
rv._next = None
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
class Menu(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1284,8 +1286,8 @@ class Menu(Node):
|
||||
next_node(self.next)
|
||||
|
||||
choices = [ ]
|
||||
narration = [ ]
|
||||
|
||||
narration = [ ]
|
||||
|
||||
for i, (label, condition, block) in enumerate(self.items):
|
||||
|
||||
if renpy.config.say_menu_text_filter:
|
||||
@@ -1302,7 +1304,7 @@ class Menu(Node):
|
||||
|
||||
if narration:
|
||||
renpy.exports.say(None, "\n".join(narration), interact=False)
|
||||
|
||||
|
||||
say_menu_with(self.with_, renpy.game.interface.set_transition)
|
||||
choice = renpy.exports.menu(choices, self.set)
|
||||
|
||||
@@ -1310,7 +1312,7 @@ class Menu(Node):
|
||||
next_node(self.items[choice][2][0])
|
||||
else:
|
||||
next_node(self.next)
|
||||
|
||||
|
||||
|
||||
def predict(self):
|
||||
rv = [ ]
|
||||
@@ -1321,7 +1323,7 @@ class Menu(Node):
|
||||
say_menu_with(self.with_, predict_with)
|
||||
|
||||
renpy.store.predict_menu()
|
||||
|
||||
|
||||
for _label, _condition, block in self.items:
|
||||
if block:
|
||||
rv.append(block[0])
|
||||
@@ -1333,17 +1335,17 @@ class Menu(Node):
|
||||
rv._next = None
|
||||
rv.interacts = True
|
||||
return rv
|
||||
|
||||
|
||||
def restructure(self, callback):
|
||||
for _label, _condition, block in self.items:
|
||||
if block is not None:
|
||||
callback(block)
|
||||
|
||||
|
||||
setattr(Menu, "with", Menu.with_) # E1101
|
||||
|
||||
|
||||
# Goto is considered harmful. So we decided to name it "jump"
|
||||
# instead.
|
||||
# instead.
|
||||
class Jump(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1389,7 +1391,7 @@ class Jump(Node):
|
||||
rv._next = None
|
||||
else:
|
||||
rv._next = renpy.game.script.lookup(self.target)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
@@ -1437,7 +1439,7 @@ class While(Node):
|
||||
|
||||
def predict(self):
|
||||
return [ self.block[0], self.next ]
|
||||
|
||||
|
||||
def scry(self):
|
||||
rv = Node.scry(self)
|
||||
rv._next = None
|
||||
@@ -1501,17 +1503,17 @@ class If(Node):
|
||||
|
||||
class UserStatement(Node):
|
||||
|
||||
__slots__ = [
|
||||
'line',
|
||||
'parsed',
|
||||
'block',
|
||||
__slots__ = [
|
||||
'line',
|
||||
'parsed',
|
||||
'block',
|
||||
'translatable' ]
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.block = [ ]
|
||||
self.translatable = False
|
||||
Node.__setstate__(self, state)
|
||||
|
||||
|
||||
def __init__(self, loc, line, block):
|
||||
|
||||
super(UserStatement, self).__init__(loc)
|
||||
@@ -1521,22 +1523,22 @@ class UserStatement(Node):
|
||||
|
||||
# Do not store the parse quite yet.
|
||||
_parse_info = renpy.statements.parse(self, self.line, self.block)
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
return (UserStatement, self.line)
|
||||
|
||||
def execute(self):
|
||||
next_node(self.get_next())
|
||||
|
||||
|
||||
self.call("execute")
|
||||
|
||||
def predict(self):
|
||||
self.call("predict")
|
||||
self.call("predict")
|
||||
return [ self.get_next() ]
|
||||
|
||||
|
||||
def call(self, method, *args, **kwargs):
|
||||
|
||||
parsed = self.parsed
|
||||
|
||||
parsed = self.parsed
|
||||
if parsed is None:
|
||||
parsed = renpy.statements.parse(self, self.line, self.block)
|
||||
self.parsed = parsed
|
||||
@@ -1549,17 +1551,17 @@ class UserStatement(Node):
|
||||
return renpy.game.script.lookup(rv)
|
||||
else:
|
||||
return self.next
|
||||
|
||||
|
||||
def scry(self):
|
||||
rv = Node.scry(self)
|
||||
rv._next = self.get_next()
|
||||
self.call("scry", rv)
|
||||
return rv
|
||||
|
||||
|
||||
def get_code(self, dialogue_filter=None):
|
||||
return self.line
|
||||
|
||||
|
||||
|
||||
|
||||
class Define(Node):
|
||||
|
||||
__slots__ = [
|
||||
@@ -1576,11 +1578,11 @@ class Define(Node):
|
||||
"""
|
||||
|
||||
super(Define, self).__init__(loc)
|
||||
|
||||
|
||||
self.varname = name
|
||||
self.code = PyCode(expr, loc=loc, mode='eval')
|
||||
|
||||
def diff_info(self):
|
||||
|
||||
def diff_info(self):
|
||||
return (Define, tuple(self.varname))
|
||||
|
||||
def execute(self):
|
||||
@@ -1589,7 +1591,7 @@ class Define(Node):
|
||||
|
||||
value = renpy.python.py_eval_bytecode(self.code.bytecode)
|
||||
renpy.dump.definitions.append((self.varname, self.filename, self.linenumber))
|
||||
setattr(renpy.store, self.varname, value)
|
||||
setattr(renpy.store, self.varname, value)
|
||||
|
||||
|
||||
class Screen(Node):
|
||||
@@ -1607,10 +1609,10 @@ class Screen(Node):
|
||||
"""
|
||||
|
||||
super(Screen, self).__init__(loc)
|
||||
|
||||
|
||||
self.screen = screen
|
||||
|
||||
def diff_info(self):
|
||||
|
||||
def diff_info(self):
|
||||
return (Screen, self.screen.name)
|
||||
|
||||
def execute(self):
|
||||
@@ -1625,31 +1627,31 @@ class Screen(Node):
|
||||
|
||||
class Translate(Node):
|
||||
"""
|
||||
A translation block, produced either by explicit translation statements
|
||||
A translation block, produced either by explicit translation statements
|
||||
or implicit translation blocs.
|
||||
|
||||
If language is None, when executed this transfers control to the translate
|
||||
|
||||
If language is None, when executed this transfers control to the translate
|
||||
statement in the current language, if any, and otherwise runs the block.
|
||||
If language is not None, causes an error to occur if control reaches this
|
||||
If language is not None, causes an error to occur if control reaches this
|
||||
statement.
|
||||
|
||||
When control normally leaves a translate statement, in any language, it
|
||||
When control normally leaves a translate statement, in any language, it
|
||||
goes to the end of the translate statement in the None language.
|
||||
"""
|
||||
|
||||
|
||||
__slots__ = [
|
||||
"identifier",
|
||||
"language",
|
||||
"block",
|
||||
]
|
||||
|
||||
|
||||
def __init__(self, loc, identifier, language, block):
|
||||
super(Translate, self).__init__(loc)
|
||||
|
||||
|
||||
self.identifier = identifier
|
||||
self.language = language
|
||||
self.block = block
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
return (Translate, self.identifier, self.language)
|
||||
|
||||
@@ -1662,63 +1664,63 @@ class Translate(Node):
|
||||
if self.language is not None:
|
||||
next_node(self.next)
|
||||
raise Exception("Translation nodes cannot be run directly.")
|
||||
|
||||
|
||||
next_node(renpy.game.script.translator.lookup_translate(self.identifier))
|
||||
renpy.game.context().translate_identifier = self.identifier
|
||||
|
||||
def predict(self):
|
||||
node = renpy.game.script.translator.lookup_translate(self.identifier)
|
||||
return [ node ]
|
||||
|
||||
|
||||
def scry(self):
|
||||
rv = Scry()
|
||||
rv._next = renpy.game.script.translator.lookup_translate(self.identifier)
|
||||
return rv
|
||||
|
||||
|
||||
def get_children(self):
|
||||
return self.block
|
||||
|
||||
|
||||
def restructure(self, callback):
|
||||
return callback(self.block)
|
||||
|
||||
|
||||
|
||||
|
||||
class EndTranslate(Node):
|
||||
"""
|
||||
A node added implicitly after each translate block. It's responsible for
|
||||
resetting the translation identifier.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, loc):
|
||||
super(EndTranslate, self).__init__(loc)
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
return (EndTranslate,)
|
||||
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
renpy.game.context().translate_identifier = None
|
||||
|
||||
|
||||
|
||||
class TranslateString(Node):
|
||||
"""
|
||||
A node used for translated strings.
|
||||
"""
|
||||
|
||||
__slots__ = [
|
||||
|
||||
__slots__ = [
|
||||
"language",
|
||||
"old",
|
||||
"new"
|
||||
]
|
||||
|
||||
|
||||
def __init__(self, loc, language, old, new):
|
||||
super(TranslateString, self).__init__(loc)
|
||||
self.language = language
|
||||
self.old = old
|
||||
self.new = new
|
||||
|
||||
|
||||
def diff_info(self):
|
||||
return (TranslateString,)
|
||||
|
||||
|
||||
def execute(self):
|
||||
next_node(self.next)
|
||||
renpy.translation.add_string_translation(self.language, self.old, self.new)
|
||||
@@ -1737,7 +1739,7 @@ class TranslatePython(Node):
|
||||
@param hide: If True, the code will be executed with its
|
||||
own local dictionary.
|
||||
"""
|
||||
|
||||
|
||||
super(TranslatePython, self).__init__(loc)
|
||||
|
||||
self.language = language
|
||||
@@ -1752,5 +1754,3 @@ class TranslatePython(Node):
|
||||
# def early_execute(self):
|
||||
# renpy.python.create_store(self.store)
|
||||
# renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
|
||||
|
||||
|
||||
+130
-130
@@ -29,7 +29,7 @@ def compiling(loc):
|
||||
|
||||
def executing(loc):
|
||||
file, number = loc #@ReservedAssignment
|
||||
|
||||
|
||||
renpy.game.exception_info = "Executing ATL code at %s:%d" % (file, number)
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ def atl_warper(f):
|
||||
name = f.func_name
|
||||
warpers[name] = f
|
||||
return f
|
||||
|
||||
|
||||
# The pause warper is used internally when no other warper is
|
||||
# specified.
|
||||
@atl_warper
|
||||
@@ -51,7 +51,7 @@ def pause(t):
|
||||
return 1.0
|
||||
|
||||
position = object()
|
||||
|
||||
|
||||
# A dictionary giving property names and the corresponding default
|
||||
# values.
|
||||
PROPERTIES = {
|
||||
@@ -110,17 +110,17 @@ def correct_type(v, b, ty):
|
||||
|
||||
def interpolate(t, a, b, type): #@ReservedAssignment
|
||||
"""
|
||||
Linearly interpolate the arguments.
|
||||
Linearly interpolate the arguments.
|
||||
"""
|
||||
|
||||
if t >= 1.0:
|
||||
return b
|
||||
|
||||
|
||||
# Recurse into tuples.
|
||||
if isinstance(b, tuple):
|
||||
if isinstance(b, tuple):
|
||||
if a is None:
|
||||
a = [ None ] * len(b)
|
||||
|
||||
|
||||
return tuple(interpolate(t, i, j, ty) for i, j, ty in zip(a, b, type))
|
||||
|
||||
# Deal with booleans, nones, etc.
|
||||
@@ -134,7 +134,7 @@ def interpolate(t, a, b, type): #@ReservedAssignment
|
||||
else:
|
||||
if a is None:
|
||||
a = 0
|
||||
|
||||
|
||||
return correct_type(a + t * (b - a), b, type)
|
||||
|
||||
# Interpolate the value of a spline. This code is based on Aenakume's code,
|
||||
@@ -146,9 +146,9 @@ def interpolate_spline(t, spline):
|
||||
|
||||
if spline[0] is None:
|
||||
return spline[-1]
|
||||
|
||||
|
||||
if len(spline) == 2:
|
||||
t_p = 1.0 - t
|
||||
t_p = 1.0 - t
|
||||
|
||||
rv = t_p * spline[0] + t * spline[-1]
|
||||
|
||||
@@ -156,7 +156,7 @@ def interpolate_spline(t, spline):
|
||||
t_pp = (1.0 - t)**2
|
||||
t_p = 2 * t * (1.0 - t)
|
||||
t2 = t**2
|
||||
|
||||
|
||||
rv = t_pp * spline[0] + t_p * spline[1] + t2 * spline[2]
|
||||
|
||||
elif len(spline) == 4:
|
||||
@@ -165,14 +165,14 @@ def interpolate_spline(t, spline):
|
||||
t_pp = 3 * t * (1.0 - t)**2
|
||||
t_p = 3 * t**2 * (1.0 - t)
|
||||
t3 = t**3
|
||||
|
||||
|
||||
rv = t_ppp * spline[0] + t_pp * spline[1] + t_p * spline[2] + t3 * spline[3]
|
||||
|
||||
else:
|
||||
raise Exception("ATL can't interpolate splines of length %d." % len(spline))
|
||||
|
||||
return correct_type(rv, spline[-1], position)
|
||||
|
||||
|
||||
|
||||
# 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,
|
||||
@@ -184,15 +184,15 @@ class Context(object):
|
||||
def eval(self, expr): #@ReservedAssignment
|
||||
expr = renpy.python.escape_unicode(expr)
|
||||
return eval(expr, renpy.store.__dict__, self.context) #@UndefinedVariable
|
||||
|
||||
|
||||
# This is intended to be subclassed by ATLTransform. It takes care of
|
||||
# managing ATL execution, which allows ATLTransform itself to not care
|
||||
# much about the contents of this file.
|
||||
class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
# Compatibility with older saves.
|
||||
parameters = renpy.ast.ParameterInfo([ ], [ ], None, None)
|
||||
|
||||
parameters = renpy.ast.ParameterInfo([ ], [ ], None, None)
|
||||
|
||||
def __init__(self, atl, context, parameters):
|
||||
|
||||
# The constructor will be called by atltransform.
|
||||
@@ -202,13 +202,13 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
# The parameters that we take.
|
||||
self.parameters = parameters
|
||||
|
||||
|
||||
# The raw code that makes up this ATL statement.
|
||||
self.atl = atl
|
||||
|
||||
# The context in which execution occurs.
|
||||
self.context = Context(context)
|
||||
|
||||
|
||||
# The code after it has been compiled into a block.
|
||||
self.block = None
|
||||
|
||||
@@ -240,7 +240,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
"""
|
||||
|
||||
super(ATLTransformBase, self).take_execution_state(t)
|
||||
|
||||
|
||||
if t.atl is not self.atl:
|
||||
return
|
||||
|
||||
@@ -258,7 +258,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
if self.child is renpy.display.motion.null:
|
||||
self.child = t.child
|
||||
|
||||
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
|
||||
@@ -275,7 +275,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
if not positional and args:
|
||||
child = args.pop(0)
|
||||
|
||||
|
||||
# Handle positional arguments.
|
||||
while positional and args:
|
||||
name = positional.pop(0)
|
||||
@@ -304,7 +304,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
if child is None:
|
||||
child = self.child
|
||||
|
||||
|
||||
if child is None:
|
||||
child = renpy.display.motion.get_null()
|
||||
|
||||
@@ -319,10 +319,10 @@ class ATLTransformBase(renpy.object.Object):
|
||||
parameters=parameters)
|
||||
|
||||
rv.take_state(self)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
def compile(self): #@ReservedAssignment
|
||||
"""
|
||||
Compiles the ATL code into a block. As necessary, updates the
|
||||
@@ -331,9 +331,9 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
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])
|
||||
|
||||
|
||||
old_exception_info = renpy.game.exception_info
|
||||
|
||||
|
||||
self.block = self.atl.compile(self.context)
|
||||
|
||||
if len(self.block.statements) == 1 \
|
||||
@@ -346,7 +346,7 @@ class ATLTransformBase(renpy.object.Object):
|
||||
|
||||
renpy.game.exception_info = old_exception_info
|
||||
|
||||
|
||||
|
||||
def execute(self, trans, st, at):
|
||||
|
||||
if self.done:
|
||||
@@ -360,21 +360,21 @@ class ATLTransformBase(renpy.object.Object):
|
||||
if self.child.transform_event != self.last_child_transform_event:
|
||||
self.last_child_transform_event = self.child.transform_event
|
||||
self.transform_event = self.child.transform_event
|
||||
|
||||
|
||||
# Hide request.
|
||||
if trans.hide_request:
|
||||
self.transform_event = "hide"
|
||||
|
||||
if trans.replaced_request:
|
||||
self.transform_event = "replaced"
|
||||
|
||||
|
||||
# Notice transform events.
|
||||
if self.transform_event != self.last_transform_event:
|
||||
event = self.transform_event
|
||||
self.last_transform_event = self.transform_event
|
||||
else:
|
||||
event = None
|
||||
|
||||
|
||||
old_exception_info = renpy.game.exception_info
|
||||
|
||||
if self.atl.animation:
|
||||
@@ -387,31 +387,31 @@ class ATLTransformBase(renpy.object.Object):
|
||||
renpy.game.exception_info = old_exception_info
|
||||
|
||||
# print "Executing", self, self.state, self.xpos, self.ypos
|
||||
|
||||
|
||||
if action == "continue":
|
||||
self.atl_state = arg
|
||||
else:
|
||||
self.done = True
|
||||
|
||||
return pause
|
||||
|
||||
|
||||
def predict_one(self):
|
||||
self.atl.predict(self.context)
|
||||
|
||||
|
||||
def visit(self):
|
||||
if not self.block:
|
||||
self.compile()
|
||||
|
||||
return self.children + self.block.visit()
|
||||
|
||||
|
||||
|
||||
|
||||
# The base class for raw ATL statements.
|
||||
class RawStatement(renpy.object.Object):
|
||||
|
||||
def __init__(self, loc):
|
||||
super(RawStatement, self).__init__()
|
||||
self.loc = loc
|
||||
|
||||
|
||||
# Compiles this RawStatement into a Statement, by using ctx to
|
||||
# evaluate expressions as necessary.
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
@@ -437,7 +437,7 @@ class Statement(renpy.object.Object):
|
||||
# "continue", state, pause - Causes this statement to execute
|
||||
# again, with the given state passed in the second time around.
|
||||
#
|
||||
#
|
||||
#
|
||||
# "next", timeleft, pause - Causes the next statement to execute,
|
||||
# with timeleft being the amount of time left after this statement
|
||||
# finished.
|
||||
@@ -469,12 +469,12 @@ class RawBlock(RawStatement):
|
||||
def __init__(self, loc, statements, animation):
|
||||
|
||||
super(RawBlock, self).__init__(loc)
|
||||
|
||||
|
||||
# A list of RawStatements in this block.
|
||||
self.statements = statements
|
||||
|
||||
|
||||
self.animation = animation
|
||||
|
||||
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
compiling(self.loc)
|
||||
|
||||
@@ -485,30 +485,30 @@ class RawBlock(RawStatement):
|
||||
def predict(self, ctx):
|
||||
for i in self.statements:
|
||||
i.predict(ctx)
|
||||
|
||||
|
||||
# A compiled ATL block.
|
||||
|
||||
|
||||
# A compiled ATL block.
|
||||
class Block(Statement):
|
||||
def __init__(self, loc, statements):
|
||||
|
||||
super(Block, self).__init__(loc)
|
||||
|
||||
|
||||
# A list of statements in the block.
|
||||
self.statements = statements
|
||||
|
||||
# The start times of various statements.
|
||||
self.times = [ ]
|
||||
|
||||
|
||||
for i, s in enumerate(statements):
|
||||
if isinstance(s, Time):
|
||||
self.times.append((s.time, i + 1))
|
||||
|
||||
self.times.sort()
|
||||
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
|
||||
|
||||
# Unpack the state.
|
||||
if state is not None:
|
||||
index, start, loop_start, repeats, times, child_state = state
|
||||
@@ -519,7 +519,7 @@ class Block(Statement):
|
||||
action = "continue"
|
||||
arg = None
|
||||
pause = None
|
||||
|
||||
|
||||
while action == "continue":
|
||||
|
||||
# Target is the time we're willing to execute to.
|
||||
@@ -597,7 +597,7 @@ class Block(Statement):
|
||||
time, tindex = times[0]
|
||||
if time <= target:
|
||||
times.pop(0)
|
||||
|
||||
|
||||
index = tindex
|
||||
start = time
|
||||
child_state = None
|
||||
@@ -608,7 +608,7 @@ class Block(Statement):
|
||||
|
||||
def visit(self):
|
||||
return [ j for i in self.statements for j in i.visit() ]
|
||||
|
||||
|
||||
# This can become one of four things:
|
||||
#
|
||||
# - A pause.
|
||||
@@ -623,11 +623,11 @@ class Block(Statement):
|
||||
class RawMultipurpose(RawStatement):
|
||||
|
||||
warp_function = None
|
||||
|
||||
|
||||
def __init__(self, loc):
|
||||
|
||||
super(RawMultipurpose, self).__init__(loc)
|
||||
|
||||
|
||||
self.warper = None
|
||||
self.duration = None
|
||||
self.properties = [ ]
|
||||
@@ -635,12 +635,12 @@ class RawMultipurpose(RawStatement):
|
||||
self.splines = [ ]
|
||||
self.revolution = None
|
||||
self.circles = "0"
|
||||
|
||||
|
||||
def add_warper(self, name, duration, warp_function):
|
||||
self.warper = name
|
||||
self.duration = duration
|
||||
self.warp_function = warp_function
|
||||
|
||||
|
||||
def add_property(self, name, exprs):
|
||||
self.properties.append((name, exprs))
|
||||
|
||||
@@ -649,17 +649,17 @@ class RawMultipurpose(RawStatement):
|
||||
|
||||
def add_revolution(self, revolution):
|
||||
self.revolution = revolution
|
||||
|
||||
|
||||
def add_circles(self, circles):
|
||||
self.circles = circles
|
||||
|
||||
def add_spline(self, name, exprs):
|
||||
self.splines.append((name, exprs))
|
||||
|
||||
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
|
||||
compiling(self.loc)
|
||||
|
||||
|
||||
# Figure out what kind of statement we have. If there's no
|
||||
# interpolator, and no properties, than we have either a
|
||||
# call, or a child statement.
|
||||
@@ -679,7 +679,7 @@ class RawMultipurpose(RawStatement):
|
||||
|
||||
if isinstance(child, (int, float)):
|
||||
return Interpolation(self.loc, "pause", child, [ ], None, 0, [ ])
|
||||
|
||||
|
||||
if isinstance(child, ATLTransformBase):
|
||||
child.compile()
|
||||
return child.block
|
||||
@@ -693,7 +693,7 @@ class RawMultipurpose(RawStatement):
|
||||
|
||||
if self.warp_function:
|
||||
warper = ctx.eval(self.warp_function)
|
||||
else:
|
||||
else:
|
||||
warper = self.warper or "pause"
|
||||
|
||||
if warper not in warpers:
|
||||
@@ -709,7 +709,7 @@ class RawMultipurpose(RawStatement):
|
||||
properties.append((name, value))
|
||||
|
||||
splines = [ ]
|
||||
|
||||
|
||||
for name, exprs in self.splines:
|
||||
if name not in PROPERTIES:
|
||||
raise Exception("ATL Property %s is unknown at runtime." % property)
|
||||
@@ -717,7 +717,7 @@ class RawMultipurpose(RawStatement):
|
||||
values = [ ctx.eval(i) for i in exprs ]
|
||||
|
||||
splines.append((name, values))
|
||||
|
||||
|
||||
for expr, _with in self.expressions:
|
||||
try:
|
||||
value = ctx.eval(expr)
|
||||
@@ -739,11 +739,11 @@ class RawMultipurpose(RawStatement):
|
||||
circles = ctx.eval(self.circles)
|
||||
|
||||
return Interpolation(self.loc, warper, duration, properties, self.revolution, circles, splines)
|
||||
|
||||
|
||||
def predict(self, ctx):
|
||||
|
||||
for i, _j in self.expressions:
|
||||
|
||||
|
||||
try:
|
||||
i = ctx.eval(i)
|
||||
except:
|
||||
@@ -757,7 +757,7 @@ class RawMultipurpose(RawStatement):
|
||||
renpy.easy.predict(i)
|
||||
except:
|
||||
continue
|
||||
|
||||
|
||||
# This lets us have an ATL transform as our child.
|
||||
class RawContainsExpr(RawStatement):
|
||||
|
||||
@@ -790,21 +790,21 @@ class RawChild(RawStatement):
|
||||
|
||||
return Child(self.loc, box, None)
|
||||
|
||||
|
||||
|
||||
# This changes the child of this statement, optionally with a transition.
|
||||
class Child(Statement):
|
||||
|
||||
def __init__(self, loc, child, transition):
|
||||
|
||||
super(Child, self).__init__(loc)
|
||||
|
||||
|
||||
self.child = renpy.easy.displayable(child)
|
||||
self.transition = transition
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
|
||||
|
||||
old_child = trans.raw_child
|
||||
|
||||
if (old_child is not None) and (old_child is not renpy.display.motion.null) and (self.transition is not None):
|
||||
@@ -820,8 +820,8 @@ class Child(Statement):
|
||||
|
||||
def visit(self):
|
||||
return [ self.child ]
|
||||
|
||||
|
||||
|
||||
|
||||
# This causes interpolation to occur.
|
||||
class Interpolation(Statement):
|
||||
|
||||
@@ -833,19 +833,19 @@ class Interpolation(Statement):
|
||||
self.duration = duration
|
||||
self.properties = properties
|
||||
self.splines = splines
|
||||
|
||||
|
||||
# The direction we revolve in: cw, ccw, or None.
|
||||
self.revolution = revolution
|
||||
|
||||
# The number of complete circles we make.
|
||||
self.circles = circles
|
||||
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
|
||||
|
||||
warper = warpers.get(self.warper, self.warper)
|
||||
|
||||
|
||||
if self.duration:
|
||||
complete = min(1.0, st / self.duration)
|
||||
else:
|
||||
@@ -866,7 +866,7 @@ class Interpolation(Statement):
|
||||
# Now, the things we change linearly are in the difference
|
||||
# between the new and old states.
|
||||
linear = trans.state.diff(newts)
|
||||
|
||||
|
||||
revolution = None
|
||||
splines = [ ]
|
||||
|
||||
@@ -910,14 +910,14 @@ class Interpolation(Statement):
|
||||
startangle += 360
|
||||
|
||||
startangle += self.circles * 360
|
||||
|
||||
|
||||
# Store the revolution.
|
||||
revolution = (startangle, endangle, startradius, endradius)
|
||||
|
||||
# Figure out the splines.
|
||||
for name, values in self.splines:
|
||||
splines.append((name, [ getattr(trans.state, name) ] + values))
|
||||
|
||||
|
||||
state = (linear, revolution, splines)
|
||||
|
||||
# Ensure that we set things, even if they don't actually
|
||||
@@ -933,26 +933,26 @@ class Interpolation(Statement):
|
||||
for k, (old, new) in linear.iteritems():
|
||||
value = interpolate(complete, old, new, PROPERTIES[k])
|
||||
|
||||
setattr(trans.state, k, value)
|
||||
|
||||
setattr(trans.state, k, value)
|
||||
|
||||
# Handle the revolution.
|
||||
if revolution is not None:
|
||||
startangle, endangle, startradius, endradius = revolution
|
||||
trans.state.angle = interpolate(complete, startangle, endangle, float)
|
||||
trans.state.radius = interpolate(complete, startradius, endradius, float)
|
||||
|
||||
|
||||
|
||||
# Handle any splines we might have.
|
||||
for name, values in splines:
|
||||
value = interpolate_spline(complete, values)
|
||||
setattr(trans.state, name, value)
|
||||
|
||||
|
||||
if st >= self.duration:
|
||||
return "next", st - self.duration, None
|
||||
else:
|
||||
if not self.properties and not self.revolution and not self.splines:
|
||||
return "continue", state, self.duration - st
|
||||
else:
|
||||
else:
|
||||
return "continue", state, 0
|
||||
|
||||
|
||||
@@ -973,7 +973,7 @@ class RawRepeat(RawStatement):
|
||||
|
||||
if repeats is not None:
|
||||
repeats = ctx.eval(repeats)
|
||||
|
||||
|
||||
return Repeat(self.loc, repeats)
|
||||
|
||||
class Repeat(Statement):
|
||||
@@ -1003,10 +1003,10 @@ class RawParallel(RawStatement):
|
||||
def predict(self, ctx):
|
||||
for i in self.blocks:
|
||||
i.predict(ctx)
|
||||
|
||||
|
||||
|
||||
|
||||
class Parallel(Statement):
|
||||
|
||||
|
||||
def __init__(self, loc, blocks):
|
||||
super(Parallel, self).__init__(loc)
|
||||
self.blocks = blocks
|
||||
@@ -1014,7 +1014,7 @@ class Parallel(Statement):
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
|
||||
|
||||
if state is None:
|
||||
state = [ (i, None) for i in self.blocks ]
|
||||
|
||||
@@ -1026,9 +1026,9 @@ class Parallel(Statement):
|
||||
|
||||
# The new state structure.
|
||||
newstate = [ ]
|
||||
|
||||
|
||||
for i, istate in state:
|
||||
|
||||
|
||||
action, arg, pause = i.execute(trans, st, istate, event)
|
||||
|
||||
if pause is not None:
|
||||
@@ -1040,7 +1040,7 @@ class Parallel(Statement):
|
||||
left.append(arg)
|
||||
elif action == "event":
|
||||
return action, arg, pause
|
||||
|
||||
|
||||
if newstate:
|
||||
return "continue", newstate, min(pauses)
|
||||
else:
|
||||
@@ -1078,7 +1078,7 @@ class Choice(Statement):
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
|
||||
|
||||
if state is None:
|
||||
|
||||
total = 0
|
||||
@@ -1107,7 +1107,7 @@ class Choice(Statement):
|
||||
def visit(self):
|
||||
return [ j for i in self.choices for j in i[1].visit() ]
|
||||
|
||||
|
||||
|
||||
# The Time statement.
|
||||
|
||||
class RawTime(RawStatement):
|
||||
@@ -1130,7 +1130,7 @@ class Time(Statement):
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
return "continue", None, None
|
||||
|
||||
|
||||
|
||||
# The On statement.
|
||||
|
||||
@@ -1162,7 +1162,7 @@ class On(Statement):
|
||||
super(On, self).__init__(loc)
|
||||
|
||||
self.handlers = handlers
|
||||
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
|
||||
executing(self.loc)
|
||||
@@ -1184,23 +1184,23 @@ class On(Statement):
|
||||
start = st
|
||||
cstate = None
|
||||
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
# If we don't have a handler, return until we change event.
|
||||
if name not in self.handlers:
|
||||
return "continue", (name, start, cstate), None
|
||||
|
||||
|
||||
action, arg, pause = self.handlers[name].execute(trans, st - start, cstate, event)
|
||||
|
||||
# If we get a continue, save our state.
|
||||
if action == "continue":
|
||||
|
||||
|
||||
# If it comes from a hide block, indicate that.
|
||||
if name == "hide" or name == "replaced":
|
||||
trans.hide_response = False
|
||||
trans.replaced_response = False
|
||||
|
||||
|
||||
return "continue", (name, start, arg), pause
|
||||
|
||||
# If we get a next, then try going to the default
|
||||
@@ -1235,7 +1235,7 @@ class On(Statement):
|
||||
|
||||
|
||||
# Event statement.
|
||||
|
||||
|
||||
class RawEvent(RawStatement):
|
||||
|
||||
def __init__(self, loc, name):
|
||||
@@ -1246,7 +1246,7 @@ class RawEvent(RawStatement):
|
||||
def compile(self, ctx): #@ReservedAssignment
|
||||
return Event(self.loc, self.name)
|
||||
|
||||
|
||||
|
||||
class Event(Statement):
|
||||
|
||||
def __init__(self, loc, name):
|
||||
@@ -1256,7 +1256,7 @@ class Event(Statement):
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
return "event", (self.name, st), None
|
||||
|
||||
|
||||
|
||||
class RawFunction(RawStatement):
|
||||
|
||||
@@ -1269,9 +1269,9 @@ class RawFunction(RawStatement):
|
||||
compiling(self.loc)
|
||||
return Function(self.loc, ctx.eval(self.expr))
|
||||
|
||||
|
||||
|
||||
class Function(Statement):
|
||||
|
||||
|
||||
def __init__(self, loc, function):
|
||||
super(Function, self).__init__(loc)
|
||||
|
||||
@@ -1279,13 +1279,13 @@ class Function(Statement):
|
||||
|
||||
def execute(self, trans, st, state, event):
|
||||
fr = self.function(trans, st, trans.at)
|
||||
|
||||
|
||||
if fr is not None:
|
||||
return "continue", None, fr
|
||||
else:
|
||||
return "next", 0, None
|
||||
|
||||
|
||||
|
||||
|
||||
# This parses an ATL block.
|
||||
def parse_atl(l):
|
||||
|
||||
@@ -1295,11 +1295,11 @@ def parse_atl(l):
|
||||
statements = [ ]
|
||||
|
||||
animation = False
|
||||
|
||||
|
||||
while not l.eob:
|
||||
|
||||
loc = l.get_location()
|
||||
|
||||
|
||||
if l.keyword('repeat'):
|
||||
|
||||
repeats = l.simple_expression()
|
||||
@@ -1310,7 +1310,7 @@ def parse_atl(l):
|
||||
l.expect_eol()
|
||||
l.expect_block('block')
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(block)
|
||||
|
||||
elif l.keyword('contains'):
|
||||
@@ -1328,14 +1328,14 @@ def parse_atl(l):
|
||||
l.expect_eol()
|
||||
l.expect_block('contains')
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(RawChild(loc, block))
|
||||
|
||||
elif l.keyword('parallel'):
|
||||
l.require(':')
|
||||
l.expect_eol()
|
||||
l.expect_block('parallel')
|
||||
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(RawParallel(loc, block))
|
||||
|
||||
@@ -1348,7 +1348,7 @@ def parse_atl(l):
|
||||
l.require(':')
|
||||
l.expect_eol()
|
||||
l.expect_block('choice')
|
||||
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(RawChoice(loc, chance, block))
|
||||
|
||||
@@ -1359,7 +1359,7 @@ def parse_atl(l):
|
||||
l.require(':')
|
||||
l.expect_eol()
|
||||
l.expect_block('on')
|
||||
|
||||
|
||||
block = parse_atl(l.subblock_lexer())
|
||||
statements.append(RawOn(loc, name, block))
|
||||
|
||||
@@ -1388,13 +1388,13 @@ def parse_atl(l):
|
||||
elif l.keyword('animation'):
|
||||
l.expect_noblock('animation')
|
||||
animation = True
|
||||
|
||||
|
||||
else:
|
||||
|
||||
# If we can't assign it it a statement more specifically,
|
||||
# we try to parse it into a RawMultipurpose. That will
|
||||
# then be turned into another statement, as appropriate.
|
||||
|
||||
|
||||
# The RawMultipurpose we add things to.
|
||||
rm = renpy.atl.RawMultipurpose(loc)
|
||||
|
||||
@@ -1403,29 +1403,29 @@ def parse_atl(l):
|
||||
|
||||
# Is this clause an expression?
|
||||
this_expression = False
|
||||
|
||||
|
||||
# First, look for a warper.
|
||||
cp = l.checkpoint()
|
||||
warper = l.name()
|
||||
|
||||
|
||||
|
||||
if warper in warpers:
|
||||
duration = l.require(l.simple_expression)
|
||||
warp_function = None
|
||||
|
||||
elif warper == "warp":
|
||||
|
||||
|
||||
warper = None
|
||||
warp_function = l.require(l.simple_expression)
|
||||
duration = l.require(l.simple_expression)
|
||||
|
||||
|
||||
else:
|
||||
l.revert(cp)
|
||||
|
||||
warper = None
|
||||
warp_function = None
|
||||
duration = "0"
|
||||
|
||||
|
||||
rm.add_warper(warper, duration, warp_function)
|
||||
|
||||
# Now, look for properties and simple_expressions.
|
||||
@@ -1437,7 +1437,7 @@ def parse_atl(l):
|
||||
|
||||
if l.keyword('pass'):
|
||||
continue
|
||||
|
||||
|
||||
# Parse revolution keywords.
|
||||
if l.keyword('clockwise'):
|
||||
rm.add_revolution('clockwise')
|
||||
@@ -1451,9 +1451,9 @@ def parse_atl(l):
|
||||
expr = l.require(l.simple_expression)
|
||||
rm.add_circles(expr)
|
||||
|
||||
# Try to parse a property.
|
||||
# Try to parse a property.
|
||||
cp = l.checkpoint()
|
||||
|
||||
|
||||
prop = l.name()
|
||||
|
||||
if prop in PROPERTIES:
|
||||
@@ -1464,7 +1464,7 @@ def parse_atl(l):
|
||||
# presence of knots that determine which one it is.
|
||||
|
||||
knots = [ ]
|
||||
|
||||
|
||||
while l.keyword('knot'):
|
||||
knots.append(l.require(l.simple_expression))
|
||||
|
||||
@@ -1475,7 +1475,7 @@ def parse_atl(l):
|
||||
rm.add_property(prop, expr)
|
||||
|
||||
continue
|
||||
|
||||
|
||||
# Otherwise, try to parse it as a simple expressoon,
|
||||
# with an optional with clause.
|
||||
|
||||
@@ -1490,7 +1490,7 @@ def parse_atl(l):
|
||||
l.error('ATL statement contains two expressions in a row; is one of them a misspelled property? If not, separate them with pass.')
|
||||
|
||||
this_expression = True
|
||||
|
||||
|
||||
if l.keyword("with"):
|
||||
with_expr = l.require(l.simple_expression)
|
||||
else:
|
||||
@@ -1499,17 +1499,17 @@ def parse_atl(l):
|
||||
rm.add_expression(expr, with_expr)
|
||||
|
||||
l.expect_noblock('ATL')
|
||||
|
||||
|
||||
statements.append(rm)
|
||||
|
||||
|
||||
|
||||
|
||||
if l.eol():
|
||||
l.advance()
|
||||
continue
|
||||
|
||||
l.require(",", "comma or end of line")
|
||||
|
||||
|
||||
|
||||
# Merge together statements that need to be merged together.
|
||||
|
||||
merged = [ ]
|
||||
@@ -1538,7 +1538,7 @@ def parse_atl(l):
|
||||
elif new is None:
|
||||
old = new
|
||||
continue
|
||||
|
||||
|
||||
merged.append(new)
|
||||
old = new
|
||||
|
||||
|
||||
+241
-67
@@ -24,11 +24,11 @@
|
||||
# Invariants: The periodic callback assumes pcm_ok. If we don't have
|
||||
# at least pcm_ok, we have no sound whatsoever.
|
||||
|
||||
import renpy.audio
|
||||
import renpy.display
|
||||
import renpy.audio # @UnusedImport
|
||||
import renpy.display # @UnusedImport
|
||||
|
||||
import time
|
||||
import pygame
|
||||
import pygame # @UnusedImport
|
||||
import os
|
||||
import atexit
|
||||
|
||||
@@ -41,8 +41,8 @@ pss = None
|
||||
if 'pss' not in disable:
|
||||
try:
|
||||
import pysdlsound as pss
|
||||
pss.check_version(4)
|
||||
atexit.register(pss.quit)
|
||||
pss.check_version(4) # @UndefinedVariable
|
||||
atexit.register(pss.quit) # @UndefinedVariable
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -53,12 +53,12 @@ if 'pss' not in disable:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# Save the mixer, and restore it at exit.
|
||||
|
||||
old_wave = None
|
||||
old_midi = None
|
||||
|
||||
|
||||
# This is True if we were able to sucessfully enable the pcm audio.
|
||||
pcm_ok = None
|
||||
|
||||
@@ -69,7 +69,7 @@ def get_serial():
|
||||
"""
|
||||
Gets a globally unique serial number for each music change.
|
||||
"""
|
||||
|
||||
|
||||
global serial
|
||||
serial += 1
|
||||
return (unique, serial)
|
||||
@@ -107,7 +107,7 @@ class MusicContext(renpy.python.RevertableObject):
|
||||
def __init__(self):
|
||||
|
||||
super(MusicContext, self).__init__()
|
||||
|
||||
|
||||
# The time this channel was last ordered panned.
|
||||
self.pan_time = None
|
||||
|
||||
@@ -116,10 +116,10 @@ class MusicContext(renpy.python.RevertableObject):
|
||||
|
||||
# The time the secondary volume was last ordered changed.
|
||||
self.secondary_volume_time = None
|
||||
|
||||
|
||||
# The secondary volume.
|
||||
self.secondary_volume = 1.0
|
||||
|
||||
|
||||
# The time the channel was ordered last changed.
|
||||
self.last_changed = 0
|
||||
|
||||
@@ -131,7 +131,7 @@ class MusicContext(renpy.python.RevertableObject):
|
||||
|
||||
# Should we force stop this channel?
|
||||
self.force_stop = False
|
||||
|
||||
|
||||
def copy(self):
|
||||
"""
|
||||
Returns a shallow copy of this context.
|
||||
@@ -141,21 +141,21 @@ class MusicContext(renpy.python.RevertableObject):
|
||||
rv.__dict__.update(self.__dict__)
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# The next channel number to be assigned.
|
||||
next_channel_number = 0
|
||||
|
||||
|
||||
class Channel(object):
|
||||
"""
|
||||
This stores information about the currently-playing music.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name, default_loop, stop_on_mute, tight, file_prefix, file_suffix, buffer_queue):
|
||||
|
||||
# The name assigned to this channel. This is used to look up
|
||||
# information about the channel in the MusicContext object.
|
||||
self.name = name
|
||||
|
||||
|
||||
# The number this channel has been assigned, or None if we've yet
|
||||
# to assign a number to the channel. We only assign a channel
|
||||
# number when there's an operation on the channel other than
|
||||
@@ -220,7 +220,7 @@ class Channel(object):
|
||||
|
||||
# Should we buffer upcoming music/video in the queue?
|
||||
self.buffer_queue = buffer_queue
|
||||
|
||||
|
||||
if default_loop is None:
|
||||
# By default, should we loop the music?
|
||||
self.default_loop = True
|
||||
@@ -230,7 +230,7 @@ class Channel(object):
|
||||
else:
|
||||
self.default_loop = default_loop
|
||||
self.default_loop_set = True
|
||||
|
||||
|
||||
|
||||
def get_number(self):
|
||||
"""
|
||||
@@ -238,12 +238,12 @@ class Channel(object):
|
||||
proves necessary.
|
||||
"""
|
||||
global next_channel_number
|
||||
|
||||
|
||||
rv = self._number
|
||||
if rv is None:
|
||||
rv = self._number = next_channel_number
|
||||
next_channel_number += 1
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
number = property(get_number)
|
||||
@@ -263,14 +263,22 @@ class Channel(object):
|
||||
return rv
|
||||
|
||||
context = property(get_context)
|
||||
|
||||
|
||||
|
||||
|
||||
def periodic(self):
|
||||
"""
|
||||
This is the periodic call that causes this channel to load new stuff
|
||||
into its queues, if necessary.
|
||||
"""
|
||||
|
||||
# Update the channel volume.
|
||||
vol = self.chan_volume * renpy.game.preferences.volumes[self.mixer]
|
||||
|
||||
if vol != self.actual_volume:
|
||||
pss.set_volume(self.number, vol)
|
||||
self.actual_volume = vol
|
||||
|
||||
|
||||
# This should be set from something that checks to see if our
|
||||
# mixer is muted.
|
||||
force_stop = self.context.force_stop or (renpy.game.preferences.mute[self.mixer] and self.stop_on_mute)
|
||||
@@ -286,7 +294,7 @@ class Channel(object):
|
||||
else:
|
||||
self.queue = [ ]
|
||||
return
|
||||
|
||||
|
||||
# Should we do the callback?
|
||||
do_callback = False
|
||||
|
||||
@@ -314,7 +322,7 @@ class Channel(object):
|
||||
# give up here.
|
||||
if not self.buffer_queue and depth >= 1:
|
||||
break
|
||||
|
||||
|
||||
# We can't queue anything if the depth is > 0 and we're
|
||||
# waiting for a synchro_start.
|
||||
if self.synchro_start and depth:
|
||||
@@ -336,7 +344,7 @@ class Channel(object):
|
||||
|
||||
if not topq:
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
topf = load(self.file_prefix + topq.filename + self.file_suffix)
|
||||
|
||||
@@ -363,11 +371,11 @@ class Channel(object):
|
||||
|
||||
if self.loop and not self.queue:
|
||||
for i in self.loop:
|
||||
newq = QueueEntry(i, 0, topq.tight)
|
||||
newq = QueueEntry(i, 0, topq.tight)
|
||||
self.queue.append(newq)
|
||||
else:
|
||||
do_callback = True
|
||||
|
||||
|
||||
# Queue empty callback.
|
||||
if do_callback and self.callback:
|
||||
self.callback() # E1102
|
||||
@@ -382,7 +390,7 @@ class Channel(object):
|
||||
|
||||
self.queue = self.queue[:self.keep_queue]
|
||||
self.loop = [ ]
|
||||
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
@@ -395,7 +403,7 @@ class Channel(object):
|
||||
"""
|
||||
|
||||
self.keep_queue = 0
|
||||
|
||||
|
||||
if pcm_ok:
|
||||
|
||||
if self.pan_time != self.context.pan_time:
|
||||
@@ -410,7 +418,7 @@ class Channel(object):
|
||||
pss.set_secondary_volume(self.number,
|
||||
self.context.secondary_volume,
|
||||
0)
|
||||
|
||||
|
||||
if not self.queue and self.callback:
|
||||
self.callback() # E1102
|
||||
|
||||
@@ -429,14 +437,14 @@ class Channel(object):
|
||||
|
||||
if secs == 0:
|
||||
pss.stop(self.number)
|
||||
else:
|
||||
else:
|
||||
pss.fadeout(self.number, int(secs * 1000))
|
||||
|
||||
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
|
||||
|
||||
for filename in filenames:
|
||||
renpy.game.persistent._seen_audio[filename] = True
|
||||
|
||||
renpy.game.persistent._seen_audio[filename] = True # @UndefinedVariable
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
@@ -444,7 +452,7 @@ class Channel(object):
|
||||
tight = self.tight
|
||||
|
||||
self.keep_queue += 1
|
||||
|
||||
|
||||
for filename in filenames:
|
||||
qe = QueueEntry(filename, int(fadein * 1000), tight)
|
||||
self.queue.append(qe)
|
||||
@@ -472,17 +480,17 @@ class Channel(object):
|
||||
|
||||
if rv is None and self.loop:
|
||||
rv = self.loop[0]
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def set_volume(self, volume):
|
||||
self.chan_volume = volume
|
||||
|
||||
|
||||
def get_pos(self):
|
||||
|
||||
if not pcm_ok:
|
||||
return -1
|
||||
|
||||
|
||||
return pss.get_pos(self.number)
|
||||
|
||||
def set_pan(self, pan, delay):
|
||||
@@ -503,6 +511,179 @@ class Channel(object):
|
||||
self.secondary_volume_time = self.context.secondary_volume_time
|
||||
pss.set_secondary_volume(self.number, self.context.secondary_volume, delay)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Android VideoPlayer Channel
|
||||
################################################################################
|
||||
|
||||
if renpy.android:
|
||||
|
||||
import jnius # @UnresolvedImport
|
||||
|
||||
VideoPlayer = jnius.autoclass("org.renpy.android.VideoPlayer")
|
||||
|
||||
class AndroidVideoChannel(object):
|
||||
|
||||
def __init__(self, name, file_prefix="", file_suffix="", default_loop=None):
|
||||
|
||||
# A list of queued filenames.
|
||||
self.queue = [ ]
|
||||
|
||||
# The filename that's currently playing.
|
||||
self.filename = None
|
||||
|
||||
# The videoplayer that's currently playing.
|
||||
self.player = None
|
||||
|
||||
# The name assigned to this channel. This is used to look up
|
||||
# information about the channel in the MusicContext object.
|
||||
self.name = name
|
||||
|
||||
# The name of the mixer this channel uses. Set below, as there's
|
||||
# no good default.
|
||||
self.mixer = None
|
||||
|
||||
# The time the music in this channel was last changed.
|
||||
self.last_changed = 0
|
||||
|
||||
# The callback that is called if the queue becomes empty.
|
||||
self.callback = None
|
||||
|
||||
# Ignored.
|
||||
self.synchro_start = False
|
||||
self.wait_stop = False
|
||||
self.loop = [ ]
|
||||
|
||||
# A prefix and suffix that are used to create the full filenames.
|
||||
self.file_prefix = file_prefix
|
||||
self.file_suffix = file_suffix
|
||||
|
||||
if default_loop is None:
|
||||
# By default, should we loop the music?
|
||||
self.default_loop = True
|
||||
# Was this set explicitly?
|
||||
self.default_loop_set = False
|
||||
|
||||
else:
|
||||
self.default_loop = default_loop
|
||||
self.default_loop_set = True
|
||||
|
||||
|
||||
def get_context(self):
|
||||
"""
|
||||
Returns the MusicContext corresponding to this channel, taken from
|
||||
the context object. Allocates a MusicContext if none exists.
|
||||
"""
|
||||
|
||||
mcd = renpy.game.context().music
|
||||
|
||||
rv = mcd.get(self.name)
|
||||
if rv is None:
|
||||
rv = mcd[self.name] = MusicContext()
|
||||
|
||||
return rv
|
||||
|
||||
context = property(get_context)
|
||||
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts playing the first video in the queue.
|
||||
"""
|
||||
|
||||
if not self.queue:
|
||||
return
|
||||
|
||||
filename = self.queue.pop(0)
|
||||
|
||||
f = renpy.loader.load(filename)
|
||||
|
||||
real_fn = f.name
|
||||
base = getattr(f, "base", -1)
|
||||
length = getattr(f, "length", -1)
|
||||
|
||||
self.filename = filename
|
||||
self.player = VideoPlayer(real_fn, base, length)
|
||||
|
||||
def stop(self):
|
||||
|
||||
if self.player is not None:
|
||||
self.player.stop()
|
||||
self.player = None
|
||||
|
||||
self.filename = None
|
||||
|
||||
def get_playing(self):
|
||||
|
||||
if self.player is None:
|
||||
return None
|
||||
|
||||
if self.player.isPlaying():
|
||||
return self.filename
|
||||
|
||||
def periodic(self):
|
||||
|
||||
# This should be set from something that checks to see if our
|
||||
# mixer is muted.
|
||||
force_stop = self.context.force_stop
|
||||
|
||||
if force_stop:
|
||||
self.dequeue()
|
||||
self.stop()
|
||||
return
|
||||
|
||||
if self.get_playing():
|
||||
return
|
||||
|
||||
if self.queue:
|
||||
self.start()
|
||||
|
||||
|
||||
def dequeue(self, even_tight=False):
|
||||
"""
|
||||
Clears the queued music, except for a first item that has
|
||||
not been started.
|
||||
"""
|
||||
|
||||
if self.get_playing():
|
||||
self.queue = [ ]
|
||||
else:
|
||||
self.queue = self.queue[:1]
|
||||
|
||||
|
||||
def interact(self):
|
||||
"""
|
||||
Called (mostly) once per interaction.
|
||||
"""
|
||||
|
||||
self.periodic()
|
||||
|
||||
|
||||
def fadeout(self, secs):
|
||||
"""
|
||||
Causes the playing music to be faded out for the given number
|
||||
of seconds. Also clears any queued music.
|
||||
"""
|
||||
|
||||
self.stop()
|
||||
self.queue = [ ]
|
||||
|
||||
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
|
||||
self.queue.extend(filenames)
|
||||
|
||||
def set_volume(self, volume):
|
||||
pass
|
||||
|
||||
def get_pos(self):
|
||||
pass
|
||||
|
||||
def set_pan(self, pan, delay):
|
||||
pass
|
||||
|
||||
def set_secondary_volume(self, volume, delay):
|
||||
pass
|
||||
|
||||
|
||||
# A list of channels we know about.
|
||||
all_channels = [ ]
|
||||
|
||||
@@ -512,7 +693,7 @@ channels = { }
|
||||
|
||||
def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix="", file_suffix="", buffer_queue=True):
|
||||
"""
|
||||
:doc: other
|
||||
:doc: audio
|
||||
|
||||
This registers a new audio channel named `name`. Audio can then be
|
||||
played on the channel by supplying the channel name to the play or
|
||||
@@ -529,7 +710,7 @@ def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False
|
||||
|
||||
`stop_on_mute`
|
||||
If true, music on the channel is stopped when the channel is muted.
|
||||
|
||||
|
||||
`tight`
|
||||
If true, sounds will loop even when fadeout is occuring. This should
|
||||
be set to True for a sound effects or seamless music channel, and False
|
||||
@@ -551,12 +732,17 @@ def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False
|
||||
if not renpy.game.context().init_phase:
|
||||
raise Exception("Can't register channel outside of init phase.")
|
||||
|
||||
c = Channel(name, loop, stop_on_mute, tight, file_prefix, file_suffix, buffer_queue)
|
||||
if renpy.android and name == "movie":
|
||||
c = AndroidVideoChannel(name, default_loop=loop, file_prefix=file_prefix, file_suffix=file_suffix)
|
||||
else:
|
||||
c = Channel(name, loop, stop_on_mute, tight, file_prefix, file_suffix, buffer_queue)
|
||||
|
||||
c.mixer = mixer
|
||||
|
||||
all_channels.append(c)
|
||||
channels[name] = c
|
||||
|
||||
|
||||
|
||||
def alias_channel(name, newname):
|
||||
if not renpy.game.context().init_phase:
|
||||
raise Exception("Can't alias channel outside of init phase.")
|
||||
@@ -564,13 +750,13 @@ def alias_channel(name, newname):
|
||||
c = get_channel(name)
|
||||
channels[newname] = c
|
||||
|
||||
|
||||
|
||||
def get_channel(name):
|
||||
|
||||
rv = channels.get(name)
|
||||
if rv is None:
|
||||
raise Exception("Audio channel %r is unknown." % name)
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
def set_force_stop(name, value):
|
||||
@@ -588,7 +774,7 @@ def init():
|
||||
|
||||
if pcm_ok is None and pss:
|
||||
bufsize = 2048
|
||||
|
||||
|
||||
if 'RENPY_SOUND_BUFSIZE' in os.environ:
|
||||
bufsize = int(os.environ['RENPY_SOUND_BUFSIZE'])
|
||||
|
||||
@@ -608,7 +794,7 @@ def init():
|
||||
mixers.append(c.mixer)
|
||||
|
||||
default_volume = 1.0
|
||||
|
||||
|
||||
for m in mixers:
|
||||
renpy.game.preferences.volumes.setdefault(m, default_volume)
|
||||
renpy.game.preferences.mute.setdefault(m, False)
|
||||
@@ -621,23 +807,23 @@ def quit(): #@ReservedAssignment
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
|
||||
for c in all_channels:
|
||||
c.dequeue()
|
||||
c.fadeout(0)
|
||||
|
||||
|
||||
c.queue = [ ]
|
||||
c.loop = [ ]
|
||||
c.playing = False
|
||||
c.playing_midi = False
|
||||
c.wait_stop = False
|
||||
c.synchro_start = False
|
||||
|
||||
|
||||
pss.quit()
|
||||
|
||||
|
||||
pcm_ok = None
|
||||
mix_ok = None
|
||||
|
||||
|
||||
# The last-set pcm volume.
|
||||
pcm_volume = None
|
||||
|
||||
@@ -661,12 +847,12 @@ def periodic():
|
||||
c.periodic()
|
||||
|
||||
pss.periodic()
|
||||
|
||||
|
||||
# Perform a synchro-start if necessary.
|
||||
need_ss = False
|
||||
|
||||
for c in all_channels:
|
||||
|
||||
|
||||
if c.synchro_start and c.wait_stop:
|
||||
need_ss = False
|
||||
break
|
||||
@@ -680,23 +866,11 @@ def periodic():
|
||||
for c in all_channels:
|
||||
c.synchro_start = False
|
||||
|
||||
# Now, consider adjusting the volume of the channel.
|
||||
|
||||
volumes = renpy.game.preferences.volumes
|
||||
|
||||
for c in all_channels:
|
||||
|
||||
vol = c.chan_volume * volumes[c.mixer]
|
||||
|
||||
if vol != c.actual_volume:
|
||||
pss.set_volume(c.number, vol)
|
||||
c.actual_volume = vol
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
|
||||
def interact():
|
||||
"""
|
||||
Called at least once per interaction.
|
||||
@@ -714,7 +888,7 @@ def interact():
|
||||
# c.set_volume(_music_volumes.get(i, 1.0))
|
||||
|
||||
ctx = c.context
|
||||
|
||||
|
||||
# If we're in the same music change, then do nothing with the
|
||||
# music.
|
||||
if c.last_changed == ctx.last_changed:
|
||||
|
||||
+132
-67
@@ -37,45 +37,57 @@ register_channel; alias_channel
|
||||
|
||||
def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=False, fadein=0, tight=None, if_changed=False):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
This stops the music currently playing on the numbered channel, dequeues
|
||||
any queued music, and begins playing the specified file or files. If loop
|
||||
is True, the tracks will loop while they are the last thing in
|
||||
the queue. If fadeout is None, the fadeout time is taken from
|
||||
config.fade_music, otherwise it is a time in seconds to fade for.
|
||||
any queued music, and begins playing the specified file or files.
|
||||
|
||||
Filenames may be a single file, or a list of files.
|
||||
`filenames`
|
||||
This may be a single file, or a list of files to be played.
|
||||
|
||||
Fadein is the number of seconds to fade the music in for, on the
|
||||
first loop only.
|
||||
|
||||
If synchro_start is given, all the channels that have had play
|
||||
called on them with synchro_start set to True will be started at
|
||||
the same time, in a sample accurate manner.
|
||||
|
||||
The filenames given becomes the last queued files if loop is
|
||||
True. If loop is False, then there are no last queued files.
|
||||
|
||||
If tight is True, then fadeouts will span into the next-queued sound.
|
||||
`channel`
|
||||
The channel to play the sound on.
|
||||
|
||||
If if_changed is True, and the music file is currently playing,
|
||||
then it will not be stopped/faded out and faded back in again, but
|
||||
instead will be kept playing. (This will always queue up an additional
|
||||
loop of the music.)
|
||||
`loop`
|
||||
If this is True, the tracks will loop while they are the last thing
|
||||
in the queue.
|
||||
|
||||
`fadeout`
|
||||
If not None, this is a time in seconds to fade for. Otherwise the
|
||||
fadeout time is taken from config.fade_music.
|
||||
|
||||
`synchro_start`
|
||||
If synchro_start is given, all the channels that have had play
|
||||
called on them with synchro_start set to True will be started at
|
||||
the same time, in a sample accurate manner.
|
||||
|
||||
`fadein`
|
||||
This is the number of seconds to fade the music in for, on the
|
||||
first loop only.
|
||||
|
||||
`tight`
|
||||
If this is True, then fadeouts will span into the next-queued sound.
|
||||
|
||||
`if_changed`
|
||||
If this is True, and the music file is currently playing,
|
||||
then it will not be stopped/faded out and faded back in again, but
|
||||
instead will be kept playing. (This will always queue up an additional
|
||||
loop of the music.)
|
||||
"""
|
||||
|
||||
if renpy.game.context().init_phase:
|
||||
raise Exception("Can't play music during init phase.")
|
||||
|
||||
|
||||
if filenames is None:
|
||||
return
|
||||
|
||||
|
||||
if isinstance(filenames, basestring):
|
||||
filenames = [ filenames ]
|
||||
|
||||
try:
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
|
||||
@@ -90,44 +102,51 @@ def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=Fals
|
||||
c.fadeout(fadeout)
|
||||
|
||||
c.enqueue(filenames, loop=loop, synchro_start=synchro_start, fadein=fadein, tight=tight)
|
||||
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
|
||||
if loop:
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
|
||||
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=None):
|
||||
"""
|
||||
This queues the given filenames on the specified channel. If
|
||||
clear_queue is True, then the queue is cleared, making these files
|
||||
the files that are played when the currently playing file
|
||||
finishes. If it is False, then these files are placed at the back of
|
||||
the queue. In either case, if no music is playing these files
|
||||
begin playing immediately.
|
||||
:doc: audio
|
||||
|
||||
Filenames may either be a single filename, or a list of filenames.
|
||||
This queues the given filenames on the specified channel.
|
||||
|
||||
Fadein is the number of seconds to fade the music in for, on the
|
||||
first loop only.
|
||||
`filenames`
|
||||
This may be a single file, or a list of files to be played.
|
||||
|
||||
If loop is True, then this music will repeat as long as it is the
|
||||
last element of the queue.
|
||||
`channel`
|
||||
The channel to play the sound on.
|
||||
|
||||
`loop`
|
||||
If this is True, the tracks will loop while they are the last thing
|
||||
in the queue.
|
||||
|
||||
The filenames given becomes the last queued file if loop is
|
||||
True. If loop is False, then the last queued file is set to None.
|
||||
`clear_queue`
|
||||
If True, then the queue is cleared, making these files the files that
|
||||
are played when the currently playing file finishes. If it is False,
|
||||
then these files are placed at the back of the queue. In either case,
|
||||
if no music is playing these files begin playing immediately.
|
||||
|
||||
If tight is True, then fadeouts will span into the next-queued sound.
|
||||
`fadein`
|
||||
This is the number of seconds to fade the music in for, on the
|
||||
first loop only.
|
||||
|
||||
`tight`
|
||||
If this is True, then fadeouts will span into the next-queued sound.
|
||||
"""
|
||||
|
||||
if renpy.game.context().init_phase:
|
||||
@@ -140,19 +159,19 @@ def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tig
|
||||
if isinstance(filenames, basestring):
|
||||
filenames = [ filenames ]
|
||||
|
||||
try:
|
||||
try:
|
||||
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
|
||||
|
||||
if clear_queue:
|
||||
c.dequeue(True)
|
||||
|
||||
|
||||
c.enqueue(filenames, loop=loop, fadein=fadein, tight=tight)
|
||||
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
@@ -163,7 +182,7 @@ def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tig
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
@@ -175,43 +194,54 @@ def playable(filename, channel="music"):
|
||||
"""
|
||||
|
||||
c = get_channel(channel)
|
||||
|
||||
|
||||
return renpy.loader.loadable(c.file_prefix + filename + c.file_suffix)
|
||||
|
||||
|
||||
|
||||
|
||||
def stop(channel="music", fadeout=None):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
This stops the music that is currently playing, and dequeues all
|
||||
queued music. If fadeout is None, the music is faded out for the
|
||||
time given in config.fade_music, otherwise it is faded for fadeout
|
||||
seconds.
|
||||
|
||||
|
||||
This sets the last queued file to None.
|
||||
|
||||
`channel`
|
||||
The channel to stop the sound on.
|
||||
|
||||
`fadeout`
|
||||
If not None, this is a time in seconds to fade for. Otherwise the
|
||||
fadeout time is taken from config.fade_music.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if renpy.game.context().init_phase:
|
||||
return
|
||||
|
||||
try:
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
if fadeout is None:
|
||||
fadeout = renpy.config.fade_music
|
||||
|
||||
c.fadeout(fadeout)
|
||||
|
||||
c.fadeout(fadeout)
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
|
||||
def set_music(channel, flag, default=False):
|
||||
"""
|
||||
Determines if channel will loop by default.
|
||||
@@ -224,7 +254,7 @@ def set_music(channel, flag, default=False):
|
||||
|
||||
c.default_loop = flag
|
||||
c.default_loop_set = True
|
||||
|
||||
|
||||
def get_delay(time, channel="music"):
|
||||
"""
|
||||
Returns the number of seconds left until the given time in the
|
||||
@@ -248,9 +278,11 @@ def get_delay(time, channel="music"):
|
||||
raise
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_playing(channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
Returns true if the given channel is playing.
|
||||
"""
|
||||
|
||||
@@ -265,20 +297,36 @@ def get_playing(channel="music"):
|
||||
|
||||
def is_playing(channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
Returns True if the channel is currently playing a sound, False if
|
||||
it is not, or if the sound system isn't working.
|
||||
"""
|
||||
|
||||
|
||||
return (get_playing(channel=channel) is not None)
|
||||
|
||||
|
||||
def set_volume(volume, delay=0, channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
Sets the volume of this channel, as a fraction of the volume of the
|
||||
mixer controlling the channel.
|
||||
|
||||
`volume`
|
||||
This is a number between 0.0 and 1.0, and is interpreted as a fraction
|
||||
of the mixer volume for the channel.
|
||||
|
||||
`delay`
|
||||
It takes delay seconds to change/fade the volume from the old to
|
||||
the new value. This value is persisted into saves, and participates
|
||||
in rollback.
|
||||
|
||||
`channel`
|
||||
The channel to be set
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
c = renpy.audio.audio.get_channel(channel)
|
||||
c.set_secondary_volume(volume, delay)
|
||||
except:
|
||||
@@ -287,10 +335,25 @@ def set_volume(volume, delay=0, channel="music"):
|
||||
|
||||
def set_pan(pan, delay, channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
Sets the pan of this channel.
|
||||
|
||||
`pan`
|
||||
A number between -1 and 1 that control the placement of the audio.
|
||||
If this is -1, then all audio is sent to the left channel.
|
||||
If it's 0, then the two channels are equally balanced. If it's 1,
|
||||
then all audio is sent to the right ear.
|
||||
|
||||
`delay`
|
||||
The amount of time it takes for the panning to occur.
|
||||
|
||||
`channel`
|
||||
The channel the panning takes place on. This can be a sound or a music
|
||||
channel. Often, this is channel 7, the default music channel.
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
c = renpy.audio.audio.get_channel(channel)
|
||||
c.set_pan(pan, delay)
|
||||
except:
|
||||
@@ -299,6 +362,8 @@ def set_pan(pan, delay, channel="music"):
|
||||
|
||||
def set_queue_empty_callback(callback, channel="music"):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
This sets a callback that is called when the queue is empty. This
|
||||
callback is called when the queue first becomes empty, and at
|
||||
least once per interaction while the queue is empty.
|
||||
@@ -308,7 +373,7 @@ def set_queue_empty_callback(callback, channel="music"):
|
||||
note that the callback may be called while a sound is playing, as
|
||||
long as a queue slot is empty.
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
c = renpy.audio.audio.get_channel(channel)
|
||||
c.callback = callback
|
||||
except:
|
||||
@@ -327,7 +392,7 @@ def set_mixer(channel, mixer, default=False):
|
||||
This function should only be called in an init block.
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
c = renpy.audio.audio.get_channel(channel)
|
||||
|
||||
if not default or c.mixer is None:
|
||||
@@ -342,12 +407,12 @@ def channel_defined(channel):
|
||||
Returns True if the channel exists, or False otherwise.
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
renpy.audio.audio.get_channel(channel)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# Music change logic:
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ def queue(filename, channel="sound", clear_queue=True, fadein=0, tight=False, lo
|
||||
def stop(channel="sound", fadeout=0):
|
||||
renpy.audio.music.stop(channel=channel,
|
||||
fadeout=fadeout)
|
||||
|
||||
|
||||
set_mixer = renpy.audio.music.set_mixer
|
||||
set_queue_empty_callback = renpy.audio.music.set_queue_empty_callback
|
||||
|
||||
|
||||
+60
-62
@@ -55,7 +55,7 @@ def extra_imports():
|
||||
import difflib; difflib
|
||||
import shutil; shutil
|
||||
import tarfile; tarfile
|
||||
import bz2; bz2
|
||||
import bz2; bz2 # @UnresolvedImport
|
||||
import webbrowser; webbrowser
|
||||
import pygame.locals; pygame.locals
|
||||
import pygame.color; pygame.color
|
||||
@@ -74,31 +74,31 @@ def extra_imports():
|
||||
import rsa; rsa
|
||||
import decimal; decimal
|
||||
import plistlib; plistlib
|
||||
|
||||
|
||||
class NullFile(io.IOBase):
|
||||
"""
|
||||
This file raises an error on input, and IOError on read.
|
||||
"""
|
||||
|
||||
|
||||
def write(self, s):
|
||||
return
|
||||
|
||||
|
||||
def read(self, length=None):
|
||||
raise IOError("Not implemented.")
|
||||
|
||||
|
||||
def null_files():
|
||||
try:
|
||||
if sys.stderr.fileno() < 0:
|
||||
sys.stderr = NullFile()
|
||||
|
||||
|
||||
if sys.stdout.fileno() < 0:
|
||||
sys.stdout = NullFile()
|
||||
except:
|
||||
pass
|
||||
|
||||
null_files()
|
||||
|
||||
|
||||
|
||||
|
||||
trace_file = None
|
||||
trace_local = None
|
||||
|
||||
@@ -106,7 +106,7 @@ def trace_function(frame, event, arg):
|
||||
fn = os.path.basename(frame.f_code.co_filename)
|
||||
print >>trace_file, fn, frame.f_lineno, frame.f_code.co_name, event
|
||||
return trace_local
|
||||
|
||||
|
||||
def enable_trace(level):
|
||||
global trace_file
|
||||
global trace_local
|
||||
@@ -117,7 +117,7 @@ def enable_trace(level):
|
||||
trace_local = trace_function
|
||||
else:
|
||||
trace_local = None
|
||||
|
||||
|
||||
sys.settrace(trace_function)
|
||||
|
||||
def mac_start(fn):
|
||||
@@ -136,7 +136,7 @@ def bootstrap(renpy_base):
|
||||
os.environ["RENPY_BASE"] = os.path.abspath(renpy_base)
|
||||
|
||||
renpy_base = unicode(renpy_base, FSENCODING, "replace")
|
||||
|
||||
|
||||
# If environment.txt exists, load it into the os.environ dictionary.
|
||||
if os.path.exists(renpy_base + "/environment.txt"):
|
||||
evars = { }
|
||||
@@ -150,14 +150,14 @@ def bootstrap(renpy_base):
|
||||
alt_path = os.path.abspath("renpy_base")
|
||||
if ".app" in alt_path:
|
||||
alt_path = alt_path[:alt_path.find(".app")+4]
|
||||
|
||||
|
||||
if os.path.exists(alt_path + "/environment.txt"):
|
||||
evars = { }
|
||||
execfile(alt_path + "/environment.txt", evars)
|
||||
for k, v in evars.iteritems():
|
||||
if k not in os.environ:
|
||||
os.environ[k] = str(v)
|
||||
|
||||
|
||||
# Get a working name for the game.
|
||||
name = os.path.basename(sys.argv[0])
|
||||
|
||||
@@ -173,7 +173,7 @@ def bootstrap(renpy_base):
|
||||
if args.command == "presplash":
|
||||
import renpy.display.presplash
|
||||
renpy.display.presplash.show(sys.argv[3])
|
||||
|
||||
|
||||
if args.trace:
|
||||
enable_trace(args.trace)
|
||||
|
||||
@@ -181,7 +181,7 @@ def bootstrap(renpy_base):
|
||||
basedir = os.path.abspath(args.basedir).decode(FSENCODING)
|
||||
else:
|
||||
basedir = renpy_base
|
||||
|
||||
|
||||
|
||||
gamedirs = [ name ]
|
||||
game_name = name
|
||||
@@ -207,7 +207,7 @@ def bootstrap(renpy_base):
|
||||
gamedir = basedir
|
||||
|
||||
sys.path.insert(0, basedir)
|
||||
|
||||
|
||||
# Force windib on windows, unless the user explicitly overrides.
|
||||
if renpy.windows and not 'SDL_VIDEODRIVER' in os.environ:
|
||||
os.environ['SDL_VIDEODRIVER'] = 'windib'
|
||||
@@ -220,7 +220,7 @@ def bootstrap(renpy_base):
|
||||
# If we're on a mac, install our own os.start.
|
||||
if renpy.macintosh:
|
||||
os.startfile = mac_start
|
||||
|
||||
|
||||
# Check that we have installed pygame properly. This also deals with
|
||||
# weird cases on Windows and Linux where we can't import modules. (On
|
||||
# windows ";" is a directory separator in PATH, so if it's in a parent
|
||||
@@ -230,12 +230,12 @@ def bootstrap(renpy_base):
|
||||
import pygame; pygame
|
||||
except:
|
||||
print >>sys.stderr, """\
|
||||
Could not import pygame. Please ensure that this program has been built
|
||||
and unpacked properly. Also, make sure that the directories containing
|
||||
Could not import pygame. Please ensure that this program has been built
|
||||
and unpacked properly. Also, make sure that the directories containing
|
||||
this program do not contain : or ; in their names.
|
||||
"""
|
||||
raise
|
||||
|
||||
|
||||
# Load up all of Ren'Py, in the right order.
|
||||
|
||||
import renpy #@Reimport
|
||||
@@ -253,7 +253,7 @@ this program do not contain : or ; in their names.
|
||||
renpy.config.basedir = basedir
|
||||
renpy.config.gamedir = gamedir
|
||||
renpy.config.args = [ ]
|
||||
|
||||
|
||||
if renpy.android:
|
||||
renpy.config.logdir = os.environ['ANDROID_PUBLIC']
|
||||
else:
|
||||
@@ -274,7 +274,7 @@ this program do not contain : or ; in their names.
|
||||
if renpy.display.draw:
|
||||
renpy.display.draw.deinit()
|
||||
renpy.display.draw.quit()
|
||||
|
||||
|
||||
# On an UtterRestart, reload Ren'Py.
|
||||
renpy.reload_all()
|
||||
continue
|
||||
@@ -292,7 +292,7 @@ this program do not contain : or ; in their names.
|
||||
sys.exit(0)
|
||||
|
||||
finally:
|
||||
|
||||
|
||||
if "RENPY_SHUTDOWN_TRACE" in os.environ:
|
||||
enable_trace(int(os.environ["RENPY_SHUTDOWN_TRACE"]))
|
||||
|
||||
@@ -301,8 +301,6 @@ this program do not contain : or ; in their names.
|
||||
if renpy.display.draw:
|
||||
renpy.display.draw.quit()
|
||||
|
||||
renpy.translation.write_updated_strings()
|
||||
|
||||
# Prevent subprocess from throwing errors while trying to run it's
|
||||
# __del__ method during shutdown.
|
||||
import subprocess # W0403
|
||||
@@ -312,12 +310,12 @@ def report_line(out, filename, line, what):
|
||||
out.write(' File "%s", line %d, in %s\n' % (filename, line, what))
|
||||
try:
|
||||
fn = renpy.parser.unelide_filename(filename)
|
||||
f = file(fn, "rb")
|
||||
f = file(fn, "rb")
|
||||
lines = f.read().decode("utf-8").replace("\r", "").split("\n")
|
||||
out.write(" " + lines[line - 1].encode("utf-8") + "\n")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def write_utf8_traceback_list(out, l):
|
||||
"""
|
||||
@@ -327,28 +325,28 @@ def write_utf8_traceback_list(out, l):
|
||||
ul = [ ]
|
||||
|
||||
for filename, line, what, text in l:
|
||||
|
||||
|
||||
# Filename is either unicode or an fsecoded string.
|
||||
if not isinstance(filename, unicode):
|
||||
filename = unicode(filename, FSENCODING, "replace")
|
||||
|
||||
|
||||
# Line is a number.
|
||||
|
||||
|
||||
# Assume what is in a unicode encoding, since it is either python,
|
||||
# or comes from inside Ren'Py.
|
||||
|
||||
# or comes from inside Ren'Py.
|
||||
|
||||
if isinstance(text, str):
|
||||
text = text.decode("utf-8", "replace")
|
||||
|
||||
|
||||
ul.append((filename, line, what, text))
|
||||
|
||||
|
||||
for t in traceback.format_list(ul):
|
||||
out.write(t.encode("utf-8", "replace"))
|
||||
|
||||
|
||||
|
||||
def script_level_traceback(out, tb):
|
||||
"""
|
||||
Writes a script-level traceback to out, based on the traceback
|
||||
Writes a script-level traceback to out, based on the traceback
|
||||
object tb.
|
||||
"""
|
||||
|
||||
@@ -359,15 +357,15 @@ def script_level_traceback(out, tb):
|
||||
line = tb.tb_lineno
|
||||
co = f.f_code
|
||||
filename = co.co_filename
|
||||
|
||||
|
||||
if filename.endswith(".rpy") and not filename.replace("\\", "/").startswith("common/"):
|
||||
tbl.append((filename, line, "python", None))
|
||||
|
||||
elif 'self' in f.f_locals:
|
||||
obj = f.f_locals['self']
|
||||
|
||||
|
||||
import renpy
|
||||
|
||||
|
||||
if isinstance(obj, renpy.execution.Context):
|
||||
tbl.extend(obj.report_tb(out))
|
||||
|
||||
@@ -380,34 +378,34 @@ def open_error_file(fn, mode):
|
||||
Opens an error/log/file. Returns the open file, and the filename that
|
||||
was opened.
|
||||
"""
|
||||
|
||||
|
||||
try:
|
||||
f = file(os.path.join(renpy.config.logdir, fn), mode)
|
||||
return f, fn
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
f = file(fn, mode)
|
||||
return f, fn
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
import tempfile
|
||||
|
||||
|
||||
fn = os.path.join(tempfile.gettempdir(), "renpy-" + fn)
|
||||
return file(fn, mode), fn
|
||||
|
||||
def report_exception(e, editor=True):
|
||||
"""
|
||||
Reports an exception by writing it to standard error and
|
||||
traceback.txt. If `editor` is True, opens the traceback
|
||||
Reports an exception by writing it to standard error and
|
||||
traceback.txt. If `editor` is True, opens the traceback
|
||||
up in a text editor.
|
||||
|
||||
Returns a two-unicode tuple, with the first item being
|
||||
|
||||
Returns a two-unicode tuple, with the first item being
|
||||
a simple message, and the second being a full traceback.
|
||||
"""
|
||||
|
||||
|
||||
import codecs
|
||||
|
||||
type, _value, tb = sys.exc_info() #@ReservedAssignment
|
||||
@@ -417,27 +415,27 @@ def report_exception(e, editor=True):
|
||||
m = unicode(e)
|
||||
except:
|
||||
m = str(e)
|
||||
|
||||
|
||||
if isinstance(m, unicode):
|
||||
return m.encode("utf-8", "replace")
|
||||
else:
|
||||
return m
|
||||
|
||||
|
||||
# Return values - which can be displayed to the user.
|
||||
simple = cStringIO.StringIO()
|
||||
full = cStringIO.StringIO()
|
||||
|
||||
|
||||
print >>simple, renpy.game.exception_info
|
||||
script_level_traceback(simple, tb)
|
||||
print >>simple, type.__name__ + ":",
|
||||
print >>simple, type.__name__ + ":",
|
||||
print >>simple, safe_utf8(e)
|
||||
|
||||
print >>full, "Full traceback:"
|
||||
tbl = traceback.extract_tb(tb)
|
||||
write_utf8_traceback_list(full, tbl)
|
||||
print >>full, type.__name__ + ":",
|
||||
print >>full, type.__name__ + ":",
|
||||
print >>full, safe_utf8(e)
|
||||
|
||||
|
||||
# Write to stdout/stderr.
|
||||
sys.stdout.write("\n")
|
||||
sys.stdout.write(full.getvalue())
|
||||
@@ -452,10 +450,10 @@ def report_exception(e, editor=True):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
simple = simple.getvalue()
|
||||
full = full.getvalue()
|
||||
|
||||
|
||||
# Inside of the file, which may not be openable.
|
||||
try:
|
||||
|
||||
@@ -467,14 +465,14 @@ def report_exception(e, editor=True):
|
||||
print >>f
|
||||
|
||||
f.write(simple)
|
||||
|
||||
|
||||
print >>f
|
||||
print >>f, "-- Full Traceback ------------------------------------------------------------"
|
||||
print >>f
|
||||
print >>f
|
||||
|
||||
f.write(full)
|
||||
f.close()
|
||||
|
||||
|
||||
try:
|
||||
if editor and renpy.game.args.command == "run": #@UndefinedVariable
|
||||
renpy.exports.launch_editor([ traceback_fn ], 1, transient=1)
|
||||
@@ -496,12 +494,12 @@ old_memory = { }
|
||||
|
||||
def memory_profile():
|
||||
"""
|
||||
Calling this function displays the change in the number of instances of
|
||||
Calling this function displays the change in the number of instances of
|
||||
each type of object.
|
||||
"""
|
||||
|
||||
|
||||
print "- Memory Profile ---------------------------------------------------"
|
||||
|
||||
|
||||
import gc
|
||||
gc.collect()
|
||||
|
||||
|
||||
Regular → Executable
+119
-107
@@ -47,14 +47,14 @@ class DialogueTextTags(object):
|
||||
|
||||
# The time to delay for each pause. None to delay forever.
|
||||
self.pause_delay = [ ]
|
||||
|
||||
|
||||
# True if we've encountered the no-wait tag.
|
||||
self.no_wait = False
|
||||
|
||||
|
||||
i = iter(TAG_RE.split(s))
|
||||
|
||||
while True:
|
||||
|
||||
|
||||
try:
|
||||
self.text += i.next()
|
||||
|
||||
@@ -65,7 +65,7 @@ class DialogueTextTags(object):
|
||||
|
||||
if value is not None:
|
||||
value = float(value)
|
||||
|
||||
|
||||
if quoted is not None:
|
||||
self.text += quoted
|
||||
continue
|
||||
@@ -85,13 +85,13 @@ class DialogueTextTags(object):
|
||||
self.no_wait = False
|
||||
|
||||
self.text += full_tag
|
||||
|
||||
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
self.pause_end.append(len(self.text))
|
||||
|
||||
if self.no_wait:
|
||||
if self.no_wait:
|
||||
self.pause_delay.append(0)
|
||||
else:
|
||||
self.pause_delay.append(None)
|
||||
@@ -117,9 +117,9 @@ def predict_show_display_say(who, what, who_args, what_args, window_args, image=
|
||||
two_window=two_window,
|
||||
side_image=side_image,
|
||||
**kwargs)
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
if image:
|
||||
if image != "<Dynamic>":
|
||||
renpy.easy.predict(who)
|
||||
@@ -139,16 +139,16 @@ def compute_widget_properties(who_args, what_args, window_args, variant=None):
|
||||
return d
|
||||
|
||||
in_rollback = renpy.exports.in_rollback()
|
||||
|
||||
|
||||
if (not in_rollback) and (not variant):
|
||||
return d
|
||||
|
||||
|
||||
d = d.copy()
|
||||
|
||||
|
||||
style = d["style"]
|
||||
|
||||
if isinstance(style, basestring):
|
||||
style = getattr(renpy.store.style, style)
|
||||
style = getattr(renpy.store.style, style)
|
||||
|
||||
if variant is not None:
|
||||
style = style[variant]
|
||||
@@ -159,7 +159,7 @@ def compute_widget_properties(who_args, what_args, window_args, variant=None):
|
||||
d["style"] = style
|
||||
|
||||
return d
|
||||
|
||||
|
||||
who_args = style_args(who_args)
|
||||
what_args = style_args(what_args)
|
||||
window_args = style_args(window_args)
|
||||
@@ -212,9 +212,9 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
|
||||
This function is required to return the ui.text() widget
|
||||
displaying the what text.
|
||||
"""
|
||||
|
||||
|
||||
props = compute_widget_properties(who_args, what_args, window_args, variant=variant)
|
||||
|
||||
|
||||
def handle_who():
|
||||
if who:
|
||||
if image:
|
||||
@@ -229,10 +229,10 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
|
||||
|
||||
if variant is not None:
|
||||
style = style[variant]
|
||||
|
||||
|
||||
if renpy.exports.in_rollback():
|
||||
style = style["rollback"]
|
||||
|
||||
|
||||
rv = dict(style=style)
|
||||
rv.update(properties)
|
||||
return rv
|
||||
@@ -241,11 +241,11 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
|
||||
|
||||
tag = screen
|
||||
index = 0
|
||||
|
||||
|
||||
while renpy.exports.showing(tag):
|
||||
index += 1
|
||||
tag = "%s%d" % (screen, index)
|
||||
|
||||
|
||||
renpy.display.screen.show_screen(
|
||||
screen,
|
||||
_widget_properties=props,
|
||||
@@ -261,12 +261,12 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
|
||||
renpy.exports.shown_window()
|
||||
|
||||
return renpy.display.screen.get_widget(screen, "what")
|
||||
|
||||
|
||||
|
||||
|
||||
# Apply the transform.
|
||||
if transform:
|
||||
renpy.ui.at(transform)
|
||||
|
||||
|
||||
if two_window:
|
||||
|
||||
# Opens say_two_window_vbox.
|
||||
@@ -295,7 +295,7 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
|
||||
renpy.ui.image(side_image)
|
||||
|
||||
renpy.exports.shown_window()
|
||||
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ class SlowDone(object):
|
||||
self.type = type
|
||||
self.cb_args = cb_args
|
||||
self.delay = delay
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if self.ctc and self.ctc_position == "fixed":
|
||||
@@ -321,11 +321,11 @@ class SlowDone(object):
|
||||
if self.delay is not None:
|
||||
renpy.ui.pausebehavior(self.delay, True)
|
||||
renpy.exports.restart_interaction()
|
||||
|
||||
|
||||
for c in self.callback:
|
||||
c("slow_done", interact=self.interact, type=self.type, **self.cb_args)
|
||||
|
||||
|
||||
|
||||
# This function takes care of repeatably showing the screen as part of
|
||||
# an interaction.
|
||||
def display_say(
|
||||
@@ -347,10 +347,12 @@ def display_say(
|
||||
ctc_timedpause=None,
|
||||
ctc_force=False):
|
||||
|
||||
if (not renpy.game.preferences.skip_unseen) and (not renpy.game.context().seen_current(True)) and renpy.config.skipping == "fast":
|
||||
renpy.config.skipping = None
|
||||
# If we're in fast skipping mode, don't bother with say
|
||||
# statements at all.
|
||||
if interact and renpy.config.skipping == "fast":
|
||||
|
||||
|
||||
# Clears out transients.
|
||||
renpy.exports.with_statement(None)
|
||||
return
|
||||
@@ -361,30 +363,30 @@ def display_say(
|
||||
callback = [ renpy.config.character_callback ]
|
||||
else:
|
||||
callback = [ ]
|
||||
|
||||
|
||||
if not isinstance(callback, list):
|
||||
callback = [ callback ]
|
||||
|
||||
callback = renpy.config.all_character_callbacks + callback
|
||||
|
||||
callback = renpy.config.all_character_callbacks + callback
|
||||
|
||||
# Call the begin callback.
|
||||
for c in callback:
|
||||
c("begin", interact=interact, type=type, **cb_args)
|
||||
|
||||
|
||||
if renpy.exports.roll_forward_info():
|
||||
roll_forward = False
|
||||
else:
|
||||
roll_forward = None
|
||||
|
||||
|
||||
# If we're just after a rollback or roll_forward, disable slow.
|
||||
after_rollback = renpy.game.after_rollback
|
||||
if after_rollback:
|
||||
slow = False
|
||||
|
||||
|
||||
# If we're committed to skipping this statement, disable slow.
|
||||
elif (renpy.config.skipping and
|
||||
(renpy.game.preferences.skip_unseen or
|
||||
renpy.game.context().seen_current(True))):
|
||||
renpy.game.context().seen_current(True))):
|
||||
slow = False
|
||||
|
||||
# Figure out which pause we're on. (Or set the pause to None in
|
||||
@@ -403,20 +405,20 @@ def display_say(
|
||||
pause_end = dtt.pause_end
|
||||
pause_delay = dtt.pause_delay
|
||||
|
||||
|
||||
|
||||
for i, (start, end, delay) in enumerate(zip(pause_start, pause_end, pause_delay)):
|
||||
|
||||
last_pause = (i == len(pause_start) - 1)
|
||||
|
||||
|
||||
# If we're going to do an interaction, then saybehavior needs
|
||||
# to be here.
|
||||
if interact:
|
||||
behavior = renpy.ui.saybehavior(allow_dismiss=renpy.config.say_allow_dismiss)
|
||||
if interact:
|
||||
behavior = renpy.ui.saybehavior(allow_dismiss=renpy.config.say_allow_dismiss)
|
||||
else:
|
||||
behavior = None
|
||||
|
||||
|
||||
# The string to show.
|
||||
|
||||
# The string to show.
|
||||
what_string = dtt.text
|
||||
|
||||
# Figure out the CTC to use, if any.
|
||||
@@ -427,10 +429,10 @@ def display_say(
|
||||
what_ctc = ctc_timedpause or ctc_pause
|
||||
else:
|
||||
what_ctc = ctc_pause
|
||||
|
||||
|
||||
if not (interact or ctc_force):
|
||||
what_ctc = None
|
||||
|
||||
|
||||
what_ctc = renpy.easy.displayable_or_none(what_ctc)
|
||||
|
||||
if what_ctc is not None:
|
||||
@@ -438,10 +440,10 @@ def display_say(
|
||||
|
||||
if delay == 0:
|
||||
what_ctc = None
|
||||
|
||||
|
||||
# Create the callback that is called when the slow text is done.
|
||||
slow_done = SlowDone(what_ctc, ctc_position, callback, interact, type, cb_args, delay)
|
||||
|
||||
|
||||
# Run the show callback.
|
||||
for c in callback:
|
||||
c("show", interact=interact, type=type, **cb_args)
|
||||
@@ -454,7 +456,7 @@ def display_say(
|
||||
|
||||
if what_ctc and ctc_position == "nestled":
|
||||
what_text.set_ctc(what_ctc)
|
||||
|
||||
|
||||
# Update the properties of the what_text widget.
|
||||
what_text.start = start
|
||||
what_text.end = end
|
||||
@@ -470,18 +472,18 @@ def display_say(
|
||||
if not slow:
|
||||
slow_done()
|
||||
|
||||
if interact:
|
||||
if interact:
|
||||
rv = renpy.ui.interact(mouse='say', type=type, roll_forward=roll_forward)
|
||||
|
||||
# This is only the case if the user has rolled forward, {nw} happens, or
|
||||
# maybe in some other obscure cases.
|
||||
if rv is False:
|
||||
break
|
||||
break
|
||||
|
||||
if not last_pause:
|
||||
for i in renpy.config.say_sustain_callbacks:
|
||||
i()
|
||||
|
||||
|
||||
# Do the checkpoint and with None.
|
||||
if interact:
|
||||
|
||||
@@ -490,7 +492,7 @@ def display_say(
|
||||
renpy.exports.checkpoint(True)
|
||||
else:
|
||||
renpy.game.after_rollback = after_rollback
|
||||
|
||||
|
||||
if with_none is None:
|
||||
with_none = renpy.config.implicit_with_none
|
||||
|
||||
@@ -524,7 +526,7 @@ class ADVCharacter(object):
|
||||
]
|
||||
|
||||
voice_tag = None
|
||||
|
||||
|
||||
# When adding a new argument here, remember to add it to copy below.
|
||||
def __init__(
|
||||
self,
|
||||
@@ -547,13 +549,13 @@ class ADVCharacter(object):
|
||||
return getattr(kind, n)
|
||||
|
||||
|
||||
# Similar, but it grabs the value out of kind.display_args instead.
|
||||
# Similar, but it grabs the value out of kind.display_args instead.
|
||||
def d(n):
|
||||
if n in properties:
|
||||
return properties.pop(n)
|
||||
else:
|
||||
return kind.display_args[n]
|
||||
|
||||
|
||||
self.name = v('name')
|
||||
self.who_prefix = v('who_prefix')
|
||||
self.who_suffix = v('who_suffix')
|
||||
@@ -576,8 +578,8 @@ class ADVCharacter(object):
|
||||
else:
|
||||
self.image_tag = kind.image_tag
|
||||
else:
|
||||
self.image_tag = None
|
||||
|
||||
self.image_tag = None
|
||||
|
||||
self.display_args = dict(
|
||||
interact = d('interact'),
|
||||
slow = d('slow'),
|
||||
@@ -606,13 +608,13 @@ class ADVCharacter(object):
|
||||
self.show_args = { }
|
||||
self.cb_args = { }
|
||||
|
||||
if not renpy.config.new_character_image_argument:
|
||||
if not renpy.config.new_character_image_argument:
|
||||
if "image" in properties:
|
||||
self.show_args["image"] = properties.pop("image")
|
||||
|
||||
if "slow_abortable" in properties:
|
||||
self.what_args["slow_abortable"] = properties.pop("slow_abortable")
|
||||
|
||||
|
||||
for k in list(properties):
|
||||
|
||||
if "_" in k:
|
||||
@@ -639,7 +641,7 @@ class ADVCharacter(object):
|
||||
def copy(self, name=NotSet, **properties):
|
||||
return type(self)(name, kind=self, **properties)
|
||||
|
||||
# This is called before the interaction.
|
||||
# This is called before the interaction.
|
||||
def do_add(self, who, what):
|
||||
return
|
||||
|
||||
@@ -647,7 +649,7 @@ class ADVCharacter(object):
|
||||
def do_show(self, who, what):
|
||||
return self.show_function(
|
||||
who,
|
||||
what,
|
||||
what,
|
||||
who_args=self.who_args,
|
||||
what_args=self.what_args,
|
||||
window_args=self.window_args,
|
||||
@@ -657,7 +659,7 @@ class ADVCharacter(object):
|
||||
# This is called after the last interaction is done.
|
||||
def do_done(self, who, what):
|
||||
return
|
||||
|
||||
|
||||
# This is called when an extend occurs, before the usual add/show
|
||||
# cycel.
|
||||
def do_extend(self):
|
||||
@@ -669,8 +671,8 @@ class ADVCharacter(object):
|
||||
what,
|
||||
self.do_show,
|
||||
**display_args)
|
||||
|
||||
|
||||
|
||||
|
||||
# This is called to predict images that will be used by this
|
||||
# statement.
|
||||
def do_predict(self, who, what):
|
||||
@@ -688,9 +690,9 @@ class ADVCharacter(object):
|
||||
Deals with image attributes associated with the current say
|
||||
statement.
|
||||
"""
|
||||
|
||||
|
||||
attrs = renpy.exports.get_say_attributes()
|
||||
|
||||
|
||||
if not attrs:
|
||||
return
|
||||
|
||||
@@ -700,14 +702,14 @@ class ADVCharacter(object):
|
||||
else:
|
||||
return
|
||||
|
||||
tagged_attrs = (self.image_tag,) + attrs
|
||||
tagged_attrs = (self.image_tag,) + attrs
|
||||
images = renpy.game.context().images
|
||||
|
||||
# If image is showing already, resolve it, then show or predict it.
|
||||
if images.showing("master", (self.image_tag,)):
|
||||
|
||||
new_image = images.apply_attributes("master", self.image_tag, tagged_attrs)
|
||||
|
||||
|
||||
if new_image is None:
|
||||
new_image = tagged_attrs
|
||||
|
||||
@@ -718,17 +720,27 @@ class ADVCharacter(object):
|
||||
|
||||
if trans is not None:
|
||||
renpy.exports.with_statement(None)
|
||||
|
||||
renpy.exports.show(new_image)
|
||||
|
||||
renpy.exports.show(new_image)
|
||||
|
||||
if trans is not None:
|
||||
renpy.exports.with_statement(trans)
|
||||
|
||||
else:
|
||||
|
||||
# Otherwise, just record the attributes of the image.
|
||||
|
||||
# Otherwise, just record the attributes of the image.
|
||||
images.predict_show("master", tagged_attrs, show=False)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
who = self.name
|
||||
|
||||
# If dynamic is set, evaluate the name expression.
|
||||
if self.dynamic:
|
||||
who = renpy.python.py_eval(who)
|
||||
|
||||
return who
|
||||
|
||||
|
||||
def __call__(self, what, interact=True, **kwargs):
|
||||
|
||||
# Check self.condition to see if we should show this line at all.
|
||||
@@ -736,35 +748,35 @@ class ADVCharacter(object):
|
||||
return True
|
||||
|
||||
self.resolve_say_attributes(False)
|
||||
|
||||
|
||||
old_side_image_attributes = renpy.store._side_image_attributes
|
||||
|
||||
|
||||
if self.image_tag:
|
||||
attrs = (self.image_tag,) + renpy.game.context().images.get_attributes("master", self.image_tag)
|
||||
else:
|
||||
attrs = None
|
||||
|
||||
|
||||
renpy.store._side_image_attributes = attrs
|
||||
|
||||
if renpy.config.voice_tag_callback is not None:
|
||||
renpy.config.voice_tag_callback(self.voice_tag)
|
||||
|
||||
|
||||
try:
|
||||
|
||||
|
||||
if interact:
|
||||
renpy.exports.mode(self.mode)
|
||||
|
||||
|
||||
# Figure out the arguments to display.
|
||||
display_args = self.display_args.copy()
|
||||
display_args.update(kwargs)
|
||||
display_args["interact"] = display_args["interact"] and interact
|
||||
|
||||
|
||||
who = self.name
|
||||
|
||||
|
||||
# If dynamic is set, evaluate the name expression.
|
||||
if self.dynamic:
|
||||
who = renpy.python.py_eval(who)
|
||||
|
||||
|
||||
sub = renpy.substitutions.substitute
|
||||
|
||||
if who is not None:
|
||||
@@ -773,9 +785,9 @@ class ADVCharacter(object):
|
||||
who = who_pattern.replace("[who]", sub(who))
|
||||
else:
|
||||
who = self.who_prefix + who + self.who_suffix
|
||||
|
||||
|
||||
ctx = renpy.game.context()
|
||||
|
||||
|
||||
if (ctx.translate_language is not None) and (ctx.translate_identifier is not None):
|
||||
translate = False
|
||||
else:
|
||||
@@ -786,40 +798,40 @@ class ADVCharacter(object):
|
||||
what = what_pattern.replace("[what]", sub(what, translate=translate))
|
||||
else:
|
||||
what = self.what_prefix + what + self.what_suffix
|
||||
|
||||
|
||||
# Run the add_function, to add this character to the
|
||||
# things like NVL-mode.
|
||||
self.do_add(who, what)
|
||||
|
||||
|
||||
# Now, display the damned thing.
|
||||
self.do_display(who, what, cb_args=self.cb_args, **display_args)
|
||||
|
||||
|
||||
# Indicate that we're done.
|
||||
self.do_done(who, what)
|
||||
|
||||
# Finally, log this line of dialogue.
|
||||
|
||||
# Finally, log this line of dialogue.
|
||||
if who and isinstance(who, (str, unicode)):
|
||||
renpy.exports.log(who)
|
||||
renpy.exports.log(what)
|
||||
renpy.exports.log("")
|
||||
|
||||
finally:
|
||||
|
||||
|
||||
if interact:
|
||||
renpy.store._side_image_attributes = old_side_image_attributes
|
||||
|
||||
|
||||
|
||||
|
||||
def predict(self, what):
|
||||
|
||||
self.resolve_say_attributes(True)
|
||||
|
||||
|
||||
old_side_image_attributes = renpy.store._side_image_attributes
|
||||
|
||||
|
||||
if self.image_tag:
|
||||
attrs = self.image_tag + renpy.game.context().images.get_attributes("master", self.image_tag)
|
||||
else:
|
||||
attrs = None
|
||||
|
||||
|
||||
renpy.store._side_image_attributes = attrs
|
||||
|
||||
try:
|
||||
@@ -828,11 +840,11 @@ class ADVCharacter(object):
|
||||
who = "<Dynamic>"
|
||||
else:
|
||||
who = self.name
|
||||
|
||||
|
||||
return self.do_predict(who, what)
|
||||
|
||||
finally:
|
||||
renpy.store._side_image_attributes = old_side_image_attributes
|
||||
finally:
|
||||
renpy.store._side_image_attributes = old_side_image_attributes
|
||||
|
||||
def will_interact(self):
|
||||
|
||||
@@ -841,13 +853,13 @@ class ADVCharacter(object):
|
||||
|
||||
return self.display_args['interact']
|
||||
|
||||
|
||||
|
||||
def Character(name=NotSet, kind=None, **properties):
|
||||
"""
|
||||
:doc: character
|
||||
:args: (name, kind=adv, **args)
|
||||
:name: Character
|
||||
|
||||
|
||||
Creates and returns a Character object, which controls the look
|
||||
and feel of dialogue and narration.
|
||||
|
||||
@@ -870,16 +882,16 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
image to show when this character speaks.
|
||||
|
||||
`image`
|
||||
A string giving the image tag that is linked with this
|
||||
A string giving the image tag that is linked with this
|
||||
character.
|
||||
|
||||
|
||||
**Voice Tag**
|
||||
If a voice tag is assign to a Character, the voice files that are
|
||||
associated with it, can be muted or played in the preference
|
||||
associated with it, can be muted or played in the preference
|
||||
screen.
|
||||
|
||||
`voice_tag`
|
||||
A String that enables the voice file assosiated with the
|
||||
A String that enables the voice file assosiated with the
|
||||
Character to be muted or played in the 'voice' channel.
|
||||
|
||||
**Prefixes and Suffixes.**
|
||||
@@ -894,7 +906,7 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
`what_suffix`
|
||||
A string that is appended to the dialogue being spoken before
|
||||
it is shown.
|
||||
|
||||
|
||||
`who_prefix`
|
||||
A string that is prepended to the name of the character before
|
||||
it is shown.
|
||||
@@ -902,7 +914,7 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
`who_suffix`
|
||||
A string that is appended to the name of the character before
|
||||
it is shown.
|
||||
|
||||
|
||||
**Changing Name Display.**
|
||||
These options help to control the display of the name.
|
||||
|
||||
@@ -932,7 +944,7 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
`callback`
|
||||
A function that is called when events occur while the
|
||||
character is speaking. See the section on
|
||||
:ref:`character callbacks` fore more information.
|
||||
:ref:`character-callbacks` fore more information.
|
||||
|
||||
**Click-to-continue.**
|
||||
A click-to-continue indicator is displayed once all the text has
|
||||
@@ -951,7 +963,7 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
display of text is paused by the {p=} or {w=} text tags. When
|
||||
None, this takes its default from ctc_pause, use ``Null()``
|
||||
when you want a ctc_pause but no ctc_timedpause.
|
||||
|
||||
|
||||
`ctc_position`
|
||||
Controls the location of the click-to-continue indicator. If
|
||||
``"nestled"``, the indicator is displayed as part of the text
|
||||
@@ -980,12 +992,12 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
controlled by its position properties. This is often used
|
||||
to show an image of the speaking character to the side
|
||||
of the dialogue.
|
||||
|
||||
|
||||
`show_two_window`
|
||||
If true, restructures the layout so that the name of the
|
||||
character is placed in one window, and the dialogue text in a
|
||||
second window.
|
||||
|
||||
|
||||
**Styling Text and Windows.**
|
||||
Keyword arguments beginning with ``who_``, ``what_``, and
|
||||
`window_`` have their prefix stripped, and are used to :ref:`style
|
||||
|
||||
@@ -14,7 +14,7 @@ python early hide:
|
||||
# return 1.0
|
||||
# else:
|
||||
# return 0.0
|
||||
|
||||
|
||||
@renpy.atl_warper
|
||||
def linear(t):
|
||||
return t
|
||||
|
||||
+57
-122
@@ -1,74 +1,12 @@
|
||||
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# This file contains code that creates a few new statements. We'll
|
||||
# also describe here the API for defining your own statements.
|
||||
#
|
||||
# Statements can be defined by calling renpy.statements.register. This
|
||||
# function takes a string giving the keywords at the start of the
|
||||
# statement, and then up to 4 functions defining the behavior of the
|
||||
# statement: parse, execute, predict, and lint. If given the keyword
|
||||
# argument block=True, the statement will take a block.
|
||||
#
|
||||
# The parse function takes a lexer object as an argument, and is
|
||||
# expected to return some parser data. The lexer has the following
|
||||
# methods.
|
||||
#
|
||||
# l.eol() - True if we are at the end of the line.
|
||||
# l.match(re) - Matches an arbitrary regexp string.
|
||||
# l.keyword(s) - Matches s.
|
||||
# l.name() - Matches any non-keyword name. Note that this only
|
||||
# counts built-in keywords.
|
||||
# l.word() - Matches any word, period.
|
||||
# l.string() - Matches a renpy string.
|
||||
# l.integer() - Matches an integer, returns a string containing the
|
||||
# integer.
|
||||
# l.float() - Matches a floating point number.
|
||||
# l.simple_expression() - Matches a simple python expression, returns
|
||||
# it as a string.
|
||||
# l.rest() - Skips whitespace, then returns the rest of the line.
|
||||
# l.checkpoint() - Returns an opaque object representing the current
|
||||
# point in the parse.
|
||||
# l.revert(o) - Given the object returned by l.checkpoint(), returns
|
||||
# there.
|
||||
#
|
||||
# l.subblock_lexer() - Return a lexer that gives a sub-block for the
|
||||
# block associated with the current statement.
|
||||
# l.advance() - In a subblock lexer, advance to the next line. This needs
|
||||
# to be called before the above functions can be called on the first line.
|
||||
#
|
||||
#
|
||||
#
|
||||
# The parse function is expected to return an object, which is passed
|
||||
# to the other functions. Parse should call renpy.error with the error
|
||||
# message to report an error.
|
||||
#
|
||||
# The execute function is passed the object returned from parse, and
|
||||
# is expected to execute the statement.
|
||||
#
|
||||
# The predict function is passed the object returned from parse, and
|
||||
# is expected to return a list of images that are used by the
|
||||
# statement.
|
||||
#
|
||||
# The lint function is called at lint time, after the init code is
|
||||
# run. It should check the statement for errors, and report them by
|
||||
# calling renpy.error with the appropriate error message.
|
||||
#
|
||||
# The scry function is called with a scry object. It may mutate that
|
||||
# object, but it is then expected to return it. See 00nvlmode.rpy for
|
||||
# details.
|
||||
#
|
||||
# The next function is expected to return a string giving the label of
|
||||
# the next statement to execute, or None to indicate that next
|
||||
# statement in the block should be executed. The next function is
|
||||
# called during predict, scry, and execute, and should always return
|
||||
# the same value. (Or scrying may be incorrect.)
|
||||
|
||||
# This file contains code that creates a few new statements.
|
||||
|
||||
python early hide:
|
||||
|
||||
# Music play - The example of a full statement.
|
||||
|
||||
|
||||
def parse_play_music(l):
|
||||
|
||||
file = l.simple_expression()
|
||||
@@ -80,7 +18,7 @@ python early hide:
|
||||
channel = None
|
||||
loop = None
|
||||
if_changed = False
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
if l.eol():
|
||||
@@ -88,18 +26,18 @@ python early hide:
|
||||
|
||||
if l.keyword('fadeout'):
|
||||
fadeout = l.simple_expression()
|
||||
if fadeout is None:
|
||||
if fadeout is None:
|
||||
renpy.error('expected simple expression')
|
||||
|
||||
continue
|
||||
|
||||
|
||||
if l.keyword('fadein'):
|
||||
fadein = l.simple_expression()
|
||||
if fadein is None:
|
||||
if fadein is None:
|
||||
renpy.error('expected simple expression')
|
||||
|
||||
continue
|
||||
|
||||
|
||||
if l.keyword('channel'):
|
||||
channel = l.simple_expression()
|
||||
if channel is None:
|
||||
@@ -110,7 +48,7 @@ python early hide:
|
||||
if l.keyword('loop'):
|
||||
loop = True
|
||||
continue
|
||||
|
||||
|
||||
if l.keyword('noloop'):
|
||||
loop = False
|
||||
continue
|
||||
@@ -118,7 +56,7 @@ python early hide:
|
||||
if l.keyword('if_changed'):
|
||||
if_changed = True
|
||||
continue
|
||||
|
||||
|
||||
renpy.error('could not parse statement.')
|
||||
|
||||
return dict(file=file,
|
||||
@@ -134,7 +72,7 @@ python early hide:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = "music"
|
||||
|
||||
|
||||
renpy.music.play(eval(p["file"]),
|
||||
fadeout=eval(p["fadeout"]),
|
||||
fadein=eval(p["fadein"]),
|
||||
@@ -151,7 +89,7 @@ python early hide:
|
||||
|
||||
if p["channel"] is not None:
|
||||
channel = _try_eval(p["channel"], 'channel')
|
||||
|
||||
|
||||
if not isinstance(file, list):
|
||||
file = [ file ]
|
||||
|
||||
@@ -162,8 +100,8 @@ python early hide:
|
||||
renpy.error("%r is not loadable" % fn)
|
||||
except:
|
||||
pass
|
||||
|
||||
renpy.statements.register('play music',
|
||||
|
||||
renpy.register_statement('play music',
|
||||
parse=parse_play_music,
|
||||
execute=execute_play_music,
|
||||
predict=predict_play_music,
|
||||
@@ -180,9 +118,9 @@ python early hide:
|
||||
|
||||
channel = None
|
||||
loop = None
|
||||
|
||||
|
||||
while not l.eol():
|
||||
|
||||
|
||||
if l.keyword('channel'):
|
||||
channel = l.simple_expression()
|
||||
if channel is None:
|
||||
@@ -191,7 +129,7 @@ python early hide:
|
||||
if l.keyword('loop'):
|
||||
loop = True
|
||||
continue
|
||||
|
||||
|
||||
if l.keyword('noloop'):
|
||||
loop = False
|
||||
continue
|
||||
@@ -205,14 +143,14 @@ python early hide:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = "music"
|
||||
|
||||
|
||||
renpy.music.queue(
|
||||
eval(p["file"]),
|
||||
channel=channel,
|
||||
loop=p.get("loop", None))
|
||||
|
||||
|
||||
renpy.statements.register('queue music',
|
||||
renpy.register_statement('queue music',
|
||||
parse=parse_queue_music,
|
||||
execute=execute_queue_music,
|
||||
lint=lint_play_music)
|
||||
@@ -224,7 +162,7 @@ python early hide:
|
||||
fadeout = l.simple_expression()
|
||||
|
||||
channel = None
|
||||
|
||||
|
||||
if l.keyword('channel'):
|
||||
channel = l.simple_expression()
|
||||
if channel is None:
|
||||
@@ -233,7 +171,7 @@ python early hide:
|
||||
if not l.eol():
|
||||
renpy.error('expected end of line')
|
||||
|
||||
if fadeout is None:
|
||||
if fadeout is None:
|
||||
renpy.error('expected simple expression')
|
||||
|
||||
return dict(fadeout=fadeout, channel=channel)
|
||||
@@ -243,10 +181,10 @@ python early hide:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = "music"
|
||||
|
||||
|
||||
renpy.music.stop(fadeout=eval(p["fadeout"]), channel=channel)
|
||||
|
||||
renpy.statements.register('stop music',
|
||||
renpy.register_statement('stop music',
|
||||
parse=parse_stop_music,
|
||||
execute=execute_stop_music)
|
||||
|
||||
@@ -255,14 +193,14 @@ python early hide:
|
||||
# statements.
|
||||
|
||||
def execute_play_sound(p):
|
||||
|
||||
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = "sound"
|
||||
|
||||
fadeout = eval(p["fadeout"]) or 0
|
||||
|
||||
|
||||
renpy.sound.play(eval(p["file"]),
|
||||
fadeout=fadeout,
|
||||
fadein=eval(p["fadein"]),
|
||||
@@ -270,8 +208,8 @@ python early hide:
|
||||
|
||||
def lint_play_sound(p, lint_play_music=lint_play_music):
|
||||
return lint_play_music(p, channel="sound")
|
||||
|
||||
renpy.statements.register('play sound',
|
||||
|
||||
renpy.register_statement('play sound',
|
||||
parse=parse_play_music,
|
||||
execute=execute_play_sound,
|
||||
lint=lint_play_sound)
|
||||
@@ -285,7 +223,7 @@ python early hide:
|
||||
renpy.sound.queue(eval(p["file"]), channel=channel)
|
||||
|
||||
|
||||
renpy.statements.register('queue sound',
|
||||
renpy.register_statement('queue sound',
|
||||
parse=parse_queue_music,
|
||||
execute=execute_queue_sound,
|
||||
lint=lint_play_music)
|
||||
@@ -300,7 +238,7 @@ python early hide:
|
||||
|
||||
renpy.sound.stop(fadeout=fadeout, channel=channel)
|
||||
|
||||
renpy.statements.register('stop sound',
|
||||
renpy.register_statement('stop sound',
|
||||
parse=parse_stop_music,
|
||||
execute=execute_stop_sound)
|
||||
|
||||
@@ -346,7 +284,7 @@ python early hide:
|
||||
|
||||
def lint_play_generic(p, lint_play_music=lint_play_music):
|
||||
channel = eval(p["channel"])
|
||||
|
||||
|
||||
if not renpy.music.channel_defined(channel):
|
||||
renpy.error("channel %r is not defined" % channel)
|
||||
|
||||
@@ -354,22 +292,22 @@ python early hide:
|
||||
|
||||
def lint_stop_generic(p):
|
||||
channel = eval(p["channel"])
|
||||
|
||||
|
||||
if not renpy.music.channel_defined(channel):
|
||||
renpy.error("channel %r is not defined" % channel)
|
||||
|
||||
renpy.statements.register('play',
|
||||
renpy.register_statement('play',
|
||||
parse=parse_play_generic,
|
||||
execute=execute_play_music,
|
||||
predict=predict_play_music,
|
||||
lint=lint_play_generic)
|
||||
|
||||
renpy.statements.register('queue',
|
||||
|
||||
renpy.register_statement('queue',
|
||||
parse=parse_queue_generic,
|
||||
execute=execute_queue_music,
|
||||
lint=lint_play_generic)
|
||||
|
||||
renpy.statements.register('stop',
|
||||
|
||||
renpy.register_statement('stop',
|
||||
parse=parse_stop_generic,
|
||||
execute=execute_stop_music,
|
||||
lint=lint_stop_generic)
|
||||
@@ -384,7 +322,7 @@ python early hide:
|
||||
renpy.error('expected end of line')
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def lint_window(p):
|
||||
if p is not None:
|
||||
_try_eval(p, 'window transition')
|
||||
@@ -397,15 +335,15 @@ python early hide:
|
||||
trans = eval(p)
|
||||
else:
|
||||
trans = config.window_show_transition
|
||||
|
||||
|
||||
renpy.with_statement(None)
|
||||
store._window = True
|
||||
renpy.with_statement(trans)
|
||||
|
||||
|
||||
def execute_window_hide(p):
|
||||
if not _window:
|
||||
return
|
||||
|
||||
|
||||
if p is not None:
|
||||
trans = eval(p)
|
||||
else:
|
||||
@@ -415,19 +353,19 @@ python early hide:
|
||||
store._window = False
|
||||
renpy.with_statement(trans)
|
||||
|
||||
renpy.statements.register('window show',
|
||||
renpy.register_statement('window show',
|
||||
parse=parse_window,
|
||||
execute=execute_window_show,
|
||||
lint=lint_window)
|
||||
|
||||
renpy.statements.register('window hide',
|
||||
renpy.register_statement('window hide',
|
||||
parse=parse_window,
|
||||
execute=execute_window_hide,
|
||||
lint=lint_window)
|
||||
|
||||
##########################################################################
|
||||
# Pause statement.
|
||||
|
||||
|
||||
def parse_pause(l):
|
||||
|
||||
delay = l.simple_expression()
|
||||
@@ -441,7 +379,7 @@ python early hide:
|
||||
|
||||
if p["delay"]:
|
||||
_try_eval(p["delay"], 'pause statement')
|
||||
|
||||
|
||||
def execute_pause(p):
|
||||
|
||||
if p["delay"]:
|
||||
@@ -451,23 +389,23 @@ python early hide:
|
||||
renpy.pause()
|
||||
|
||||
|
||||
renpy.statements.register('pause',
|
||||
renpy.register_statement('pause',
|
||||
parse=parse_pause,
|
||||
lint=lint_pause,
|
||||
execute=execute_pause)
|
||||
|
||||
|
||||
|
||||
|
||||
init -1200 python:
|
||||
|
||||
config.window_show_transition = None
|
||||
config.window_hide_transition = None
|
||||
|
||||
|
||||
def _try_eval(e, what):
|
||||
try:
|
||||
return eval(e)
|
||||
except:
|
||||
renpy.error('unable to evaluate %s %r' % (what, e))
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Screen-related statements.
|
||||
|
||||
@@ -481,7 +419,7 @@ python early hide:
|
||||
# Parse the list of arguments.
|
||||
arguments = renpy.parser.parse_arguments(l)
|
||||
l.expect_eol()
|
||||
|
||||
|
||||
return dict(name=name, arguments=arguments)
|
||||
|
||||
def parse_hide_screen(l):
|
||||
@@ -494,7 +432,7 @@ python early hide:
|
||||
def predict_screen(p):
|
||||
if not p["arguments"]:
|
||||
renpy.predict_screen(p["arguments"])
|
||||
|
||||
|
||||
def execute_show_screen(p):
|
||||
|
||||
name = p["name"]
|
||||
@@ -513,7 +451,7 @@ python early hide:
|
||||
|
||||
if a.extrapos is not None:
|
||||
args.extend(eval(a.extrapos))
|
||||
|
||||
|
||||
if a.extrakw is not None:
|
||||
kwargs.update(eval(a.extrakw))
|
||||
|
||||
@@ -536,7 +474,7 @@ python early hide:
|
||||
|
||||
if a.extrapos is not None:
|
||||
args.extend(eval(a.extrapos))
|
||||
|
||||
|
||||
if a.extrakw is not None:
|
||||
kwargs.update(eval(a.extrakw))
|
||||
|
||||
@@ -545,28 +483,25 @@ python early hide:
|
||||
def execute_hide_screen(p):
|
||||
name = p["name"]
|
||||
renpy.hide_screen(name)
|
||||
|
||||
|
||||
def lint_screen(p):
|
||||
name = p["name"]
|
||||
if not renpy.has_screen(name):
|
||||
renpy.error("Screen %s does not exist." % name)
|
||||
|
||||
|
||||
renpy.statements.register("show screen",
|
||||
|
||||
renpy.register_statement("show screen",
|
||||
parse=parse_show_call_screen,
|
||||
execute=execute_show_screen,
|
||||
predict=predict_screen,
|
||||
lint=lint_screen)
|
||||
|
||||
renpy.statements.register("call screen",
|
||||
renpy.register_statement("call screen",
|
||||
parse=parse_show_call_screen,
|
||||
execute=execute_call_screen,
|
||||
predict=predict_screen,
|
||||
lint=lint_screen)
|
||||
|
||||
renpy.statements.register("hide screen",
|
||||
renpy.register_statement("hide screen",
|
||||
parse=parse_hide_screen,
|
||||
execute=execute_hide_screen)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ init -1500 python:
|
||||
class Play(Action):
|
||||
"""
|
||||
:doc: audio_action
|
||||
|
||||
|
||||
Causes an audio file to be played on a given channel.
|
||||
|
||||
|
||||
`channel`
|
||||
The channel to play the sound on.
|
||||
`file`
|
||||
@@ -19,7 +19,7 @@ init -1500 python:
|
||||
|
||||
Any keyword arguments are passed to :func:`renpy.music.play`
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, channel, file, **kwargs):
|
||||
self.channel = channel
|
||||
self.file = file
|
||||
@@ -29,9 +29,9 @@ init -1500 python:
|
||||
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
|
||||
return renpy.music.get_playing(self.channel) == self.file
|
||||
|
||||
def periodic(self, st):
|
||||
if self.selected != self.get_selected():
|
||||
@@ -39,7 +39,7 @@ init -1500 python:
|
||||
|
||||
return .1
|
||||
|
||||
|
||||
|
||||
class Queue(Action):
|
||||
"""
|
||||
:doc: audio_action
|
||||
@@ -63,7 +63,7 @@ init -1500 python:
|
||||
renpy.music.queue(self.file, channel=self.channel, **self.kwargs)
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
|
||||
class Stop(Action):
|
||||
"""
|
||||
:doc: audio_action
|
||||
@@ -71,11 +71,9 @@ init -1500 python:
|
||||
Causes an audio channel to be stopped.
|
||||
|
||||
`channel`
|
||||
The channel to play the sound on.
|
||||
`file`
|
||||
The file to play.
|
||||
The channel to stop the sound on.
|
||||
|
||||
Any keyword arguments are passed to :func:`renpy.music.play`
|
||||
Any keyword arguments are passed to :func:`renpy.music.stop`
|
||||
"""
|
||||
|
||||
def __init__(self, channel, **kwargs):
|
||||
@@ -89,25 +87,25 @@ init -1500 python:
|
||||
class SetMixer(Action):
|
||||
"""
|
||||
:doc: audio_action
|
||||
|
||||
Sets the volume of `mixer` to `value`.
|
||||
|
||||
|
||||
Sets the volume of `mixer` to `value`.
|
||||
|
||||
`mixer`
|
||||
The mixer to set the volume of. A string, usually one of
|
||||
The mixer to set the volume of. A string, usually one of
|
||||
"music", "sfx", or "voice".
|
||||
`value`
|
||||
The value to set the volume to. A number between 0.0 and 1.0,
|
||||
The value to set the volume to. A number between 0.0 and 1.0,
|
||||
inclusive.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, mixer, volume):
|
||||
self.mixer = mixer
|
||||
self.volume = volume
|
||||
|
||||
|
||||
def __call__(self):
|
||||
_preferences.set_volume(self.mixer, self.volume)
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return _preferences.get_volume(self.mixer) == self.volume
|
||||
|
||||
|
||||
|
||||
@@ -3,10 +3,23 @@
|
||||
|
||||
init -1500 python:
|
||||
|
||||
class NullAction(Action):
|
||||
"""
|
||||
:doc: control_action
|
||||
|
||||
Does nothing.
|
||||
|
||||
This can be used to make a button responsive to hover/unhover events,
|
||||
without actually doing anything.
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
return
|
||||
|
||||
class Return(Action):
|
||||
"""
|
||||
:doc: control_action
|
||||
|
||||
|
||||
Causes the current interaction to return the supplied value. This is
|
||||
often used with menus and imagemaps, to select what the return value
|
||||
of the interaction is.
|
||||
@@ -28,35 +41,35 @@ init -1500 python:
|
||||
else:
|
||||
return self.value
|
||||
|
||||
|
||||
|
||||
class Jump(Action):
|
||||
"""
|
||||
:doc: control_action
|
||||
|
||||
|
||||
Causes control to transfer to the given label. This can be used in
|
||||
conjunction with renpy.run_screen to define an imagemap that jumps
|
||||
to a label when run.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
def __call__(self):
|
||||
renpy.jump(self.label)
|
||||
|
||||
|
||||
|
||||
class Show(Action):
|
||||
"""
|
||||
:doc: control_action
|
||||
|
||||
|
||||
This causes another screen to be shown. `screen` is a string
|
||||
giving the name of the screen. The keyword arguments are
|
||||
passed to the screen being shown.
|
||||
|
||||
If not None, `transition` is use to show the new screen.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
args = None
|
||||
|
||||
def __init__(self, screen, transition=None, *args, **kwargs):
|
||||
@@ -67,7 +80,7 @@ init -1500 python:
|
||||
|
||||
def predict(self):
|
||||
renpy.predict_screen(self.screen, *self.args, **self.kwargs)
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.show_screen(self.screen, *self.args, **self.kwargs)
|
||||
|
||||
@@ -75,7 +88,7 @@ init -1500 python:
|
||||
renpy.transition(self.transition)
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return renpy.showing(self.screen)
|
||||
|
||||
@@ -89,27 +102,27 @@ init -1500 python:
|
||||
"""
|
||||
|
||||
return Show(screen, _transient=True, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
class Hide(Action):
|
||||
"""
|
||||
:doc: control_action
|
||||
|
||||
This causes the screen named `screen` to be hidden, if it is shown.
|
||||
|
||||
This causes the screen named `screen` to be hidden, if it is shown.
|
||||
|
||||
`transition`
|
||||
If not None, a transition that occurs when hiding the screen.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, screen, transition=None):
|
||||
self.screen = screen
|
||||
self.transition = transition
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.hide_screen(self.screen)
|
||||
|
||||
if self.transition is not None:
|
||||
renpy.transition(self.transition)
|
||||
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
@@ -19,15 +19,15 @@ init -1600 python:
|
||||
self.object = object
|
||||
self.field = field
|
||||
self.value = value
|
||||
|
||||
|
||||
def __call__(self):
|
||||
setattr(self.object, self.field, self.value)
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
return getattr(self.object, self.field) == self.value
|
||||
|
||||
|
||||
|
||||
|
||||
def SetVariable(variable, value):
|
||||
"""
|
||||
:doc: data_action
|
||||
@@ -37,7 +37,7 @@ init -1600 python:
|
||||
|
||||
return SetField(store, variable, value)
|
||||
|
||||
|
||||
|
||||
class SetDict(Action):
|
||||
"""
|
||||
:doc: data_action
|
||||
@@ -55,22 +55,25 @@ init -1600 python:
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
if self.key not in self.dict:
|
||||
return False
|
||||
|
||||
return self.dict[self.key] == self.value
|
||||
|
||||
def SetScreenVariable(name, value):
|
||||
"""
|
||||
:doc: data_action
|
||||
|
||||
Causes the variable `name` associated with the current screen to
|
||||
Causes the variable `name` associated with the current screen to
|
||||
be set to `value`.
|
||||
"""
|
||||
|
||||
|
||||
cs = renpy.current_screen()
|
||||
if cs is not None:
|
||||
return SetDict(cs.scope, name, value)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class ToggleField(Action):
|
||||
"""
|
||||
:doc: data_action
|
||||
@@ -81,15 +84,15 @@ init -1600 python:
|
||||
`true_value`
|
||||
If not None, then this is the true value we use.
|
||||
`false_value`
|
||||
If not None, then this is the false value we use.
|
||||
If not None, then this is the false value we use.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, object, field, true_value=None, false_value=None):
|
||||
self.object = object
|
||||
self.field = field
|
||||
self.true_value = true_value
|
||||
self.false_value = false_value
|
||||
|
||||
|
||||
def __call__(self):
|
||||
value = getattr(self.object, self.field)
|
||||
|
||||
@@ -103,7 +106,7 @@ init -1600 python:
|
||||
value = self.true_value
|
||||
else:
|
||||
value = self.false_value
|
||||
|
||||
|
||||
setattr(self.object, self.field, value)
|
||||
renpy.restart_interaction()
|
||||
|
||||
@@ -125,12 +128,12 @@ init -1600 python:
|
||||
`true_value`
|
||||
If not None, then this is the true value we use.
|
||||
`false_value`
|
||||
If not None, then this is the false value we use.
|
||||
If not None, then this is the false value we use.
|
||||
"""
|
||||
|
||||
return ToggleField(store, variable, true_value=true_value, false_value=false_value)
|
||||
|
||||
|
||||
|
||||
class ToggleDict(Action):
|
||||
"""
|
||||
:doc: data_action
|
||||
@@ -141,15 +144,15 @@ init -1600 python:
|
||||
`true_value`
|
||||
If not None, then this is the true value we use.
|
||||
`false_value`
|
||||
If not None, then this is the false value we use.
|
||||
If not None, then this is the false value we use.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, dict, key, true_value=None, false_value=None):
|
||||
self.dict = dict
|
||||
self.key = key
|
||||
self.true_value = true_value
|
||||
self.false_value = false_value
|
||||
|
||||
|
||||
def __call__(self):
|
||||
value = self.dict[self.key]
|
||||
|
||||
@@ -184,9 +187,9 @@ init -1600 python:
|
||||
`true_value`
|
||||
If not None, then this is the true value we use.
|
||||
`false_value`
|
||||
If not None, then this is the false value we use.
|
||||
If not None, then this is the false value we use.
|
||||
"""
|
||||
|
||||
|
||||
cs = renpy.current_screen()
|
||||
|
||||
if cs is not None:
|
||||
|
||||
+168
-127
@@ -3,16 +3,16 @@
|
||||
|
||||
init -1500 python:
|
||||
|
||||
|
||||
|
||||
##########################################################################
|
||||
# File functions
|
||||
|
||||
config.linear_saves_page_size = None
|
||||
|
||||
|
||||
if persistent._file_page is None:
|
||||
persistent._file_page = "1"
|
||||
|
||||
def __filename(name, page=None):
|
||||
def __slotname(name, page=None):
|
||||
|
||||
if page is None:
|
||||
page = persistent._file_page
|
||||
@@ -27,54 +27,62 @@ init -1500 python:
|
||||
|
||||
return str(page) + "-" + str(name)
|
||||
|
||||
def __newest_slot():
|
||||
"""
|
||||
Returns the name of the newest slot on a page.
|
||||
"""
|
||||
|
||||
return renpy.newest_slot(r'\d+')
|
||||
|
||||
def __unused_slot_name(page):
|
||||
"""
|
||||
Returns an unused slot name.
|
||||
Returns an unused name of a slot on the current page. (This will
|
||||
likely be a very big number, as it's based on the current unix time.)
|
||||
"""
|
||||
|
||||
|
||||
import time
|
||||
|
||||
|
||||
rv = int(time.time())
|
||||
|
||||
|
||||
while True:
|
||||
if not renpy.can_load(__filename(str(rv), page)):
|
||||
if not renpy.can_load(__slotname(str(rv), page)):
|
||||
return str(rv)
|
||||
|
||||
|
||||
rv += 1
|
||||
|
||||
def FileCurrentPage():
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
|
||||
Returns the current file page as a string.
|
||||
"""
|
||||
|
||||
|
||||
return str(persistent._file_page)
|
||||
|
||||
def FileUsedSlots(page=None, highest_first=True):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
|
||||
Returns a list of used numeric file slots on the page.
|
||||
|
||||
|
||||
`page`
|
||||
The name of the page that will be scanned. If None, the current page
|
||||
The name of the page that will be scanned. If None, the current page
|
||||
is used.
|
||||
|
||||
|
||||
`highest_first`
|
||||
If true, the highest-numbered file slot is listed first.
|
||||
Otherwise, the lowest-numbered slot is listed first.
|
||||
"""
|
||||
|
||||
regexp = __filename(r'\d+', page)
|
||||
|
||||
|
||||
regexp = __slotname(r'\d+', page)
|
||||
|
||||
rv = [ ]
|
||||
|
||||
for fn in renpy.list_saved_games(regexp=regexp, fast=True):
|
||||
|
||||
for fn in renpy.list_slots(regexp=regexp):
|
||||
_page, _, slot = fn.partition('-')
|
||||
|
||||
|
||||
rv.append(int(slot))
|
||||
|
||||
|
||||
rv.sort()
|
||||
if highest_first:
|
||||
rv.reverse()
|
||||
@@ -89,12 +97,12 @@ init -1500 python:
|
||||
if the file is loadable, and false otherwise.
|
||||
"""
|
||||
|
||||
return renpy.can_load(__filename(name, page))
|
||||
|
||||
return renpy.can_load(__slotname(name, page))
|
||||
|
||||
def FileScreenshot(name, empty=None, page=None):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
|
||||
Returns the screenshot associated with the given file. If the
|
||||
file is not loadable, then `empty` is returned, unless it's None,
|
||||
in which case, a Null displayable is created.
|
||||
@@ -102,60 +110,81 @@ init -1500 python:
|
||||
The return value is a displayable.
|
||||
"""
|
||||
|
||||
save_data = renpy.scan_saved_game(__filename(name, page))
|
||||
screenshot = renpy.slot_screenshot(__slotname(name, page))
|
||||
|
||||
if save_data is None:
|
||||
if empty is not None:
|
||||
return empty
|
||||
else:
|
||||
return Null(config.thumbnail_width, config.thumbnail_height)
|
||||
if screenshot is not None:
|
||||
return screenshot
|
||||
|
||||
extra_info, displayable, save_time = save_data
|
||||
if empty is not None:
|
||||
return empty
|
||||
else:
|
||||
return Null(config.thumbnail_width, config.thumbnail_height)
|
||||
|
||||
return displayable
|
||||
|
||||
|
||||
def FileTime(name, format=_("%b %d, %H:%M"), empty="", page=None):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
:doc: file_action_function
|
||||
|
||||
Returns the time the file was saved, formatted according
|
||||
to the supplied `format`. If the file is not found, `empty` is
|
||||
returned.
|
||||
|
||||
The return value is a string.
|
||||
"""
|
||||
|
||||
save_data = renpy.scan_saved_game(__filename(name, page))
|
||||
|
||||
if save_data is None:
|
||||
mtime = renpy.slot_mtime(__slotname(name, page))
|
||||
|
||||
if mtime is None:
|
||||
return empty
|
||||
|
||||
import time
|
||||
|
||||
extra_info, displayable, save_time = save_data
|
||||
|
||||
format = renpy.translation.translate_string(format)
|
||||
return time.strftime(format.encode("utf-8"), time.localtime(mtime)).decode("utf-8")
|
||||
|
||||
def FileJson(name, key=None, empty=None, missing=None, page=None):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
Accesses the Json information associated with `name`.
|
||||
|
||||
If `key` is None, returns the entire Json other object, or `empty` if the slot
|
||||
is empty.
|
||||
|
||||
Otherwise, this returns json[key] if `key` is defined on the json object of the save,
|
||||
`missing` if there is a save with the given name, but it does not contain `key`, or
|
||||
`empty` if the save slot is empty.
|
||||
"""
|
||||
|
||||
json = renpy.slot_json(__slotname(name, page))
|
||||
|
||||
if json is None:
|
||||
return empty
|
||||
|
||||
if key is None:
|
||||
return json
|
||||
|
||||
return json.get(key, missing)
|
||||
|
||||
return time.strftime(format.encode("utf-8"), time.localtime(save_time)).decode("utf-8")
|
||||
|
||||
def FileSaveName(name, empty="", page=None):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
|
||||
Return the save_name that was in effect when the file was saved,
|
||||
or `empty` if the file does not exist.
|
||||
"""
|
||||
|
||||
save_data = renpy.scan_saved_game(__filename(name, page))
|
||||
return FileJson(name, "_save_name", empty=empty, missing=empty, page=page)
|
||||
|
||||
if save_data is None:
|
||||
return empty
|
||||
def FileNewest(name, page=None):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
|
||||
extra_info, displayable, save_time = save_data
|
||||
|
||||
return extra_info
|
||||
Returns True if this is the newest file slot, or False otherwise.
|
||||
"""
|
||||
|
||||
return __newest_slot() == __slotname(name, page)
|
||||
|
||||
class FileSave(Action):
|
||||
"""
|
||||
@@ -165,18 +194,16 @@ init -1500 python:
|
||||
|
||||
The button with this slot is selected if it's marked as the
|
||||
newest save file.
|
||||
|
||||
|
||||
`name`
|
||||
The name of the slot to save to. If None, an unused slot
|
||||
(a large number based on the current time) will be
|
||||
will be used.
|
||||
|
||||
(a large number based on the current time) will be used.
|
||||
|
||||
`confirm`
|
||||
If true, then we will prompt before overwriting a file.
|
||||
|
||||
`newest`
|
||||
If true, then this file will be marked as the newest save
|
||||
file when it's saved.
|
||||
Ignored.
|
||||
|
||||
`page`
|
||||
The name of the page that the slot is on. If None, the current
|
||||
@@ -194,33 +221,25 @@ init -1500 python:
|
||||
self.name = name
|
||||
self.confirm = confirm
|
||||
self.page = page
|
||||
self.newest = newest
|
||||
self.page = page
|
||||
self.cycle = cycle
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
fn = __filename(self.name, self.page)
|
||||
|
||||
fn = __slotname(self.name, self.page)
|
||||
|
||||
if renpy.scan_saved_game(fn):
|
||||
if self.confirm:
|
||||
layout.yesno_screen(layout.OVERWRITE_SAVE, FileSave(self.name, False, False, self.page, cycle=self.cycle))
|
||||
return
|
||||
|
||||
if self.cycle:
|
||||
renpy.renpy.loadsave.cycle_saves(self.page + "-", 10)
|
||||
|
||||
if renpy.scan_saved_game(fn):
|
||||
if self.confirm:
|
||||
layout.yesno_screen(layout.OVERWRITE_SAVE, FileSave(self.name, False, self.newest, self.page))
|
||||
return
|
||||
|
||||
renpy.save(fn, extra_info=save_name)
|
||||
|
||||
if self.newest:
|
||||
persistent._file_newest = fn
|
||||
|
||||
if self.page is not None:
|
||||
persistent._file_page = self.page
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_sensitive(self):
|
||||
@@ -236,9 +255,9 @@ init -1500 python:
|
||||
def get_selected(self):
|
||||
if not self.confirm:
|
||||
return False
|
||||
|
||||
return persistent._file_newest == __filename(self.name, self.page)
|
||||
|
||||
|
||||
return __newest_slot() == __slotname(self.name, self.page)
|
||||
|
||||
class FileLoad(Action):
|
||||
"""
|
||||
:doc: file_action
|
||||
@@ -248,35 +267,35 @@ init -1500 python:
|
||||
`name`
|
||||
The name of the slot to load from. If None, an unused slot
|
||||
the file will not be loadable.
|
||||
|
||||
|
||||
`confirm`
|
||||
If true, prompt if loading the file will end the game.
|
||||
|
||||
`page`
|
||||
The page that the file will be loaded from. If None, the
|
||||
current page is used.
|
||||
|
||||
|
||||
`newest`
|
||||
If true, the button is selected if this is the newest file.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name, confirm=True, page=None, newest=True):
|
||||
|
||||
if name is None:
|
||||
name = __unused_slot_name(page)
|
||||
|
||||
|
||||
self.name = name
|
||||
self.confirm = confirm
|
||||
self.page = page
|
||||
self.newest = newest
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
fn = __filename(self.name, self.page)
|
||||
|
||||
|
||||
fn = __slotname(self.name, self.page)
|
||||
|
||||
if not renpy.context()._main_menu:
|
||||
if self.confirm:
|
||||
layout.yesno_screen(layout.LOADING, FileLoad(self.name, False, self.page))
|
||||
@@ -287,14 +306,14 @@ init -1500 python:
|
||||
def get_sensitive(self):
|
||||
if _in_replay:
|
||||
return False
|
||||
|
||||
return renpy.can_load(__filename(self.name, self.page))
|
||||
|
||||
return renpy.can_load(__slotname(self.name, self.page))
|
||||
|
||||
def get_selected(self):
|
||||
if not self.confirm or not self.newest:
|
||||
return False
|
||||
|
||||
return persistent._file_newest == __filename(self.name, self.page)
|
||||
return __newest_slot() == __slotname(self.name, self.page)
|
||||
|
||||
class FileDelete(Action):
|
||||
"""
|
||||
@@ -305,19 +324,19 @@ init -1500 python:
|
||||
`confirm`
|
||||
If true, prompts before deleting a file.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name, confirm=True, page=None):
|
||||
self.name = name
|
||||
self.confirm = confirm
|
||||
self.page = page
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
fn = __filename(self.name, self.page)
|
||||
|
||||
|
||||
fn = __slotname(self.name, self.page)
|
||||
|
||||
if self.confirm:
|
||||
layout.yesno_screen(layout.DELETE_SAVE, FileDelete(self.name, False, self.page))
|
||||
return
|
||||
@@ -325,12 +344,12 @@ init -1500 python:
|
||||
renpy.unlink_save(fn)
|
||||
|
||||
def get_sensitive(self):
|
||||
return renpy.can_load(__filename(self.name, self.page))
|
||||
return renpy.can_load(__slotname(self.name, self.page))
|
||||
|
||||
def get_selected(self):
|
||||
return persistent._file_newest == __filename(self.name, self.page)
|
||||
return __newest_slot() == __slotname(self.name, self.page)
|
||||
|
||||
|
||||
|
||||
def FileAction(name, page=None):
|
||||
"""
|
||||
:doc: file_action
|
||||
@@ -340,19 +359,18 @@ init -1500 python:
|
||||
|
||||
`name`
|
||||
The name of the slot to save to or load from. If None, an unused slot
|
||||
(a large number based on the current time) will be
|
||||
will be used.
|
||||
|
||||
(a large number based on the current time) will be used.
|
||||
|
||||
`page`
|
||||
The page that the file will be saved to or loaded from. If None, the
|
||||
current page is used.
|
||||
"""
|
||||
|
||||
|
||||
if renpy.current_screen().screen_name[0] == "load":
|
||||
return FileLoad(name, page=page)
|
||||
else:
|
||||
return FileSave(name, page=page)
|
||||
|
||||
|
||||
|
||||
class FilePage(Action):
|
||||
"""
|
||||
@@ -361,7 +379,7 @@ init -1500 python:
|
||||
Sets the file page to `page`, which should be one of "auto", "quick",
|
||||
or an integer.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, page):
|
||||
self.page = str(page)
|
||||
|
||||
@@ -371,10 +389,10 @@ init -1500 python:
|
||||
|
||||
persistent._file_page = self.page
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return self.page == persistent._file_page
|
||||
|
||||
|
||||
def FilePageName(auto="a", quick="q"):
|
||||
"""
|
||||
:doc: file_action_function
|
||||
@@ -402,7 +420,7 @@ init -1500 python:
|
||||
that page numbers start with 1. When slot is 2, and slots_per_page
|
||||
is 10, and the other variables are the defauts:
|
||||
|
||||
* When the first page is slowing, this returns "2".
|
||||
* When the first page is showing, this returns "2".
|
||||
* When the second page is showing, this returns "12".
|
||||
* When the auto page is showing, this returns "a2".
|
||||
* When the quicksave page is showing, this returns "q2".
|
||||
@@ -437,8 +455,8 @@ init -1500 python:
|
||||
page = int(page) - 1
|
||||
|
||||
return format % (prefix, page * slots_per_page + slot)
|
||||
|
||||
|
||||
|
||||
|
||||
class FilePageNext(Action):
|
||||
"""
|
||||
:doc: file_action
|
||||
@@ -448,9 +466,12 @@ init -1500 python:
|
||||
`max`
|
||||
If set, this should be an integer that gives the number of
|
||||
the maximum file page we can go to.
|
||||
|
||||
`wrap`
|
||||
If true, we can go to the first page when on the last file page if max is set.
|
||||
"""
|
||||
|
||||
def __init__(self, max=None):
|
||||
def __init__(self, max=None, wrap=False):
|
||||
|
||||
page = persistent._file_page
|
||||
|
||||
@@ -468,13 +489,21 @@ init -1500 python:
|
||||
|
||||
if max is not None:
|
||||
if page > max:
|
||||
page = None
|
||||
if wrap:
|
||||
if config.has_autosave:
|
||||
page = "auto"
|
||||
elif config.has_quicksave:
|
||||
page = "quick"
|
||||
else:
|
||||
page = "1"
|
||||
else:
|
||||
page = None
|
||||
|
||||
if page is not None:
|
||||
page = str(page)
|
||||
|
||||
self.page = page
|
||||
|
||||
|
||||
def __call__(self):
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
@@ -484,27 +513,41 @@ init -1500 python:
|
||||
|
||||
def get_sensitive(self):
|
||||
return self.page is not None
|
||||
|
||||
|
||||
|
||||
class FilePagePrevious(Action):
|
||||
"""
|
||||
:doc: file_action
|
||||
|
||||
Goes to the previous file page, if possible.
|
||||
|
||||
`max`
|
||||
If set, this should be an integer that gives the number of
|
||||
the maximum file page we can go to. This is required to enable
|
||||
wrap.
|
||||
|
||||
`wrap`
|
||||
If true, we can go to the last page when on the first file page if max is set.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, max=None, wrap=False):
|
||||
|
||||
if wrap and max is not None:
|
||||
max = str(max)
|
||||
else:
|
||||
max = None
|
||||
|
||||
|
||||
page = persistent._file_page
|
||||
|
||||
|
||||
if page == "auto":
|
||||
page = None
|
||||
page = max
|
||||
|
||||
elif page == "quick":
|
||||
if config.has_autosave:
|
||||
page = "auto"
|
||||
else:
|
||||
page = None
|
||||
page = max
|
||||
|
||||
elif page == "1":
|
||||
if config.has_quicksave:
|
||||
@@ -512,13 +555,13 @@ init -1500 python:
|
||||
elif config.has_autosave:
|
||||
page = "auto"
|
||||
else:
|
||||
page = None
|
||||
page = max
|
||||
|
||||
else:
|
||||
page = str(int(page) - 1)
|
||||
|
||||
self.page = page
|
||||
|
||||
|
||||
def __call__(self):
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
@@ -540,32 +583,30 @@ init -1500 python:
|
||||
|
||||
def __call__(self):
|
||||
renpy.take_screenshot()
|
||||
|
||||
def QuickSave(message="Quick save complete.", newest=False):
|
||||
|
||||
def QuickSave(message=_("Quick save complete."), newest=False):
|
||||
"""
|
||||
:doc: file_action
|
||||
|
||||
|
||||
Performs a quick save.
|
||||
|
||||
|
||||
`message`
|
||||
A message to display to the user when the quick save finishes.
|
||||
|
||||
`newest`
|
||||
Set to true to mark the quicksave as the newest save.
|
||||
"""
|
||||
|
||||
return [
|
||||
|
||||
return [
|
||||
FileTakeScreenshot(),
|
||||
FileSave(1, page="quick", confirm=False, cycle=True, newest=newest),
|
||||
Notify("Quick save complete.") ]
|
||||
|
||||
FileSave(1, page="quick", confirm=False, cycle=True, newest=newest),
|
||||
Notify(message) ]
|
||||
|
||||
def QuickLoad():
|
||||
"""
|
||||
:doc: file_action
|
||||
|
||||
|
||||
Performs a quick load.
|
||||
"""
|
||||
|
||||
return FileLoad(1, page="quick", confirm=True, newest=False)
|
||||
|
||||
|
||||
return FileLoad(1, page="quick", confirm=True, newest=False)
|
||||
|
||||
Regular → Executable
+63
-28
@@ -3,7 +3,7 @@
|
||||
|
||||
init -1500 python:
|
||||
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Menu-related actions.
|
||||
|
||||
@@ -32,7 +32,7 @@ init -1500 python:
|
||||
|
||||
ShowMenu without an argument will enter the game menu at the
|
||||
default screen, taken from _game_menu_screen.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, screen=None):
|
||||
@@ -46,12 +46,12 @@ init -1500 python:
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
|
||||
orig_screen = screen = self.screen or store._game_menu_screen
|
||||
|
||||
if not (renpy.has_screen(screen) or renpy.has_label(screen)):
|
||||
screen = screen + "_screen"
|
||||
|
||||
|
||||
# Ugly. We have different code depending on if we're in the
|
||||
# game menu or not.
|
||||
if renpy.context()._menu:
|
||||
@@ -61,7 +61,7 @@ init -1500 python:
|
||||
renpy.transition(config.intra_transition)
|
||||
renpy.show_screen(screen, _transient=True)
|
||||
renpy.restart_interaction()
|
||||
|
||||
|
||||
elif renpy.has_label(screen):
|
||||
renpy.transition(config.intra_transition)
|
||||
|
||||
@@ -85,12 +85,12 @@ init -1500 python:
|
||||
return eval(config.show_menu_enable[self.screen])
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
class Start(Action):
|
||||
"""
|
||||
:doc: menu_action
|
||||
|
||||
|
||||
Causes Ren'Py to jump out of the menu context to the named
|
||||
label. The main use of this is to start a new game from the
|
||||
main menu. Common uses are:
|
||||
@@ -98,14 +98,14 @@ init -1500 python:
|
||||
* Start() - Start at the start label.
|
||||
* Start("foo") - Start at the "foo" label.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, label="start"):
|
||||
self.label = label
|
||||
|
||||
def __call__(self):
|
||||
renpy.jump_out_of_context(self.label)
|
||||
|
||||
|
||||
|
||||
class MainMenu(Action):
|
||||
"""
|
||||
:doc: menu_action
|
||||
@@ -120,13 +120,14 @@ init -1500 python:
|
||||
|
||||
def __init__(self, confirm=True):
|
||||
self.confirm = confirm
|
||||
|
||||
|
||||
def __call__(self):
|
||||
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
if self.confirm:
|
||||
renpy.loadsave.force_autosave()
|
||||
layout.yesno_screen(layout.MAIN_MENU, MainMenu(False))
|
||||
else:
|
||||
renpy.full_restart()
|
||||
@@ -145,7 +146,7 @@ init -1500 python:
|
||||
If true, prompts the user if he wants to quit, rather
|
||||
than quitting directly.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, confirm=True):
|
||||
self.confirm = confirm
|
||||
|
||||
@@ -154,10 +155,10 @@ init -1500 python:
|
||||
if self.confirm:
|
||||
renpy.loadsave.force_autosave()
|
||||
layout.yesno_screen(layout.QUIT, Quit(False))
|
||||
else:
|
||||
renpy.quit()
|
||||
else:
|
||||
renpy.jump("_quit")
|
||||
|
||||
|
||||
|
||||
class Skip(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
@@ -165,22 +166,41 @@ init -1500 python:
|
||||
Causes the game to begin skipping. If the game is in a menu
|
||||
context, then this returns to the game. Otherwise, it just
|
||||
enables skipping.
|
||||
|
||||
`fast`
|
||||
If True, skips directly to the next menu choice.
|
||||
"""
|
||||
|
||||
fast = False
|
||||
|
||||
def __init__(self, fast=False):
|
||||
`fast`
|
||||
If true, skips directly to the next menu choice.
|
||||
|
||||
`confirm`
|
||||
If true, asks for confirmation before beginning skipping.
|
||||
"""
|
||||
|
||||
fast = False
|
||||
confirm = False
|
||||
|
||||
def __init__(self, fast=False, confirm=False):
|
||||
self.fast = fast
|
||||
self.confirm = confirm
|
||||
|
||||
def __call__(self):
|
||||
if not self.get_sensitive():
|
||||
return
|
||||
|
||||
if self.confirm:
|
||||
if self.fast:
|
||||
if _preferences.skip_unseen:
|
||||
layout.yesno_screen(layout.FAST_SKIP_UNSEEN, Skip(True))
|
||||
else:
|
||||
layout.yesno_screen(layout.FAST_SKIP_SEEN, Skip(True))
|
||||
else:
|
||||
layout.yesno_screen(layout.SLOW_SKIP, Skip(False))
|
||||
|
||||
return
|
||||
|
||||
if renpy.context()._menu:
|
||||
renpy.jump("_return_skipping")
|
||||
if self.fast:
|
||||
renpy.jump("_return_fast_skipping")
|
||||
else:
|
||||
renpy.jump("_return_skipping")
|
||||
else:
|
||||
|
||||
if not config.skipping:
|
||||
@@ -194,10 +214,25 @@ init -1500 python:
|
||||
renpy.restart_interaction()
|
||||
|
||||
def get_selected(self):
|
||||
return config.skipping
|
||||
|
||||
if self.fast:
|
||||
return config.skipping == "fast"
|
||||
else:
|
||||
return config.skipping and config.skipping != "fast"
|
||||
|
||||
def get_sensitive(self):
|
||||
return config.allow_skipping and (not renpy.context()._main_menu)
|
||||
if not config.allow_skipping:
|
||||
return False
|
||||
|
||||
if store.main_menu:
|
||||
return False
|
||||
|
||||
if renpy.game.context().seen_current(True):
|
||||
return True
|
||||
|
||||
if _preferences.skip_unseen:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class Help(Action):
|
||||
@@ -216,7 +251,7 @@ init -1500 python:
|
||||
|
||||
def __init__(self, help=None):
|
||||
self.help = help
|
||||
|
||||
|
||||
def __call__(self):
|
||||
_help(self.help)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ init -1500 python:
|
||||
class InvertSelected(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
|
||||
This inverts the selection state of the provided action, while
|
||||
proxying over all of the other methods.
|
||||
"""
|
||||
@@ -19,7 +19,7 @@ init -1500 python:
|
||||
|
||||
def get_selected(self):
|
||||
return not self.action.get_selected()
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return self.action.get_sensitive()
|
||||
|
||||
@@ -38,7 +38,7 @@ init -1500 python:
|
||||
Note that the default, None, can be used as an action that causes
|
||||
a button to be disabled.
|
||||
"""
|
||||
|
||||
|
||||
if expression:
|
||||
return true
|
||||
else:
|
||||
@@ -48,64 +48,64 @@ init -1500 python:
|
||||
class SelectedIf(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
|
||||
This allows an expression to control if a button should be marked
|
||||
as selected. It should be used as part of a list with one or more
|
||||
actions. For example::
|
||||
|
||||
|
||||
# The button is selected if mars_flag is True
|
||||
textbutton "Marsopolis":
|
||||
textbutton "Marsopolis":
|
||||
action [ Jump("mars"), SelectedIf(mars_flag) ]
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, expression):
|
||||
self.expression = expression
|
||||
|
||||
|
||||
def __call__(self):
|
||||
return None
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return self.expression
|
||||
|
||||
class Screenshot(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
|
||||
Takes a screenshot.
|
||||
"""
|
||||
|
||||
|
||||
def __call__(self):
|
||||
_screenshot()
|
||||
|
||||
|
||||
|
||||
def HideInterface():
|
||||
"""
|
||||
:doc other_action
|
||||
|
||||
|
||||
Causes the interface to be hidden until the user clicks.
|
||||
"""
|
||||
|
||||
return ui.callsinnewcontext("_hide_windows")
|
||||
|
||||
|
||||
|
||||
class OpenURL(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
|
||||
Causes `url` to be opened in a web browser.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
|
||||
|
||||
def __call__(self):
|
||||
try:
|
||||
import webbrowser
|
||||
webbrowser.open_new(self.url)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
class With(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
@@ -114,8 +114,8 @@ init -1500 python:
|
||||
"""
|
||||
|
||||
def __init__(self, transition):
|
||||
self.transition = transition
|
||||
|
||||
self.transition = transition
|
||||
|
||||
def __call__(self):
|
||||
renpy.transition(self.transition)
|
||||
renpy.restart_interaction()
|
||||
@@ -124,45 +124,49 @@ init -1500 python:
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
Displays `message` using :func:`renpy.notify`.
|
||||
Displays `message` using :func:`renpy.notify`.
|
||||
"""
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
def predict(self):
|
||||
renpy.predict_screen("notify")
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.notify(self.message)
|
||||
|
||||
def Rollback():
|
||||
class Rollback(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
|
||||
This action causes a rollback to occur, when a rollback is possible.
|
||||
Otherwise, nothing happens.
|
||||
"""
|
||||
|
||||
return renpy.rollback
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.rollback()
|
||||
|
||||
def get_sensitive(self):
|
||||
return renpy.can_rollback()
|
||||
|
||||
class RollForward(Action):
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
This action causes a rollforward to occur, if a roll forward is
|
||||
|
||||
This action causes a rollforward to occur, if a roll forward is
|
||||
possible. Otherwise, it is insensitive.
|
||||
"""
|
||||
|
||||
|
||||
def __call__(self):
|
||||
return renpy.roll_forward_info()
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return renpy.roll_forward_info() is not None
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
class __TooltipAction(object):
|
||||
|
||||
def __init__(self, tooltip, value):
|
||||
@@ -172,28 +176,28 @@ init -1500 python:
|
||||
def __call__(self):
|
||||
if self.tooltip.value != self.value:
|
||||
self.tooltip.value = self.value
|
||||
renpy.restart_interaction()
|
||||
renpy.restart_interaction()
|
||||
|
||||
def unhovered(self):
|
||||
if self.tooltip.value != self.tooltip.default:
|
||||
self.tooltip.value = self.tooltip.default
|
||||
renpy.restart_interaction()
|
||||
renpy.restart_interaction()
|
||||
|
||||
_m1_00screen__TooltipAction = __TooltipAction
|
||||
|
||||
class Tooltip(object):
|
||||
"""
|
||||
:doc: tooltips class
|
||||
|
||||
A tooltip object can be used to define a portion of a screen that is
|
||||
updated when the mouse hovers an area.
|
||||
|
||||
|
||||
A tooltip object can be used to define a portion of a screen that is
|
||||
updated when the mouse hovers an area.
|
||||
|
||||
A tooltip object has a ``value`` field, which is set to the `default`
|
||||
value passed to the constructor when the tooltip is created. When
|
||||
a button using an action creadted by the tooltip is hovered, the
|
||||
value field changes to the value associated with the action.
|
||||
value passed to the constructor when the tooltip is created. When
|
||||
a button using an action creadted by the tooltip is hovered, the
|
||||
value field changes to the value associated with the action.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, default):
|
||||
self.value = default
|
||||
self.default = default
|
||||
@@ -202,26 +206,26 @@ init -1500 python:
|
||||
"""
|
||||
:doc: tooltips method
|
||||
:name: Action
|
||||
|
||||
|
||||
Returns an action that is generally used as the hovered property
|
||||
of a button. When the button is hovered, the value field of this
|
||||
of a button. When the button is hovered, the value field of this
|
||||
tooltip is set to `value`. When the buttton loses focus, the
|
||||
value field of this tooltip reverts to the default.
|
||||
"""
|
||||
|
||||
|
||||
return __TooltipAction(self, value)
|
||||
|
||||
|
||||
action = Action
|
||||
|
||||
|
||||
#########################################################################
|
||||
#########################################################################
|
||||
|
||||
class Language(Action):
|
||||
"""
|
||||
:doc: language_action
|
||||
|
||||
|
||||
Changes the language of the game to `language`.
|
||||
|
||||
|
||||
`language`
|
||||
A string giving the language to translate to, or None to use
|
||||
the default language of the game script.
|
||||
@@ -229,21 +233,21 @@ init -1500 python:
|
||||
|
||||
def __init__(self, language):
|
||||
self.language = language
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.change_language(self.language)
|
||||
|
||||
|
||||
def get_selected(self):
|
||||
return _preferences.language == self.language
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
if self.language is None:
|
||||
return True
|
||||
|
||||
|
||||
return self.language in renpy.known_languages()
|
||||
|
||||
|
||||
#########################################################################
|
||||
#########################################################################
|
||||
|
||||
# Transitions used when entering and leaving replays.
|
||||
config.enter_replay_transition = None
|
||||
@@ -252,53 +256,53 @@ init -1500 python:
|
||||
class Replay(Action):
|
||||
"""
|
||||
:doc: replay
|
||||
|
||||
|
||||
An action that starts `label` as a replay.
|
||||
|
||||
|
||||
`scope`
|
||||
A dictionary mapping variable name to value. These variables are set
|
||||
when entering the replay.
|
||||
|
||||
|
||||
`locked`
|
||||
If true, this replay is locked. If false, it is unlocked. If None, the
|
||||
If true, this replay is locked. If false, it is unlocked. If None, the
|
||||
replay is locked if the label has not been seen in any playthrough.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, label, scope={}, locked=None):
|
||||
self.label = label
|
||||
self.scope = scope
|
||||
|
||||
|
||||
if locked is None:
|
||||
self.locked = not renpy.seen_label(label)
|
||||
|
||||
|
||||
self.locked = locked
|
||||
|
||||
def __call__(self):
|
||||
|
||||
|
||||
if self.locked:
|
||||
return
|
||||
|
||||
|
||||
if config.enter_replay_transition:
|
||||
renpy.transition(config.enter_replay_transition)
|
||||
|
||||
|
||||
renpy.call_replay(self.label, self.scope)
|
||||
|
||||
|
||||
if config.exit_replay_transition:
|
||||
renpy.transition(config.exit_replay_transition)
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return not self.locked
|
||||
|
||||
|
||||
class EndReplay(Action):
|
||||
"""
|
||||
:doc: replay
|
||||
|
||||
|
||||
An action that ends the current memory.
|
||||
"""
|
||||
|
||||
|
||||
def __call__(self):
|
||||
renpy.end_replay()
|
||||
|
||||
|
||||
def get_sensitive(self):
|
||||
return _in_replay
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user