Compare commits
389 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 201b6432c4 | |||
| fc10bbf6b6 | |||
| 1c82c71aea | |||
| a59abd3135 | |||
| a51633b511 | |||
| 2b40d265f9 | |||
| 734b5b02f8 | |||
| 4120434e5a | |||
| 6d9c4dc6d9 | |||
| ce94a1360a | |||
| 27a61f4faf | |||
| 36f50a482b | |||
| 28d681b29b | |||
| ddb53bfce1 | |||
| 81414254f9 | |||
| 4af4481a17 | |||
| f1cff045e1 | |||
| f75f0ccb14 | |||
| 01f82aaf4c | |||
| 8b294e05ad | |||
| 5b2fcb85e5 | |||
| fb1d38dc3a | |||
| 5cc6a8d75a | |||
| fbe2a03933 | |||
| 915bccf099 | |||
| 0943e368e7 | |||
| d35c6e190c | |||
| 1025ad5a6a | |||
| fd74541318 | |||
| 821db477ae | |||
| ed66034930 | |||
| a9c91378fd | |||
| 1dc58f2ed1 | |||
| ae916e2a59 | |||
| f3af72e67e | |||
| 939c2121b7 | |||
| 46699bfc1e | |||
| 63d381d5a6 | |||
| c608d18684 | |||
| c31f61e7b6 | |||
| 9912c15c04 | |||
| 651653593c | |||
| 85858974b8 | |||
| a265fbb797 | |||
| e353ea2d56 | |||
| 6f91db067a | |||
| 8ed51cc810 | |||
| f256f174f9 | |||
| 49d3796378 | |||
| bfb6a18527 | |||
| 2960220a74 | |||
| c6605f1742 | |||
| cebffcfee1 | |||
| 006cdb8c3b | |||
| 374e0697bf | |||
| f988878424 | |||
| e59b252dce | |||
| b2747914d8 | |||
| 41aeb625f3 | |||
| 4cfa8aa06c | |||
| 8cb4a4e3b9 | |||
| 9a84c9715f | |||
| 38538f1d9a | |||
| 6a42b2a107 | |||
| 486790b810 | |||
| 0e538e2261 | |||
| 9042fcca55 | |||
| 040035adbc | |||
| d72097de18 | |||
| d9771bdade | |||
| 07ca905373 | |||
| ccd0d45a67 | |||
| 15a15870e7 | |||
| 28108c7796 | |||
| 171f388120 | |||
| bc50f171db | |||
| ea4c955f1f | |||
| 27524457d0 | |||
| 01fe67cfa9 | |||
| f4d493465d | |||
| 33cbe44390 | |||
| 5214f08d1a | |||
| 608fc986c4 | |||
| 779a96f97f | |||
| faf48246d7 | |||
| 81ec2a6c35 | |||
| 803423f12b | |||
| b384ee0381 | |||
| b8862d6b24 | |||
| dbfa4ed46d | |||
| d9eb999775 | |||
| b4a9ca3f87 | |||
| d087c86d1a | |||
| 0cfc7b25a6 | |||
| 8f3c9bd2ba | |||
| 91c79cdac9 | |||
| 20e4e110ce | |||
| 870d7ffe2c | |||
| 6ff88c914d | |||
| 2a2078517f | |||
| c09f697293 | |||
| a9e273a13d | |||
| 592665aa9a | |||
| 3745788f06 | |||
| 52b09d8f4c | |||
| 32f25cdcec | |||
| 6f022a9b6a | |||
| eea6970929 | |||
| 35ecfd279f | |||
| 1f5c610843 | |||
| 05f4c52c33 | |||
| 326f773e75 | |||
| 2079b518a2 | |||
| 70ed15e5ac | |||
| f1d7fe0c73 | |||
| 08e4b9bafc | |||
| 56a0212316 | |||
| 5df6506191 | |||
| 39779be980 | |||
| bdacdddf14 | |||
| 4b32337ef3 | |||
| 4897d5b7a9 | |||
| 6daa64facd | |||
| 07651e414d | |||
| 7e1e76f0d8 | |||
| b91a5d1a16 | |||
| 39b0646f24 | |||
| ea6406f144 | |||
| 7ed3f3fbad | |||
| cacb4ac40e | |||
| 9503744631 | |||
| 58dfd5dbfa | |||
| 60d5507184 | |||
| 5641cec146 | |||
| dd455e3d14 | |||
| 6876697f74 | |||
| 4373cab8cf | |||
| eeccb5833b | |||
| 790dad0330 | |||
| 078a38af5d | |||
| 8c186d2eb1 | |||
| 81b94b27e0 | |||
| 17e8616e8c | |||
| 50b0dc3c5e | |||
| 9e217e722f | |||
| f466b44b66 | |||
| 34e0fc7cba | |||
| bb88a7bb95 | |||
| 71ba444e62 | |||
| 3e0baee463 | |||
| a0064f5511 | |||
| e7ce23f377 | |||
| 9c6d93968c | |||
| e4b29d58f4 | |||
| a48b87a0d6 | |||
| 763515a937 | |||
| 46a8242e51 | |||
| efa8d66d3d | |||
| b7c71bb3b8 | |||
| aca5438b5a | |||
| e7eb23ab5e | |||
| 05dd8bfcc7 | |||
| 2c299ab079 | |||
| 62acff5c75 | |||
| 316d146893 | |||
| e69fee2108 | |||
| 8fe6e1cf20 | |||
| 6fcf7dbbba | |||
| f55c5f0ce5 | |||
| aaf8369421 | |||
| 8e26c7730c | |||
| 556ca0611a | |||
| e2e78c175b | |||
| 7b8033e6b2 | |||
| d602645fee | |||
| f8ac9c9e83 | |||
| 98c90f8ab3 | |||
| 16bb21ee62 | |||
| 46bfec93d4 | |||
| 00e1ecf37d | |||
| a3e7b290fb | |||
| 27ce59963f | |||
| 54e3a97447 | |||
| f886f710b7 | |||
| a895e1dc6c | |||
| 6f24d8eebd | |||
| 000174c2c4 | |||
| 192aaea186 | |||
| eb0d6b696e | |||
| 94e1b0eb56 | |||
| 694a1cd6d5 | |||
| 0600897a26 | |||
| e8c52f9417 | |||
| 6d86963b1d | |||
| 01e621067a | |||
| cd379ef1a3 | |||
| 41a4fbfb4d | |||
| 04db2112c3 | |||
| d20bfb18bc | |||
| d02d83f896 | |||
| 6b45c92a58 | |||
| 871ad8c07f | |||
| 997290cd28 | |||
| fcfab5ada6 | |||
| 005f45bad3 | |||
| ef64872af5 | |||
| 2cd5528df9 | |||
| 0a73e6f905 | |||
| b9f468e3f4 | |||
| ad5631ffc1 | |||
| 50767c211a | |||
| 8223545b72 | |||
| 9925fa78e7 | |||
| 7834365803 | |||
| 5bfeea6e30 | |||
| 1877fcfe65 | |||
| 98437bc207 | |||
| 49e9560e91 | |||
| 9c5084ef14 | |||
| 401c503c91 | |||
| 73d4515f9e | |||
| 9faadbd077 | |||
| c886f16308 | |||
| 6b4b410708 | |||
| d6e50d840f | |||
| c1848159a9 | |||
| 46f503ec3c | |||
| 71f40a33f7 | |||
| 94e789efde | |||
| d738da4272 | |||
| 8bbf9cb618 | |||
| c5276e5073 | |||
| 9b0a739872 | |||
| b3e817e1d4 | |||
| 96a73712eb | |||
| dc91721ca2 | |||
| 7175bb664c | |||
| 2a49120ac2 | |||
| 4ef546649b | |||
| f1a77bd2b0 | |||
| aa8b6d364b | |||
| 1245c6120e | |||
| 2995118cae | |||
| a201418d1a | |||
| 1b46904897 | |||
| 1cf6764a08 | |||
| 6527b4e198 | |||
| fd4d01374f | |||
| c77a11382d | |||
| 1239153a1c | |||
| ae7152a5fc | |||
| eec4eb73b5 | |||
| 0ab3521005 | |||
| 660ef587c9 | |||
| 541dd7b3c3 | |||
| ca53e2f696 | |||
| 80764e130f | |||
| 6afd0120c1 | |||
| 953be074f2 | |||
| 03781d24d6 | |||
| 55d87064a8 | |||
| 512478b945 | |||
| 1c19ca8062 | |||
| fc764b464d | |||
| 945b4fc1cd | |||
| 902b17462e | |||
| 8b0b39829a | |||
| 356ca9cd1e | |||
| 634da84442 | |||
| 1d109ddaee | |||
| c1f996da07 | |||
| b14c9f8954 | |||
| 126050b4f3 | |||
| 313e417f28 | |||
| e98ef1025c | |||
| 3729e4bc3a | |||
| ac071777ad | |||
| 445972756d | |||
| 91732e7def | |||
| 5b7e4af26c | |||
| 2bb459cda5 | |||
| d410c73074 | |||
| da70f197fe | |||
| c18ffb28d0 | |||
| d5f17ef9f1 | |||
| 79c3f426e5 | |||
| b004dd138f | |||
| 45b479e324 | |||
| b07cbd4193 | |||
| ae2739f32d | |||
| dd51fcb1fd | |||
| edc26fe0a4 | |||
| c9215b3b71 | |||
| 115338bdeb | |||
| b0b10ac7d3 | |||
| 5a6013aac9 | |||
| f3aa299aa0 | |||
| 8e44536133 | |||
| 0cb937298e | |||
| 6ed0491520 | |||
| af7748920c | |||
| 3c1c0310d8 | |||
| 91a67304dd | |||
| 04d0e46c3e | |||
| ed27eac80b | |||
| 1f3e02bbdc | |||
| 275e938602 | |||
| 3f80320d37 | |||
| 0e44ce7636 | |||
| 8fe727a8a1 | |||
| b82f7a5548 | |||
| fe15242479 | |||
| 677a9b0dab | |||
| 309001e2fe | |||
| 90e782c9c6 | |||
| f95d9cacb5 | |||
| 308d1e6b00 | |||
| c57b3004a0 | |||
| 00bd5c96e9 | |||
| 371b11370a | |||
| b9338a7446 | |||
| e39ae375f4 | |||
| 975907aebf | |||
| ccfbdf6f3a | |||
| 7934d40b7c | |||
| 3b569a10bd | |||
| 941d959ee5 | |||
| d5a51c8139 | |||
| fc79078d51 | |||
| d6615410dd | |||
| adee372b4b | |||
| 9c7542a357 | |||
| bc18285a61 | |||
| 7b6c3f52e0 | |||
| f95c6e479d | |||
| e4e224348f | |||
| 7e914da261 | |||
| ae3eb40a0e | |||
| 2f8cd81870 | |||
| a1e7b60dab | |||
| 92515fca49 | |||
| 6a8abf2a79 | |||
| 9a47b02840 | |||
| 488c1c34cd | |||
| 52bd7de14f | |||
| deb0f813ca | |||
| 5030513375 | |||
| 53deb04137 | |||
| 2c60f5251f | |||
| 64ac5a9317 | |||
| 607113b31c | |||
| 5a472ef44b | |||
| c67ba9b4e4 | |||
| 3f36d3a881 | |||
| d188618785 | |||
| e6827bdff8 | |||
| 85ac26fb1e | |||
| abea49df8e | |||
| bfc7de0d16 | |||
| aa8c3ecec9 | |||
| 7ab984972e | |||
| da09c4d04f | |||
| c42457446f | |||
| 40bb6ca557 | |||
| f2cc5d25e8 | |||
| 04a5460e8b | |||
| 12ef8ee199 | |||
| 9c2d2f3a06 | |||
| 94bcfe5c58 | |||
| fecd13c733 | |||
| a9a6595d43 | |||
| e4e9ea4e87 | |||
| 588682f0d2 | |||
| 0b502d5530 | |||
| 86a2b5d4e5 | |||
| 312a657e78 | |||
| 6197597ec9 | |||
| c3ee29a9b0 | |||
| d5b26aa973 | |||
| 5d926ad49b | |||
| b5f133ce17 | |||
| 6ee4474e5e | |||
| d515d07110 | |||
| 3d2e5124d4 | |||
| 48a826a13d | |||
| 64e82c2c62 | |||
| 9c5d4d7ad5 | |||
| 5f006c8f4c | |||
| 3d8b6cbecb |
@@ -49,7 +49,6 @@ renpygame-1.2.zip
|
||||
speedtest
|
||||
styles.txt
|
||||
renpygame-demo/game/saves
|
||||
./lib
|
||||
Lucy Sprites.zip
|
||||
translate
|
||||
close_bugs.py
|
||||
@@ -58,3 +57,13 @@ scite-6.10.zip
|
||||
scite-renpy-20090803.zip
|
||||
module/cython.sh
|
||||
old_demo
|
||||
opengl.txt
|
||||
Microsoft.VC90.CRT.manifest
|
||||
console.exe
|
||||
msvcr90.dll
|
||||
python26.dll
|
||||
renpy.exe
|
||||
lib/windows-x86
|
||||
sphinx/source/inc/*
|
||||
doc/*
|
||||
updates/prerelease
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
New in Ren'Py 6.10.2
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ if [ "x$1" = "x" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
rsync -av updates tom@onegeek.org:/home/tom/WWW.update/renpy/
|
||||
|
||||
mkdir ~/ab/website/renpy/dl/$1
|
||||
cp dists/renpy-$1-* ~/ab/website/renpy/dl/$1
|
||||
cp CHANGELOG.txt ~/ab/website/renpy/dl/$1
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import shutil
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
import zipfile
|
||||
import traceback
|
||||
import os
|
||||
|
||||
# The pythonpath on my system.
|
||||
sys.path.insert(0, 'c:\\msys\\1.0\\newbuild25\\install\\bin')
|
||||
sys.path.insert(0, 'c:\\msys\\1.0\\newbuild25\\install\\python')
|
||||
sys.path.insert(0, 'c:\\msys\\1.0\\newbuild\\install\\bin')
|
||||
sys.path.insert(0, 'c:\\msys\\1.0\\newbuild\\install\\python')
|
||||
|
||||
def move_from_dist(fn):
|
||||
"""
|
||||
Moves the file `fn` from the dist directory to the main
|
||||
directory. (This means we don't need symlinks on windows.)
|
||||
"""
|
||||
|
||||
if os.path.isdir(fn):
|
||||
shutil.rmtree(fn)
|
||||
elif os.path.exists(fn):
|
||||
os.unlink(fn)
|
||||
|
||||
os.rename("dist/" + fn, fn)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
sys.argv[1:] = [ 'py2exe', '--bundle', '2', '-a', '--dll-excludes', 'w9xpopen.exe', ]
|
||||
# sys.argv[1:] = [ 'py2exe', '-a', '--dll-excludes', 'w9xpopen.exe', ]
|
||||
sys.argv[1:] = [ 'py2exe', '-a', '--dll-excludes', 'w9xpopen.exe', ]
|
||||
|
||||
setup(name="RenPy",
|
||||
setup(name="Ren'Py",
|
||||
windows=[ dict(script="renpy.py",
|
||||
dest_base="renpy",
|
||||
icon_resources=[ (1, "newicon.ico") ],
|
||||
@@ -24,7 +39,7 @@ def main():
|
||||
|
||||
console=[ dict(script="renpy.py", dest_base="console") ],
|
||||
|
||||
zipfile='renpy.code',
|
||||
zipfile='lib/windows-x86/renpy.code',
|
||||
|
||||
options={ 'py2exe' : { 'excludes' : [ 'doctest',
|
||||
'pygame.macosx',
|
||||
@@ -48,8 +63,8 @@ def main():
|
||||
)
|
||||
|
||||
|
||||
zfold = zipfile.ZipFile("dist/renpy.code")
|
||||
zfnew = zipfile.ZipFile("renpy.code", "w", zipfile.ZIP_STORED)
|
||||
zfold = zipfile.ZipFile("dist/lib/windows-x86/renpy.code")
|
||||
zfnew = zipfile.ZipFile("dist/lib/windows-x86/renpy.code.new", "w", zipfile.ZIP_STORED)
|
||||
|
||||
seen = { }
|
||||
|
||||
@@ -70,6 +85,18 @@ def main():
|
||||
zfold.close()
|
||||
zfnew.close()
|
||||
|
||||
os.unlink("dist/lib/windows-x86/renpy.code")
|
||||
os.rename("dist/lib/windows-x86/renpy.code.new", "dist/lib/windows-x86/renpy.code")
|
||||
|
||||
shutil.copy("c:/Python26/Microsoft.VC90.CRT.manifest", "Microsoft.VC90.CRT.manifest")
|
||||
shutil.copy("c:/Python26/msvcr90.dll", "msvcr90.dll")
|
||||
|
||||
move_from_dist("lib/windows-x86")
|
||||
move_from_dist("console.exe")
|
||||
move_from_dist("python26.dll")
|
||||
move_from_dist("renpy.exe")
|
||||
|
||||
|
||||
try:
|
||||
main()
|
||||
except:
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
1#!/usr/bin/env python
|
||||
|
||||
import collections
|
||||
import glob
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
# A map from string to filename, line number where the string is found.
|
||||
strings = collections.defaultdict(list)
|
||||
|
||||
def process(fn):
|
||||
|
||||
lineno = 0
|
||||
|
||||
for data in file(fn, "r"):
|
||||
|
||||
lineno += 1
|
||||
|
||||
matches = [ ]
|
||||
|
||||
matches += re.finditer(r'\bu\"(\\"|[^"])+\"', data)
|
||||
matches += re.finditer(r"\bu\'(\\'|[^'])+\'", data)
|
||||
|
||||
for m in matches:
|
||||
s = m.group(0)[2:-1]
|
||||
|
||||
if "\\u" in s:
|
||||
continue
|
||||
|
||||
if len(s) == 1:
|
||||
continue
|
||||
|
||||
strings[s].append("%s:%d" % (fn, lineno))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
files = [ ]
|
||||
|
||||
files += glob.glob("launcher2/*.rpy")
|
||||
files += glob.glob("common/*.rpy")
|
||||
files += glob.glob("common/_layout/*.rpym")
|
||||
files += glob.glob("common/_compat/*.rpym")
|
||||
|
||||
for fn in files:
|
||||
process(fn)
|
||||
|
||||
|
||||
converse = [ ]
|
||||
|
||||
for k, v in strings.iteritems():
|
||||
v = " ".join(sorted(v))
|
||||
converse.append((v, k))
|
||||
|
||||
converse.sort()
|
||||
|
||||
print """\
|
||||
# Ren'Py Visual Novel Engine
|
||||
# Copyright (C) 2009 PyTom <pytom@bishoujo.us>
|
||||
# This file is distributed under the same license as the Ren'Py package.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mainline\\n"
|
||||
"Report-Msgid-Bugs-To: PyTom <pytom@bishoujo.us>\\n"
|
||||
"POT-Creation-Date: %s\\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\\n"
|
||||
"Content-Transfer-Encoding: 8bit\\n"
|
||||
""" % time.strftime("%Y-%m-%d %H:%M%z")
|
||||
|
||||
for v, k in converse:
|
||||
print
|
||||
print "#:", v
|
||||
print "#, python-format"
|
||||
print "msgid \"%s\"" % k
|
||||
print "msgstr \"\""
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,21 @@ init -1210 python:
|
||||
store.offscreenleft = Position(xpos=0.0, xanchor=1.0)
|
||||
store.offscreenright = Position(xpos=1.0, xanchor=0.0)
|
||||
|
||||
if version <= (6, 10, 2):
|
||||
# Before 6.11, we used the image placement to handle
|
||||
# the location of things on the screen.
|
||||
style.image_placement.xpos = 0.5
|
||||
style.image_placement.ypos = 1.0
|
||||
style.image_placement.xanchor = 0.5
|
||||
style.image_placement.yanchor = 1.0
|
||||
|
||||
config.transform_uses_child_position = False
|
||||
config.default_transform = None
|
||||
config.start_scene_black = True
|
||||
|
||||
if version <= (6, 11, 0):
|
||||
config.movetransition_respects_offsets = False
|
||||
|
||||
|
||||
init 1210 python hide::
|
||||
|
||||
|
||||
@@ -35,20 +35,17 @@ init -1110:
|
||||
xpos 1.0 xanchor 0.0 ypos 1.0 yanchor 1.0
|
||||
|
||||
transform default:
|
||||
reset
|
||||
center
|
||||
alpha 1 rotate None zoom 1 xzoom 1 yzoom 1 align (0, 0) alignaround (0, 0) subpixel False size None crop None
|
||||
xpos 0.5 xanchor 0.5 ypos 1.0 yanchor 1.0
|
||||
|
||||
python:
|
||||
config.default_transform = right
|
||||
config.default_transform = default
|
||||
|
||||
|
||||
init -1110 python:
|
||||
|
||||
_define = define = object()
|
||||
|
||||
# Positions ##############################################################
|
||||
|
||||
|
||||
# Transitions ############################################################
|
||||
|
||||
# Simple transitions.
|
||||
@@ -193,4 +190,4 @@ init 1110 python:
|
||||
|
||||
# This is necessary to ensure that config.default_transform works.
|
||||
if config.default_transform:
|
||||
config.default_transform.show()
|
||||
config.default_transform._show()
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
# This contains code to choose between OpenGL and Software rendering, when
|
||||
# a system supports both.
|
||||
|
||||
init -1024:
|
||||
screen _gl_test:
|
||||
frame:
|
||||
xalign .5
|
||||
yalign .33
|
||||
|
||||
xpadding 20
|
||||
ypadding 20
|
||||
|
||||
has vbox
|
||||
|
||||
label _(u"Graphics Acceleration")
|
||||
|
||||
null height 10
|
||||
|
||||
textbutton _(u"Automatically Choose"):
|
||||
size_group "gl"
|
||||
action SetField(persistent, "_gl_test", "auto")
|
||||
textbutton _(u"Prefer Software Renderer"):
|
||||
size_group "gl"
|
||||
action SetField(persistent, "_gl_test", "sw")
|
||||
textbutton _(u"Prefer OpenGL Renderer"):
|
||||
size_group "gl"
|
||||
action SetField(persistent, "_gl_test", "gl")
|
||||
|
||||
null height 10
|
||||
|
||||
textbutton _(u"Continue"):
|
||||
size_group "gl"
|
||||
action Return(True)
|
||||
|
||||
init -1024 python:
|
||||
# The image that we fill the screen with in GL-test mode.
|
||||
config.gl_test_image = "black"
|
||||
|
||||
class __GLTest(renpy.Displayable):
|
||||
"""
|
||||
This counts the number of times it's been rendered, and
|
||||
the number of seconds it's been displayed, and uses them
|
||||
to make the decisions as to if OpenGL is working or not.
|
||||
"""
|
||||
|
||||
def __init__(self, frames, fps, timeout):
|
||||
super(__GLTest, self).__init__()
|
||||
|
||||
self.target = 1.0 * frames / fps
|
||||
self.frames = frames
|
||||
self.timeout = timeout
|
||||
|
||||
self.times = [ ]
|
||||
self.success = False
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
self.times.append(st)
|
||||
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
if len(self.times) >= self.frames:
|
||||
if (self.times[-1] - self.times[-self.frames]) < self.target:
|
||||
self.success = True
|
||||
renpy.timeout(0)
|
||||
|
||||
rv = renpy.Render(width, height)
|
||||
return rv
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if self.success:
|
||||
return True
|
||||
|
||||
if st > self.timeout:
|
||||
return False
|
||||
|
||||
renpy.timeout(self.timeout - st)
|
||||
|
||||
|
||||
def __gl_prefer_renderers(renderers):
|
||||
"""
|
||||
Forces the current renderer to be renderer, one of gl or sw.
|
||||
"""
|
||||
|
||||
if renpy.display.prefer_renderers == renderers:
|
||||
return
|
||||
|
||||
renpy.display.prefer_renderers = renderers
|
||||
renpy.display_reset()
|
||||
|
||||
def __gl_prompt():
|
||||
"""
|
||||
Decides if we want to prompt the user to enable OpenGL mode.
|
||||
If so, shows a screen that allows the user to alter the
|
||||
OpenGL setting.
|
||||
"""
|
||||
|
||||
if not renpy.display.interface.safe_mode:
|
||||
return
|
||||
|
||||
__gl_prefer_renderers("sw")
|
||||
|
||||
renpy.call_screen("_gl_test")
|
||||
|
||||
renpy.display.interface.safe_mode = False
|
||||
|
||||
def __gl_test():
|
||||
"""
|
||||
Makes the decision as to if we should use GL or SW mode.
|
||||
"""
|
||||
|
||||
import os
|
||||
if "RENPY_RENDERER" in os.environ:
|
||||
return
|
||||
|
||||
# Our decision survives a restart.
|
||||
if _restart:
|
||||
return
|
||||
|
||||
# If GL is disabled, don't bother.
|
||||
if not config.gl_enable:
|
||||
return
|
||||
|
||||
__gl_prompt()
|
||||
|
||||
if persistent._gl_test == "gl":
|
||||
__gl_prefer_renderers("gl,sw")
|
||||
return
|
||||
|
||||
if persistent._gl_test == "sw":
|
||||
__gl_prefer_renderers("sw")
|
||||
return
|
||||
|
||||
__gl_prefer_renderers("gl,sw")
|
||||
|
||||
ui.pausebehavior(0)
|
||||
ui.interact(suppress_underlay=True, suppress_overlay=True)
|
||||
|
||||
# If GL is able to render FRAMES frames at FPS fps in less
|
||||
# than DELAY seconds, we consider it to be operational, and
|
||||
# continue in GL mode. Otherwise, we rever to software
|
||||
# rendering mode.
|
||||
FRAMES = 5
|
||||
FPS = 15
|
||||
DELAY = 1
|
||||
|
||||
renpy.transition(Dissolve(DELAY), always=True, force=True)
|
||||
ui.add(__GLTest(FRAMES, FPS, DELAY))
|
||||
result = ui.interact(suppress_overlay=True, suppress_underlay=True)
|
||||
|
||||
if result:
|
||||
__gl_prefer_renderers("gl,sw")
|
||||
else:
|
||||
__gl_prefer_renderers("sw")
|
||||
|
||||
# Init-time code:
|
||||
# Make a guess as to what modes we should be in.
|
||||
if persistent._gl_test is None:
|
||||
persistent._gl_test = "auto"
|
||||
|
||||
if persistent._gl_test == "sw":
|
||||
renpy.display.prefer_renderers = "sw"
|
||||
|
||||
|
||||
label _gl_test:
|
||||
|
||||
# Show the test image.
|
||||
scene
|
||||
show expression config.gl_test_image
|
||||
|
||||
$ __gl_test()
|
||||
|
||||
# Hide the test image.
|
||||
scene
|
||||
|
||||
return
|
||||
|
||||
@@ -56,6 +56,21 @@ init -1105 python hide:
|
||||
joystick_preferences=layout.classic_joystick_preferences,
|
||||
)
|
||||
|
||||
if renpy.has_screen("main_menu"):
|
||||
defaults["main_menu"] = layout.screen_main_menu
|
||||
|
||||
if renpy.has_screen("load") and renpy.has_screen("save"):
|
||||
defaults["load_save"] = layout.screen_load_save
|
||||
|
||||
if renpy.has_screen("yesno_prompt"):
|
||||
defaults["yesno_prompt"] = layout.screen_yesno_prompt
|
||||
|
||||
if renpy.has_screen("preferences"):
|
||||
defaults["preferences"] = layout.screen_preferences
|
||||
|
||||
if renpy.has_screen("joystick_preferences"):
|
||||
defaults["joystick_preferences"] = layout.screen_joystick_preferences
|
||||
|
||||
for k, v in defaults.iteritems():
|
||||
if k not in layout.provided:
|
||||
v()
|
||||
@@ -343,11 +358,77 @@ init -1105 python hide:
|
||||
config.load_save_selected_idle[variant] = selected_idle
|
||||
config.load_save_selected_hover[variant] = selected_hover
|
||||
config.load_save_hotspots[variant] = hotspots
|
||||
|
||||
|
||||
@layout
|
||||
def screen_main_menu():
|
||||
renpy.load_module("_layout/screen_main_menu")
|
||||
|
||||
@layout
|
||||
def screen_load_save():
|
||||
renpy.load_module("_layout/screen_load_save")
|
||||
|
||||
@layout
|
||||
def screen_preferences():
|
||||
renpy.load_module("_layout/screen_preferences")
|
||||
|
||||
@layout
|
||||
def screen_joystick_preferences():
|
||||
renpy.load_module("_layout/screen_joystick_preferences")
|
||||
|
||||
@layout
|
||||
def screen_yesno_prompt():
|
||||
renpy.load_module("_layout/screen_yesno_prompt")
|
||||
|
||||
layout.ARE_YOU_SURE = u"Are you sure?"
|
||||
layout.DELETE_SAVE = u"Are you sure you want to delete this save?"
|
||||
layout.OVERWRITE_SAVE = u"Are you sure you want to overwrite your save?"
|
||||
layout.LOADING = u"Loading will lose unsaved progress.\nAre you sure you want to do this?"
|
||||
layout.QUIT = u"Are you sure you want to quit?"
|
||||
layout.MAIN_MENU = u"Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
|
||||
|
||||
@layout
|
||||
def yesno_screen(message, yes=None, no=None):
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
This causes the a yes/no prompt screen with the given message
|
||||
to be displayed. The screen will be hidden when the user hits
|
||||
yes or no.
|
||||
|
||||
`message`
|
||||
The message that will be displayed.
|
||||
|
||||
`yes`
|
||||
An action that is run when the user chooses yes.
|
||||
|
||||
`no`
|
||||
An action that is run when the user chooses no.
|
||||
"""
|
||||
|
||||
if renpy.has_screen("yesno_prompt"):
|
||||
|
||||
yes_action = [ Hide("yesno_prompt") ]
|
||||
no_action = [ Hide("yesno_prompt") ]
|
||||
|
||||
if yes is not None:
|
||||
yes_action.append(yes)
|
||||
if no is not None:
|
||||
no_action.append(no)
|
||||
|
||||
renpy.show_screen(
|
||||
"yesno_prompt",
|
||||
message=message,
|
||||
yes_action=yes_action,
|
||||
no_action=no_action)
|
||||
|
||||
renpy.restart_interaction()
|
||||
|
||||
return
|
||||
|
||||
if renpy.invoke_in_new_context(layout.yesno_prompt, None, message):
|
||||
if yes is not None:
|
||||
yes()
|
||||
else:
|
||||
if no is not None:
|
||||
no()
|
||||
|
||||
|
||||
@@ -47,6 +47,12 @@ init -1180 python:
|
||||
# preference when the game is first run.
|
||||
config.default_text_cps = None
|
||||
|
||||
# If not None, the default value of afm_time
|
||||
config.default_afm_time = None
|
||||
|
||||
# If not None, the default value of afm_enable
|
||||
config.default_afm_enable = None
|
||||
|
||||
# Should we automatically define images?
|
||||
config.automatic_images = None
|
||||
|
||||
@@ -58,6 +64,9 @@ init -1180 python:
|
||||
|
||||
# Layers to clear when entering the menus.
|
||||
config.menu_clear_layers = [ ]
|
||||
|
||||
# Should we start the game with scene black or just scene?
|
||||
config.start_scene_black = False
|
||||
|
||||
# This is updated to give the user an idea of where a save is
|
||||
# taking place.
|
||||
@@ -81,8 +90,20 @@ init -1180 python:
|
||||
|
||||
|
||||
def _default_empty_window():
|
||||
store.narrator("", interact=False)
|
||||
|
||||
who = _last_say_who
|
||||
|
||||
if who is not None:
|
||||
who = eval(who)
|
||||
|
||||
if who is None:
|
||||
who = narrator
|
||||
|
||||
if isinstance(who, NVLCharacter):
|
||||
nvl_show_core()
|
||||
else:
|
||||
store.narrator("", interact=False)
|
||||
|
||||
config.empty_window = _default_empty_window
|
||||
|
||||
style.skip_indicator = Style(style.default, heavy=True, help='The skip indicator.')
|
||||
@@ -130,27 +151,28 @@ init -1180 python:
|
||||
|
||||
config.help = None
|
||||
|
||||
def _help():
|
||||
if not config.help:
|
||||
def _help(help=None):
|
||||
|
||||
if help is None:
|
||||
help = config.help
|
||||
|
||||
if help is None:
|
||||
return
|
||||
|
||||
if renpy.has_label(config.help):
|
||||
renpy.call_in_new_context(config.help)
|
||||
if renpy.has_label(help):
|
||||
renpy.call_in_new_context(help)
|
||||
return
|
||||
|
||||
_preferences.fullscreen = False
|
||||
|
||||
try:
|
||||
import webbrowser
|
||||
webbrowser.open_new("file:///" + config.basedir + "/" + config.help)
|
||||
webbrowser.open_new("file:///" + config.basedir + "/" + help)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
init -1180 python hide:
|
||||
|
||||
# Called to make a screenshot happen.
|
||||
def screenshot():
|
||||
def _screenshot():
|
||||
import os.path
|
||||
import os
|
||||
import __main__
|
||||
@@ -181,17 +203,28 @@ init -1180 python hide:
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
|
||||
init -1180 python hide:
|
||||
|
||||
def dump_styles():
|
||||
if config.developer:
|
||||
renpy.style.write_text("styles.txt")
|
||||
|
||||
# This is run when entering the game menu.
|
||||
config.game_menu_action = None
|
||||
|
||||
def invoke_game_menu():
|
||||
if renpy.context()._menu:
|
||||
renpy.jump("_noisy_return")
|
||||
if renpy.context()._main_menu:
|
||||
return
|
||||
else:
|
||||
renpy.jump("_noisy_return")
|
||||
else:
|
||||
renpy.call_in_new_context('_game_menu')
|
||||
if config.game_menu_action:
|
||||
renpy.display.behavior.run(config.game_menu_action)
|
||||
else:
|
||||
renpy.call_in_new_context('_game_menu')
|
||||
|
||||
def keymap_toggle_skipping():
|
||||
if renpy.context()._menu:
|
||||
@@ -223,7 +256,7 @@ init -1180 python hide:
|
||||
# the launcher.
|
||||
km = renpy.Keymap(
|
||||
rollback = renpy.rollback,
|
||||
screenshot = screenshot,
|
||||
screenshot = _screenshot,
|
||||
toggle_fullscreen = renpy.toggle_fullscreen,
|
||||
toggle_music = renpy.toggle_music,
|
||||
toggle_skip = keymap_toggle_skipping,
|
||||
@@ -391,6 +424,17 @@ init 1180 python:
|
||||
if config.default_text_cps is not None:
|
||||
_preferences.text_cps = config.default_text_cps
|
||||
|
||||
if config.default_afm_time is not None:
|
||||
_preferences.afm_time = config.default_afm_time
|
||||
|
||||
if config.default_afm_enable is not None:
|
||||
_preferences.afm_enable = config.default_afm_enable
|
||||
_preferences.using_afm_enable = True
|
||||
else:
|
||||
_preferences.afm_enable = True
|
||||
_preferences.using_afm_enable = False
|
||||
|
||||
|
||||
if config.developer:
|
||||
|
||||
def _inspector(l):
|
||||
@@ -402,7 +446,6 @@ init 1180 python:
|
||||
ui.text("Style Inspector")
|
||||
ui.text("")
|
||||
|
||||
|
||||
if not l:
|
||||
ui.text("Nothing to inspect.")
|
||||
|
||||
@@ -538,7 +581,7 @@ label _enter_menu:
|
||||
renpy.context()._menu = True
|
||||
|
||||
# This may be changed, if we are already in the main menu.
|
||||
renpy.context().main_menu = False
|
||||
renpy.context()._main_menu = False
|
||||
renpy.context_dynamic("main_menu")
|
||||
renpy.context_dynamic("_window_subtitle")
|
||||
renpy.context_dynamic("_window")
|
||||
@@ -578,9 +621,14 @@ label _game_menu(_game_menu_screen=_game_menu_screen):
|
||||
$ renpy.play(config.enter_sound)
|
||||
|
||||
call _enter_game_menu from _call__enter_game_menu_0
|
||||
|
||||
|
||||
if renpy.has_label("game_menu"):
|
||||
jump expression "game_menu"
|
||||
|
||||
if renpy.has_screen(_game_menu_screen):
|
||||
$ renpy.show_screen(_game_menu_screen)
|
||||
$ ui.interact()
|
||||
jump _noisy_return
|
||||
|
||||
jump expression _game_menu_screen
|
||||
|
||||
@@ -622,7 +670,7 @@ label _noisy_return:
|
||||
# Return to the game.
|
||||
label _return:
|
||||
|
||||
if renpy.context().main_menu:
|
||||
if renpy.context()._main_menu:
|
||||
$ renpy.transition(config.game_main_transition)
|
||||
jump _main_menu_screen
|
||||
|
||||
@@ -631,7 +679,6 @@ label _return:
|
||||
return
|
||||
|
||||
label _confirm_quit:
|
||||
call _enter_menu from _call__enter_menu_3
|
||||
|
||||
if renpy.has_label("confirm_quit"):
|
||||
jump expression "confirm_quit"
|
||||
@@ -657,6 +704,7 @@ init -1180 python hide:
|
||||
# after_load.
|
||||
label _after_load:
|
||||
$ renpy.context()._menu = False
|
||||
$ renpy.context()._main_menu = False
|
||||
|
||||
if config.after_load_transition:
|
||||
$ renpy.transition(config.after_load_transition, force=True)
|
||||
@@ -673,17 +721,25 @@ label _start:
|
||||
|
||||
python hide:
|
||||
renpy.context()._menu = False
|
||||
renpy.context()._main_menu = False
|
||||
|
||||
for i in config.start_callbacks:
|
||||
i()
|
||||
|
||||
|
||||
$ renpy.block_rollback()
|
||||
|
||||
call _gl_test
|
||||
|
||||
call _load_reload_game from _call__load_reload_game_1
|
||||
|
||||
if not _restart and config.auto_load and renpy.can_load(config.auto_load):
|
||||
$ renpy.load(config.auto_load)
|
||||
|
||||
scene black
|
||||
|
||||
if config.start_scene_black:
|
||||
scene black
|
||||
else:
|
||||
scene
|
||||
|
||||
if not _restart:
|
||||
$ ui.pausebehavior(0)
|
||||
$ ui.interact(suppress_underlay=True, suppress_overlay=True)
|
||||
@@ -707,7 +763,10 @@ label _start:
|
||||
$ renpy.music.stop()
|
||||
|
||||
# Clean out any residual scene from the splashscreen.
|
||||
scene black
|
||||
if config.start_scene_black:
|
||||
scene black
|
||||
else:
|
||||
scene
|
||||
|
||||
|
||||
# This has to be python, to deal with a case where _restart may
|
||||
@@ -742,7 +801,7 @@ label _main_menu(_main_menu_screen="_main_menu_screen"):
|
||||
renpy.dynamic("_load_prompt")
|
||||
_load_prompt = False
|
||||
|
||||
renpy.context().main_menu = True
|
||||
renpy.context()._main_menu = True
|
||||
store.main_menu = True
|
||||
|
||||
jump expression _main_menu_screen
|
||||
@@ -756,11 +815,11 @@ label _main_menu_screen:
|
||||
jump expression "main_menu"
|
||||
|
||||
# New name.
|
||||
if renpy.has_label("main_menu_screen"):
|
||||
elif renpy.has_label("main_menu_screen"):
|
||||
jump expression "main_menu_screen"
|
||||
|
||||
# Compatibility name.
|
||||
if renpy.has_label("_library_main_menu"):
|
||||
elif renpy.has_label("_library_main_menu"):
|
||||
jump expression "_library_main_menu"
|
||||
|
||||
return
|
||||
|
||||
@@ -21,7 +21,7 @@ init -1130 python hide:
|
||||
for i in xrange(0, 8):
|
||||
renpy.music.register_channel(i)
|
||||
|
||||
renpy.music.register_channel("movie", "music", False, stop_on_mute=False)
|
||||
renpy.music.register_channel("movie", "music", False, stop_on_mute=False, buffer_queue=False)
|
||||
|
||||
# Set up default names for some of the channels.
|
||||
renpy.music.alias_channel(0, "sound")
|
||||
|
||||
@@ -79,8 +79,47 @@ init -1100 python:
|
||||
return s[nvl_variant]
|
||||
else:
|
||||
return s
|
||||
|
||||
def nvl_show_core():
|
||||
|
||||
def nvl_show_screen(screen_name, **scope):
|
||||
"""
|
||||
Shows an nvl-mode screen. Returns the "who" widget.
|
||||
"""
|
||||
|
||||
widget_properties = { }
|
||||
dialogue = [ ]
|
||||
|
||||
for i, entry in enumerate(nvl_list):
|
||||
if not entry:
|
||||
continue
|
||||
|
||||
who, what, kwargs = entry
|
||||
|
||||
if i == len(nvl_list) - 1:
|
||||
who_id = "who"
|
||||
what_id = "what"
|
||||
window_id = "window"
|
||||
|
||||
else:
|
||||
who_id = "who%d" % i
|
||||
what_id = "what%d" % i
|
||||
window_id = "window%d" % i
|
||||
|
||||
widget_properties[who_id] = kwargs["who_args"]
|
||||
widget_properties[what_id] = kwargs["what_args"]
|
||||
widget_properties[window_id] = kwargs["window_args"]
|
||||
|
||||
dialogue.append((who, what, who_id, what_id, window_id))
|
||||
|
||||
renpy.show_screen(screen_name, _transient=True, _widget_properties=widget_properties, dialogue=dialogue, **scope)
|
||||
renpy.shown_window()
|
||||
|
||||
return renpy.get_widget(screen_name, "what")
|
||||
|
||||
def nvl_show_core(who=None, what=None):
|
||||
|
||||
# Screen version.
|
||||
if renpy.has_screen("nvl"):
|
||||
return nvl_show_screen("nvl")
|
||||
|
||||
if renpy.in_rollback():
|
||||
nvl_window = __s(style.nvl_window)['rollback']
|
||||
@@ -194,16 +233,19 @@ init -1100 python:
|
||||
else:
|
||||
checkpoint = True
|
||||
|
||||
renpy.display_say(nvl_show_core,
|
||||
checkpoint=checkpoint,
|
||||
**display_args)
|
||||
renpy.display_say(
|
||||
who,
|
||||
what,
|
||||
nvl_show_core,
|
||||
checkpoint=checkpoint,
|
||||
**display_args)
|
||||
|
||||
def do_done(self, who, what):
|
||||
|
||||
if self.clear:
|
||||
nvl_clear()
|
||||
|
||||
def do_extend(self):
|
||||
renpy.mode(self.mode)
|
||||
store.nvl_list = store.nvl_list[:-1]
|
||||
|
||||
# The default NVLCharacter.
|
||||
@@ -213,6 +255,7 @@ init -1100 python:
|
||||
what_style='nvl_dialogue',
|
||||
window_style='nvl_entry',
|
||||
type='nvl',
|
||||
mode='nvl',
|
||||
clear=False,
|
||||
kind=adv)
|
||||
|
||||
@@ -224,32 +267,42 @@ init -1100 python:
|
||||
|
||||
def nvl_menu(items):
|
||||
|
||||
renpy.mode('nvl_menu')
|
||||
|
||||
if nvl_list is None:
|
||||
store.nvl_list = [ ]
|
||||
|
||||
ui.layer("transient")
|
||||
ui.clear()
|
||||
ui.close()
|
||||
|
||||
ui.window(style=__s(style.nvl_window))
|
||||
ui.vbox(style=__s(style.nvl_vbox))
|
||||
if renpy.has_screen("nvl_choice"):
|
||||
|
||||
for i in nvl_list:
|
||||
if not i:
|
||||
continue
|
||||
# Screen version.
|
||||
nvl_show_screen("nvl_choice", items=items)
|
||||
|
||||
who, what, kw = i
|
||||
rv = renpy.show_display_say(who, what, **kw)
|
||||
else:
|
||||
|
||||
renpy.display_menu(items, interact=False,
|
||||
window_style=__s(style.nvl_menu_window),
|
||||
choice_style=__s(style.nvl_menu_choice),
|
||||
choice_chosen_style=__s(style.nvl_menu_choice_chosen),
|
||||
choice_button_style=__s(style.nvl_menu_choice_button),
|
||||
choice_chosen_button_style=__s(style.nvl_menu_choice_chosen_button),
|
||||
)
|
||||
# Traditional version.
|
||||
ui.layer("transient")
|
||||
ui.clear()
|
||||
ui.close()
|
||||
|
||||
ui.close()
|
||||
ui.window(style=__s(style.nvl_window))
|
||||
ui.vbox(style=__s(style.nvl_vbox))
|
||||
|
||||
for i in nvl_list:
|
||||
if not i:
|
||||
continue
|
||||
|
||||
who, what, kw = i
|
||||
rv = renpy.show_display_say(who, what, **kw)
|
||||
|
||||
renpy.display_menu(items, interact=False,
|
||||
window_style=__s(style.nvl_menu_window),
|
||||
choice_style=__s(style.nvl_menu_choice),
|
||||
choice_chosen_style=__s(style.nvl_menu_choice_chosen),
|
||||
choice_button_style=__s(style.nvl_menu_choice_button),
|
||||
choice_chosen_button_style=__s(style.nvl_menu_choice_chosen_button),
|
||||
)
|
||||
|
||||
ui.close()
|
||||
|
||||
roll_forward = renpy.roll_forward_info()
|
||||
|
||||
@@ -263,29 +316,23 @@ init -1100 python:
|
||||
config.nvl_adv_transition = None
|
||||
config.adv_nvl_transition = None
|
||||
|
||||
init 1140 python:
|
||||
|
||||
if config.nvl_adv_transition or config.adv_nvl_transition:
|
||||
# This is used to execute the nvl and adv mode transitions.
|
||||
def _nvl_adv_callback(mode, old_modes):
|
||||
|
||||
def _nvl_adv_callback(event, interact, type, **kwargs):
|
||||
|
||||
if event != "begin" or not interact or renpy.get_transition():
|
||||
return
|
||||
|
||||
old_type = renpy.last_interact_type()
|
||||
|
||||
if old_type == "say" and type == "nvl":
|
||||
# We have an extra line in the nvl_list as we do this. So
|
||||
# take it out for the duration of the nvl_show.
|
||||
old_nvl_list = store.nvl_list
|
||||
store.nvl_list = old_nvl_list[:-1]
|
||||
nvl_show(config.adv_nvl_transition)
|
||||
store.nvl_list = old_nvl_list
|
||||
elif old_type == "nvl" and type == "say":
|
||||
nvl_hide(config.nvl_adv_transition)
|
||||
|
||||
config.all_character_callbacks.insert(0, _nvl_adv_callback)
|
||||
old = old_modes[0]
|
||||
|
||||
if config.adv_nvl_transition:
|
||||
if mode == "nvl" or mode == "nvl_menu":
|
||||
if old == "say" or old == "menu":
|
||||
nvl_show(config.adv_nvl_transition)
|
||||
|
||||
if config.nvl_adv_transition:
|
||||
if mode == "say" or mode == "menu":
|
||||
if old == "nvl" or old == "nvl_menu":
|
||||
nvl_hide(config.nvl_adv_transition)
|
||||
|
||||
config.mode_callbacks.append(_nvl_adv_callback)
|
||||
|
||||
python early hide:
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ python early hide:
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 7
|
||||
channel = "music"
|
||||
|
||||
renpy.music.play(eval(p["file"]),
|
||||
fadeout=eval(p["fadeout"]),
|
||||
@@ -137,19 +137,24 @@ python early hide:
|
||||
def predict_play_music(p):
|
||||
return [ ]
|
||||
|
||||
def lint_play_music(p):
|
||||
def lint_play_music(p, channel="music"):
|
||||
|
||||
file = _try_eval(p["file"], 'filename')
|
||||
if p["channel"] is not None:
|
||||
_try_eval(p["channel"], 'channel')
|
||||
|
||||
if p["channel"] is not None:
|
||||
channel = _try_eval(p["channel"], 'channel')
|
||||
|
||||
if not isinstance(file, list):
|
||||
file = [ file ]
|
||||
|
||||
for fn in file:
|
||||
if isinstance(fn, basestring) and not renpy.loadable(fn):
|
||||
renpy.error("%r is not loadable" % fn)
|
||||
|
||||
if isinstance(fn, basestring):
|
||||
try:
|
||||
if not renpy.music.playable(fn, channel):
|
||||
renpy.error("%r is not loadable" % fn)
|
||||
except:
|
||||
pass
|
||||
|
||||
renpy.statements.register('play music',
|
||||
parse=parse_play_music,
|
||||
execute=execute_play_music,
|
||||
@@ -191,7 +196,7 @@ python early hide:
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 7
|
||||
channel = "music"
|
||||
|
||||
renpy.music.queue(
|
||||
eval(p["file"]),
|
||||
@@ -229,7 +234,7 @@ python early hide:
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 7
|
||||
channel = "music"
|
||||
|
||||
renpy.music.stop(fadeout=eval(p["fadeout"]), channel=channel)
|
||||
|
||||
@@ -246,7 +251,7 @@ python early hide:
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 0
|
||||
channel = "sound"
|
||||
|
||||
fadeout = eval(p["fadeout"]) or 0
|
||||
|
||||
@@ -254,17 +259,20 @@ python early hide:
|
||||
fadeout=fadeout,
|
||||
fadein=eval(p["fadein"]),
|
||||
channel=channel)
|
||||
|
||||
|
||||
def lint_play_sound(p, lint_play_music=lint_play_music):
|
||||
return lint_play_music(p, channel="sound")
|
||||
|
||||
renpy.statements.register('play sound',
|
||||
parse=parse_play_music,
|
||||
execute=execute_play_sound,
|
||||
lint=lint_play_music)
|
||||
lint=lint_play_sound)
|
||||
|
||||
def execute_queue_sound(p):
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 0
|
||||
channel = "sound"
|
||||
|
||||
renpy.sound.queue(eval(p["file"]), channel=channel)
|
||||
|
||||
@@ -278,7 +286,7 @@ python early hide:
|
||||
if p["channel"] is not None:
|
||||
channel = eval(p["channel"])
|
||||
else:
|
||||
channel = 0
|
||||
channel = "sound"
|
||||
|
||||
fadeout = eval(p["fadeout"]) or 0
|
||||
|
||||
@@ -334,7 +342,7 @@ python early hide:
|
||||
if not renpy.music.channel_defined(channel):
|
||||
renpy.error("channel %r is not defined" % channel)
|
||||
|
||||
lint_play_music(p)
|
||||
lint_play_music(p, channel)
|
||||
|
||||
def lint_stop_generic(p):
|
||||
channel = eval(p["channel"])
|
||||
@@ -439,7 +447,6 @@ python early hide:
|
||||
parse=parse_pause,
|
||||
lint=lint_pause,
|
||||
execute=execute_pause)
|
||||
|
||||
|
||||
|
||||
init -1200 python:
|
||||
@@ -453,3 +460,96 @@ init -1200 python:
|
||||
except:
|
||||
renpy.error('unable to evaluate %s %r' % (what, e))
|
||||
|
||||
##############################################################################
|
||||
# Screen-related statements.
|
||||
|
||||
python early hide:
|
||||
|
||||
def parse_show_call_screen(l):
|
||||
|
||||
# Parse a name.
|
||||
name = l.require(l.name)
|
||||
|
||||
# Parse a parameter list. (name -> expression string)
|
||||
parameters = { }
|
||||
|
||||
if l.match(r"\("):
|
||||
|
||||
while True:
|
||||
pname = l.name()
|
||||
if not pname:
|
||||
break
|
||||
|
||||
l.require(r"=")
|
||||
|
||||
expr = l.delimited_python(",)")
|
||||
|
||||
if not expr:
|
||||
l.error("expected expression.")
|
||||
|
||||
parameters[pname] = expr
|
||||
|
||||
if not l.match(r','):
|
||||
break
|
||||
|
||||
l.require(r'\)')
|
||||
l.expect_eol()
|
||||
|
||||
return dict(name=name, parameters=parameters)
|
||||
|
||||
def parse_hide_screen(l):
|
||||
name = l.require(l.name)
|
||||
|
||||
l.expect_eol()
|
||||
|
||||
return dict(name=name)
|
||||
|
||||
def execute_show_screen(p):
|
||||
|
||||
name = p["name"]
|
||||
parameters = p["parameters"]
|
||||
|
||||
kwargs = { }
|
||||
|
||||
for k, v in parameters.iteritems():
|
||||
kwargs[k] = eval(v)
|
||||
|
||||
renpy.show_screen(name, **kwargs)
|
||||
|
||||
def execute_call_screen(p):
|
||||
name = p["name"]
|
||||
parameters = p["parameters"]
|
||||
|
||||
kwargs = { }
|
||||
|
||||
for k, v in parameters.iteritems():
|
||||
kwargs[k] = eval(v)
|
||||
|
||||
store._return = renpy.call_screen(name, **kwargs)
|
||||
|
||||
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",
|
||||
parse=parse_show_call_screen,
|
||||
execute=execute_show_screen,
|
||||
lint=lint_screen)
|
||||
|
||||
renpy.statements.register("call screen",
|
||||
parse=parse_show_call_screen,
|
||||
execute=execute_call_screen,
|
||||
lint=lint_screen)
|
||||
|
||||
renpy.statements.register("hide screen",
|
||||
parse=parse_hide_screen,
|
||||
execute=execute_hide_screen)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,10 +22,14 @@ init -1200 python hide:
|
||||
# Style Declarations #################################################
|
||||
|
||||
style.default = Style(None, help='root of style hierarchy')
|
||||
style.text = Style(style.default, help='style of text')
|
||||
|
||||
style.fixed = Style(style.default, help='fixed layouts')
|
||||
style.hbox = Style(style.default, help='horizontal boxes')
|
||||
style.vbox = Style(style.default, help='vertical boxes')
|
||||
|
||||
style.grid = Style(style.default, help='grid layouts')
|
||||
style.side = Style(style.default, help='side layouts')
|
||||
|
||||
style.window = Style(style.default, help='windows created with ui.window')
|
||||
|
||||
style.image_placement = Style(style.default, help='default placement of images on the screen')
|
||||
@@ -50,7 +54,8 @@ init -1200 python hide:
|
||||
style.menu_choice_chosen_button = Style(style.menu_choice_button, help='buttons containing chosen in-game menu choices')
|
||||
style.menu_window = Style(style.window, help='a window containing a menu')
|
||||
|
||||
style.input_text = Style(style.default, help='text of an input box')
|
||||
style.input = Style(style.default, help='style of an input control')
|
||||
style.input_text = Style(style.input, help='text of an input box')
|
||||
style.input_prompt = Style(style.default, help='prompt of an input box')
|
||||
style.input_window = Style(style.window, help='window of an input box')
|
||||
|
||||
@@ -58,8 +63,10 @@ init -1200 python hide:
|
||||
style.centered_text = Style(style.default, help='centered text')
|
||||
|
||||
style.imagemap = Style(style.image_placement, help='default style of imagemaps')
|
||||
style.imagemap_button = Style(style.default, help='default style of buttons inside imagemaps')
|
||||
|
||||
style.hotspot = Style(style.default, help='default style of hotspots inside imagemaps')
|
||||
style.hotbar = Style(style.default, help='default style of hotbars inside imagemaps')
|
||||
style.imagemap_button = style.hotspot
|
||||
|
||||
style.image_button = Style(style.default, help='default style of image buttons')
|
||||
style.image_button_image = Style(style.default, help='default style of images inside image buttons')
|
||||
|
||||
@@ -76,6 +83,8 @@ init -1200 python hide:
|
||||
style.list_spacer = Style(style.default)
|
||||
style.list_text = Style(style.default)
|
||||
|
||||
style.tile = Style(style.default, help='default style of tile')
|
||||
|
||||
# The base styles that can be customized by themes.
|
||||
|
||||
style.frame = Style(style.default, help='base style for frames.')
|
||||
@@ -213,16 +222,9 @@ init -1090 python:
|
||||
style.window.xfill = True
|
||||
style.window.yfill = False
|
||||
style.window.yminimum = 150 # Includes margins and padding.
|
||||
|
||||
style.window.xalign = 0.5
|
||||
style.window.yalign = 1.0
|
||||
|
||||
# Image placement.
|
||||
style.image_placement.xpos = 0.5
|
||||
style.image_placement.ypos = 1.0
|
||||
style.image_placement.xanchor = 0.5
|
||||
style.image_placement.yanchor = 1.0
|
||||
|
||||
# Dialogue
|
||||
style.say_label.bold = True
|
||||
style.say_vbox.spacing = 8
|
||||
@@ -238,7 +240,7 @@ init -1090 python:
|
||||
# Menus.
|
||||
style.menu_choice.idle_color = "#0ff"
|
||||
style.menu_choice.hover_color = "#ff0"
|
||||
style.input_text.color = "#ff0"
|
||||
style.input.color = "#ff0"
|
||||
|
||||
# Styles used by centered.
|
||||
style.centered_window.xalign = 0.5
|
||||
@@ -295,7 +297,10 @@ init -1090 python:
|
||||
style.list_text.color = "#000"
|
||||
style.list_text.size = 14
|
||||
style.list_spacer.xminimum = 15
|
||||
|
||||
|
||||
# Tile
|
||||
style.tile.clipping = True
|
||||
|
||||
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -71,9 +71,7 @@ init -1110 python hide:
|
||||
style.vscrollbar.bar_vertical = True
|
||||
style.vscrollbar.bar_invert = True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# This recolors the given image using one or two colors.
|
||||
@theme
|
||||
def OneOrTwoColor(image, color):
|
||||
@@ -82,250 +80,68 @@ init -1110 python hide:
|
||||
else:
|
||||
return im.Twocolor(image, color, color)
|
||||
|
||||
@theme
|
||||
def roundrect_frames(
|
||||
less_rounded,
|
||||
frame):
|
||||
def roundrect_based_theme(name, file_prefix, Box=None, frame_png=None):
|
||||
|
||||
theme.clear_frames()
|
||||
|
||||
style.frame.background = RoundRect(frame, less_rounded)
|
||||
if Box is None:
|
||||
def Box(color, ignored):
|
||||
return Frame(theme.OneOrTwoColor(file_prefix + "_box.png", color), 12, 12)
|
||||
|
||||
style.frame.xpadding = 6
|
||||
style.frame.ypadding = 6
|
||||
|
||||
if frame_png is not None:
|
||||
def FrameBox(color, ignored):
|
||||
return Frame(theme.OneOrTwoColor(file_prefix + frame_png, color), 12, 12)
|
||||
else:
|
||||
FrameBox = Box
|
||||
|
||||
@theme
|
||||
def roundrect_buttons(text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text):
|
||||
|
||||
theme.clear_buttons()
|
||||
|
||||
style.button.background = RoundRect(widget, less_rounded)
|
||||
style.button.hover_background = RoundRect(widget_hover, less_rounded)
|
||||
style.button.insensitive_background = RoundRect(disabled, less_rounded)
|
||||
|
||||
style.button_text.size = text_size
|
||||
style.button_text.color = widget_text
|
||||
style.button_text.selected_color = widget_selected
|
||||
style.button_text.insensitive_color = disabled_text
|
||||
|
||||
if less_rounded:
|
||||
style.button.xpadding = 6
|
||||
else:
|
||||
style.button.xpadding = 12
|
||||
|
||||
style.button.ypadding = 1
|
||||
style.button.xmargin = 1
|
||||
style.button.ymargin = 1
|
||||
|
||||
style.button_text.xalign = 0.5
|
||||
style.button_text.yalign = 0.5
|
||||
style.button_text.text_align = 0.5
|
||||
|
||||
@theme
|
||||
def roundrect_large_buttons(
|
||||
text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text):
|
||||
|
||||
theme.clear_large_buttons()
|
||||
|
||||
if less_rounded:
|
||||
style.large_button.xpadding = 6
|
||||
else:
|
||||
style.large_button.xpadding = 12
|
||||
|
||||
style.large_button.ypadding = 1
|
||||
style.large_button.xmargin = 1
|
||||
style.large_button.ymargin = 1
|
||||
|
||||
style.large_button.background = RoundRect(widget, less_rounded)
|
||||
style.large_button.hover_background = RoundRect(widget_hover, less_rounded)
|
||||
style.large_button.insensitive_background = RoundRect(disabled, less_rounded)
|
||||
|
||||
style.large_button_text.size = text_size
|
||||
style.large_button_text.color = widget_text
|
||||
style.large_button_text.selected_color = widget_selected
|
||||
style.large_button_text.insensitive_color = disabled_text
|
||||
|
||||
style.large_button_text.xalign = 0
|
||||
style.large_button_text.yalign = 0
|
||||
|
||||
@theme
|
||||
def roundrect_labels(
|
||||
text_size,
|
||||
label):
|
||||
|
||||
theme.clear_labels()
|
||||
|
||||
style.label_text.size = text_size
|
||||
style.label_text.color = label
|
||||
|
||||
@theme
|
||||
def roundrect_prompts(
|
||||
text_size,
|
||||
label):
|
||||
|
||||
theme.clear_prompts()
|
||||
|
||||
style.prompt_text.size = text_size
|
||||
style.prompt_text.color = label
|
||||
|
||||
style.prompt.xalign = 0.5
|
||||
style.prompt_text.text_align = 0.5
|
||||
style.prompt_text.layout = "subtitle"
|
||||
|
||||
@theme
|
||||
def roundrect_bars(
|
||||
widget,
|
||||
widget_hover):
|
||||
|
||||
theme.clear_bars()
|
||||
|
||||
def img(name, color, x, y):
|
||||
rv = theme.OneOrTwoColor("_roundrect/" + name + ".png", color)
|
||||
if x is not None:
|
||||
rv = Frame(rv, x, y)
|
||||
return rv
|
||||
|
||||
# Bars.
|
||||
style.bar.ymaximum = 24
|
||||
style.bar.left_gutter = 6
|
||||
style.bar.right_gutter = 6
|
||||
style.bar.thumb_offset = 6
|
||||
|
||||
style.bar.left_bar = img("rrslider_full", widget, 12, 0)
|
||||
style.bar.right_bar = img("rrslider_empty", widget, 12, 0)
|
||||
style.bar.thumb = img("rrslider_thumb", widget, None, None)
|
||||
style.bar.hover_left_bar = img("rrslider_full", widget_hover, 12, 0)
|
||||
style.bar.hover_right_bar = img("rrslider_empty", widget_hover, 12, 0)
|
||||
style.bar.hover_thumb = img("rrslider_thumb", widget_hover, None, None)
|
||||
|
||||
style.vbar.xmaximum = 24
|
||||
style.vbar.top_gutter = 6
|
||||
style.vbar.bottom_gutter = 6
|
||||
style.vbar.thumb_offset = 6
|
||||
|
||||
style.vbar.bottom_bar = img("rrvslider_full", widget, 0, 12)
|
||||
style.vbar.top_bar = img("rrvslider_empty", widget, 0, 12)
|
||||
style.vbar.thumb = img("rrvslider_thumb", widget, None, None)
|
||||
style.vbar.hover_bottom_bar = img("rrvslider_full", widget_hover, 0, 12)
|
||||
style.vbar.hover_top_bar = img("rrvslider_empty", widget_hover, 0, 12)
|
||||
style.vbar.hover_thumb = img("rrvslider_thumb", widget_hover, None, None)
|
||||
|
||||
# Sliders.
|
||||
style.slider.ymaximum = 24
|
||||
style.slider.left_gutter = 6
|
||||
style.slider.right_gutter = 6
|
||||
style.slider.thumb_offset = 6
|
||||
|
||||
style.slider.left_bar = img("rrslider_full", widget, 12, 0)
|
||||
style.slider.right_bar = img("rrslider_empty", widget, 12, 0)
|
||||
style.slider.thumb = img("rrslider_thumb", widget, None, None)
|
||||
style.slider.hover_left_bar = img("rrslider_full", widget_hover, 12, 0)
|
||||
style.slider.hover_right_bar = img("rrslider_empty", widget_hover, 12, 0)
|
||||
style.slider.hover_thumb = img("rrslider_thumb", widget_hover, None, None)
|
||||
|
||||
style.vslider.xmaximum = 24
|
||||
style.vslider.top_gutter = 6
|
||||
style.vslider.bottom_gutter = 6
|
||||
style.vslider.thumb_offset = 6
|
||||
|
||||
style.vslider.bottom_bar = img("rrvslider_full", widget, 0, 12)
|
||||
style.vslider.top_bar = img("rrvslider_empty", widget, 0, 12)
|
||||
style.vslider.thumb = img("rrvslider_thumb", widget, None, None)
|
||||
style.vslider.hover_bottom_bar = img("rrvslider_full", widget_hover, 0, 12)
|
||||
style.vslider.hover_top_bar = img("rrvslider_empty", widget_hover, 0, 12)
|
||||
style.vslider.hover_thumb = img("rrvslider_thumb", widget_hover, None, None)
|
||||
|
||||
|
||||
# Scrollbars.
|
||||
style.scrollbar.left_gutter = 6
|
||||
style.scrollbar.right_gutter = 6
|
||||
style.scrollbar.thumb_offset = 6
|
||||
style.scrollbar.ymaximum = 12
|
||||
|
||||
style.scrollbar.left_bar = img("rrscrollbar", widget, 12, 0)
|
||||
style.scrollbar.right_bar = img("rrscrollbar", widget, 12, 0)
|
||||
style.scrollbar.thumb = img("rrscrollbar_thumb", widget, None, None)
|
||||
style.scrollbar.hover_left_bar = img("rrscrollbar", widget_hover, 12, 0)
|
||||
style.scrollbar.hover_right_bar = img("rrscrollbar", widget_hover, 12, 0)
|
||||
style.scrollbar.hover_thumb = img("rrscrollbar_thumb", widget_hover, None, None)
|
||||
|
||||
style.vscrollbar.top_gutter = 6
|
||||
style.vscrollbar.bottom_gutter = 6
|
||||
style.vscrollbar.thumb_offset = 6
|
||||
style.vscrollbar.xmaximum = 12
|
||||
|
||||
style.vscrollbar.left_bar = img("rrvscrollbar", widget, 0, 12)
|
||||
style.vscrollbar.right_bar = img("rrvscrollbar", widget, 0, 12)
|
||||
style.vscrollbar.thumb = img("rrvscrollbar_thumb", widget, None, None)
|
||||
style.vscrollbar.hover_left_bar = img("rrvscrollbar", widget_hover, 0, 12)
|
||||
style.vscrollbar.hover_right_bar = img("rrvscrollbar", widget_hover, 0, 12)
|
||||
style.vscrollbar.hover_thumb = img("rrvscrollbar_thumb", widget_hover, None, None)
|
||||
|
||||
@theme
|
||||
def roundrect(
|
||||
widget = (0, 60, 120, 255),
|
||||
widget_hover = (0, 80, 160, 255),
|
||||
widget_text = (200, 225, 255, 255),
|
||||
widget_selected = (255, 255, 200, 255),
|
||||
disabled = (64, 64, 64, 255),
|
||||
disabled_text = (200, 200, 200, 255),
|
||||
label = (255, 255, 255, 255),
|
||||
frame = (100, 150, 200, 255),
|
||||
window = (0, 0, 0, 192),
|
||||
mm_root = Solid((220, 235, 255, 255)),
|
||||
gm_root = Solid((220, 235, 255, 255)),
|
||||
|
||||
text_size=None,
|
||||
small_text_size=None,
|
||||
less_rounded = False,
|
||||
|
||||
# Compat for the old roundrect theme.
|
||||
window = None,
|
||||
button_menu = None,
|
||||
rounded_window = True,
|
||||
outline_bars = False,
|
||||
|
||||
mm_root = None,
|
||||
gm_root = None):
|
||||
|
||||
if button_menu is None:
|
||||
if (config.script_version is not None) and (config.script_version < (6, 9, 0)):
|
||||
button_menu = True
|
||||
else:
|
||||
button_menu = False
|
||||
|
||||
layout.defaults()
|
||||
|
||||
if config.screen_width <= 640:
|
||||
text_size = text_size or 18
|
||||
small_text_size = small_text_size or 12
|
||||
less_rounded = True
|
||||
|
||||
else:
|
||||
text_size = text_size or 22
|
||||
small_text_size = small_text_size or 16
|
||||
radius = 12
|
||||
|
||||
theme.roundrect_frames(
|
||||
def frames(
|
||||
less_rounded,
|
||||
frame)
|
||||
frame):
|
||||
|
||||
theme.roundrect_buttons(
|
||||
theme.clear_frames()
|
||||
|
||||
style.frame.background = Box(frame, less_rounded)
|
||||
|
||||
style.frame.xpadding = 6
|
||||
style.frame.ypadding = 6
|
||||
|
||||
setattr(theme, name + "_frames", frames)
|
||||
|
||||
|
||||
def buttons(text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text):
|
||||
|
||||
theme.clear_buttons()
|
||||
|
||||
style.button.background = Box(widget, less_rounded)
|
||||
style.button.hover_background = Box(widget_hover, less_rounded)
|
||||
style.button.insensitive_background = Box(disabled, less_rounded)
|
||||
|
||||
style.button_text.size = text_size
|
||||
style.button_text.color = widget_text
|
||||
style.button_text.selected_color = widget_selected
|
||||
style.button_text.insensitive_color = disabled_text
|
||||
|
||||
if less_rounded:
|
||||
style.button.xpadding = 6
|
||||
else:
|
||||
style.button.xpadding = 12
|
||||
|
||||
style.button.ypadding = 1
|
||||
style.button.xmargin = 1
|
||||
style.button.ymargin = 1
|
||||
|
||||
style.button_text.xalign = 0.5
|
||||
style.button_text.yalign = 0.5
|
||||
style.button_text.text_align = 0.5
|
||||
|
||||
setattr(theme, name + "_buttons", buttons)
|
||||
|
||||
def large_buttons(
|
||||
text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
@@ -333,55 +149,260 @@ init -1110 python hide:
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text)
|
||||
disabled_text):
|
||||
|
||||
theme.roundrect_large_buttons(
|
||||
small_text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text)
|
||||
theme.clear_large_buttons()
|
||||
|
||||
theme.roundrect_labels(
|
||||
text_size,
|
||||
label)
|
||||
|
||||
theme.roundrect_prompts(
|
||||
text_size,
|
||||
label)
|
||||
|
||||
theme.roundrect_bars(
|
||||
widget,
|
||||
widget_hover)
|
||||
|
||||
if mm_root is not None:
|
||||
style.mm_root.background = mm_root
|
||||
|
||||
if gm_root is not None:
|
||||
style.gm_root.background = gm_root
|
||||
|
||||
if window is not None:
|
||||
|
||||
if rounded_window:
|
||||
style.window.background = RoundRect(window, less_rounded)
|
||||
style.window.xpadding = 6
|
||||
style.window.xmargin = 6
|
||||
style.window.ypadding = 6
|
||||
style.window.ymargin = 6
|
||||
if less_rounded:
|
||||
style.large_button.xpadding = 6
|
||||
else:
|
||||
style.window.background = Solid(window)
|
||||
style.window.xpadding = 6
|
||||
style.window.xmargin = 0
|
||||
style.window.ypadding = 6
|
||||
style.window.ymargin = 0
|
||||
style.large_button.xpadding = 12
|
||||
|
||||
style.large_button.ypadding = 1
|
||||
style.large_button.xmargin = 1
|
||||
style.large_button.ymargin = 1
|
||||
|
||||
style.large_button.background = Box(widget, less_rounded)
|
||||
style.large_button.hover_background = Box(widget_hover, less_rounded)
|
||||
style.large_button.insensitive_background = Box(disabled, less_rounded)
|
||||
|
||||
style.large_button_text.size = text_size
|
||||
style.large_button_text.color = widget_text
|
||||
style.large_button_text.selected_color = widget_selected
|
||||
style.large_button_text.insensitive_color = disabled_text
|
||||
|
||||
style.large_button_text.xalign = 0
|
||||
style.large_button_text.yalign = 0
|
||||
|
||||
setattr(theme, name + "_large_buttons", large_buttons)
|
||||
|
||||
def labels(
|
||||
text_size,
|
||||
label):
|
||||
|
||||
theme.clear_labels()
|
||||
|
||||
style.label_text.size = text_size
|
||||
style.label_text.color = label
|
||||
|
||||
setattr(theme, name + "_labels", labels)
|
||||
|
||||
def prompts(
|
||||
text_size,
|
||||
label):
|
||||
|
||||
theme.clear_prompts()
|
||||
|
||||
style.prompt_text.size = text_size
|
||||
style.prompt_text.color = label
|
||||
|
||||
style.prompt.xalign = 0.5
|
||||
style.prompt_text.text_align = 0.5
|
||||
style.prompt_text.layout = "subtitle"
|
||||
|
||||
setattr(theme, name + "_prompts", prompts)
|
||||
|
||||
|
||||
def bars(
|
||||
widget,
|
||||
widget_hover):
|
||||
|
||||
theme.clear_bars()
|
||||
|
||||
def img(name, color, x, y):
|
||||
rv = theme.OneOrTwoColor(file_prefix + name + ".png", color)
|
||||
if x is not None:
|
||||
rv = Frame(rv, x, y, tile=True)
|
||||
return rv
|
||||
|
||||
# Bars.
|
||||
style.bar.ymaximum = 24
|
||||
style.bar.left_gutter = 6
|
||||
style.bar.right_gutter = 6
|
||||
style.bar.thumb_offset = 6
|
||||
|
||||
style.bar.left_bar = img("slider_full", widget, 12, 0)
|
||||
style.bar.right_bar = img("slider_empty", widget, 12, 0)
|
||||
style.bar.thumb = img("slider_thumb", widget, None, None)
|
||||
style.bar.hover_left_bar = img("slider_full", widget_hover, 12, 0)
|
||||
style.bar.hover_right_bar = img("slider_empty", widget_hover, 12, 0)
|
||||
style.bar.hover_thumb = img("slider_thumb", widget_hover, None, None)
|
||||
|
||||
style.vbar.xmaximum = 24
|
||||
style.vbar.top_gutter = 6
|
||||
style.vbar.bottom_gutter = 6
|
||||
style.vbar.thumb_offset = 6
|
||||
|
||||
style.vbar.bottom_bar = img("vslider_full", widget, 0, 12)
|
||||
style.vbar.top_bar = img("vslider_empty", widget, 0, 12)
|
||||
style.vbar.thumb = img("vslider_thumb", widget, None, None)
|
||||
style.vbar.hover_bottom_bar = img("vslider_full", widget_hover, 0, 12)
|
||||
style.vbar.hover_top_bar = img("vslider_empty", widget_hover, 0, 12)
|
||||
style.vbar.hover_thumb = img("vslider_thumb", widget_hover, None, None)
|
||||
|
||||
# Sliders.
|
||||
style.slider.ymaximum = 24
|
||||
style.slider.left_gutter = 6
|
||||
style.slider.right_gutter = 6
|
||||
style.slider.thumb_offset = 6
|
||||
|
||||
style.slider.left_bar = img("slider_full", widget, 12, 0)
|
||||
style.slider.right_bar = img("slider_empty", widget, 12, 0)
|
||||
style.slider.thumb = img("slider_thumb", widget, None, None)
|
||||
style.slider.hover_left_bar = img("slider_full", widget_hover, 12, 0)
|
||||
style.slider.hover_right_bar = img("slider_empty", widget_hover, 12, 0)
|
||||
style.slider.hover_thumb = img("slider_thumb", widget_hover, None, None)
|
||||
|
||||
style.vslider.xmaximum = 24
|
||||
style.vslider.top_gutter = 6
|
||||
style.vslider.bottom_gutter = 6
|
||||
style.vslider.thumb_offset = 6
|
||||
|
||||
style.vslider.bottom_bar = img("vslider_full", widget, 0, 12)
|
||||
style.vslider.top_bar = img("vslider_empty", widget, 0, 12)
|
||||
style.vslider.thumb = img("vslider_thumb", widget, None, None)
|
||||
style.vslider.hover_bottom_bar = img("vslider_full", widget_hover, 0, 12)
|
||||
style.vslider.hover_top_bar = img("vslider_empty", widget_hover, 0, 12)
|
||||
style.vslider.hover_thumb = img("vslider_thumb", widget_hover, None, None)
|
||||
|
||||
|
||||
if button_menu:
|
||||
layout.button_menu()
|
||||
# Scrollbars.
|
||||
style.scrollbar.left_gutter = 6
|
||||
style.scrollbar.right_gutter = 6
|
||||
style.scrollbar.thumb_offset = 6
|
||||
style.scrollbar.ymaximum = 12
|
||||
|
||||
style.scrollbar.left_bar = img("scrollbar", widget, 12, 0)
|
||||
style.scrollbar.right_bar = img("scrollbar", widget, 12, 0)
|
||||
style.scrollbar.thumb = img("scrollbar_thumb", widget, None, None)
|
||||
style.scrollbar.hover_left_bar = img("scrollbar", widget_hover, 12, 0)
|
||||
style.scrollbar.hover_right_bar = img("scrollbar", widget_hover, 12, 0)
|
||||
style.scrollbar.hover_thumb = img("scrollbar_thumb", widget_hover, None, None)
|
||||
|
||||
style.vscrollbar.top_gutter = 6
|
||||
style.vscrollbar.bottom_gutter = 6
|
||||
style.vscrollbar.thumb_offset = 6
|
||||
style.vscrollbar.xmaximum = 12
|
||||
|
||||
style.vscrollbar.left_bar = img("vscrollbar", widget, 0, 12)
|
||||
style.vscrollbar.right_bar = img("vscrollbar", widget, 0, 12)
|
||||
style.vscrollbar.thumb = img("vscrollbar_thumb", widget, None, None)
|
||||
style.vscrollbar.hover_left_bar = img("vscrollbar", widget_hover, 0, 12)
|
||||
style.vscrollbar.hover_right_bar = img("vscrollbar", widget_hover, 0, 12)
|
||||
style.vscrollbar.hover_thumb = img("vscrollbar_thumb", widget_hover, None, None)
|
||||
|
||||
setattr(theme, name + "_bars", bars)
|
||||
|
||||
def main(
|
||||
widget = (0, 60, 120, 255),
|
||||
widget_hover = (0, 80, 160, 255),
|
||||
widget_text = (200, 225, 255, 255),
|
||||
widget_selected = (255, 255, 200, 255),
|
||||
disabled = (64, 64, 64, 255),
|
||||
disabled_text = (200, 200, 200, 255),
|
||||
label = (255, 255, 255, 255),
|
||||
frame = (100, 150, 200, 255),
|
||||
|
||||
text_size=None,
|
||||
small_text_size=None,
|
||||
less_rounded = False,
|
||||
|
||||
# Compat for the old roundrect theme.
|
||||
window = None,
|
||||
button_menu = None,
|
||||
rounded_window = True,
|
||||
outline_bars = False,
|
||||
mm_root = None,
|
||||
gm_root = None):
|
||||
|
||||
if button_menu is None:
|
||||
if (config.script_version is not None) and (config.script_version < (6, 9, 0)):
|
||||
button_menu = True
|
||||
else:
|
||||
button_menu = False
|
||||
|
||||
layout.defaults()
|
||||
|
||||
if config.screen_width <= 640:
|
||||
text_size = text_size or 18
|
||||
small_text_size = small_text_size or 12
|
||||
less_rounded = True
|
||||
|
||||
else:
|
||||
text_size = text_size or 22
|
||||
small_text_size = small_text_size or 16
|
||||
radius = 12
|
||||
|
||||
frames(
|
||||
less_rounded,
|
||||
frame)
|
||||
|
||||
buttons(
|
||||
text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text)
|
||||
|
||||
large_buttons(
|
||||
small_text_size,
|
||||
less_rounded,
|
||||
widget,
|
||||
widget_hover,
|
||||
widget_text,
|
||||
widget_selected,
|
||||
disabled,
|
||||
disabled_text)
|
||||
|
||||
labels(
|
||||
text_size,
|
||||
label)
|
||||
|
||||
prompts(
|
||||
text_size,
|
||||
label)
|
||||
|
||||
bars(
|
||||
widget,
|
||||
widget_hover)
|
||||
|
||||
if mm_root is not None:
|
||||
style.mm_root.background = mm_root
|
||||
|
||||
if gm_root is not None:
|
||||
style.gm_root.background = gm_root
|
||||
|
||||
if window is not None:
|
||||
|
||||
if rounded_window:
|
||||
style.window.background = RoundRect(window, less_rounded)
|
||||
style.window.xpadding = 6
|
||||
style.window.xmargin = 6
|
||||
style.window.ypadding = 6
|
||||
style.window.ymargin = 6
|
||||
else:
|
||||
style.window.background = Solid(window)
|
||||
style.window.xpadding = 6
|
||||
style.window.xmargin = 0
|
||||
style.window.ypadding = 6
|
||||
style.window.ymargin = 0
|
||||
|
||||
|
||||
if button_menu:
|
||||
layout.button_menu()
|
||||
|
||||
setattr(theme, name, main)
|
||||
|
||||
roundrect_based_theme("roundrect", "_roundrect/rr", RoundRect)
|
||||
roundrect_based_theme("bordered", "_theme_bordered/br")
|
||||
roundrect_based_theme("diamond", "_theme_diamond/d")
|
||||
roundrect_based_theme("tv", "_theme_tv/t")
|
||||
roundrect_based_theme("glow", "_theme_glow/g", None, "_outline.png")
|
||||
|
||||
|
||||
@theme
|
||||
def ancient():
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ init -1120:
|
||||
|
||||
# Call this to replay the last bit of voice.
|
||||
def voice_replay():
|
||||
renpy.sound.play(_last_voice_play, channel=2)
|
||||
renpy.sound.play(_last_voice_play, channel="voice")
|
||||
|
||||
# Returns true if we can replay the voice.
|
||||
def voice_can_replay():
|
||||
@@ -70,10 +70,10 @@ init -1120:
|
||||
return
|
||||
|
||||
if _voice.play and not config.skipping:
|
||||
renpy.sound.play(_voice.play, channel=2)
|
||||
renpy.sound.play(_voice.play, channel="voice")
|
||||
store._last_voice_play = _voice.play
|
||||
elif not _voice.sustain:
|
||||
renpy.sound.stop(channel=2)
|
||||
renpy.sound.stop(channel="voice")
|
||||
store._last_voice_play = _voice.play
|
||||
|
||||
_voice.play = None
|
||||
@@ -83,7 +83,7 @@ init -1120:
|
||||
config.say_sustain_callbacks.append(voice_sustain)
|
||||
|
||||
def voice_afm_callback():
|
||||
return not renpy.sound.is_playing(channel=2)
|
||||
return not renpy.sound.is_playing(channel="voice")
|
||||
|
||||
config.afm_callback = voice_afm_callback
|
||||
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
# This file contains code that helps support the development of Ren'Py
|
||||
# games.
|
||||
|
||||
# This file contains the developer screen, which contains tools that might
|
||||
# be of interest to people making Ren'Py games.
|
||||
screen _developer:
|
||||
window style "gm_root"
|
||||
|
||||
frame:
|
||||
style_group "_developer"
|
||||
|
||||
align (.025, .05)
|
||||
|
||||
has vbox:
|
||||
first_spacing 10
|
||||
|
||||
label "Developer Menu"
|
||||
|
||||
textbutton _(u"Return") action Return()
|
||||
textbutton _(u"Reload Game (Shift + R)") action ui.callsinnewcontext("_save_reload_game")
|
||||
textbutton _(u"Variable Viewer") action Jump("_debugger_screen")
|
||||
textbutton _(u"Theme Test") action Jump("_theme_test")
|
||||
textbutton _(u"Style Hierarchy") action Jump("_style_hierarchy")
|
||||
textbutton _(u"Image Location Picker") action Jump("_image_location_picker")
|
||||
textbutton _(u"Filename List") action Jump("_filename_list")
|
||||
|
||||
init python hide:
|
||||
style._developer_button = Style(style.button)
|
||||
style._developer_button.size_group = "_developer"
|
||||
|
||||
label _developer_screen:
|
||||
|
||||
python hide:
|
||||
|
||||
ui.window(style=style.gm_root)
|
||||
ui.null()
|
||||
|
||||
ui.frame(xpos=10, ypos=10, style=style.menu_frame)
|
||||
ui.vbox(box_first_spacing=10)
|
||||
layout.label(u"Developer Menu", None)
|
||||
|
||||
sg = "developer_menu"
|
||||
|
||||
layout.button(u"Return", None, clicked=ui.returns(True), size_group=sg)
|
||||
layout.button(u"Reload Game (Shift+R)", None, clicked=ui.callsinnewcontext("_save_reload_game"), size_group=sg)
|
||||
layout.button(u"Variable Viewer", None, clicked=ui.jumps("_debugger_screen"), size_group=sg)
|
||||
layout.button(u"Theme Test", None, clicked=ui.jumps("_theme_test"), size_group=sg)
|
||||
layout.button(u"Style Hierarchy", None, clicked=ui.jumps("_style_hierarchy"), size_group=sg)
|
||||
layout.button(u"FPS Meter", None, clicked=ui.jumps("_fps_meter"), size_group=sg)
|
||||
layout.button(u"Image Location Picker", None, clicked=ui.jumps("_image_location_picker"), size_group=sg)
|
||||
|
||||
ui.close()
|
||||
ui.interact()
|
||||
call screen _developer
|
||||
|
||||
return
|
||||
|
||||
@@ -93,7 +97,7 @@ label _theme_test:
|
||||
return ""
|
||||
|
||||
toggle_var = True
|
||||
adj = ui.adjustment(100, 25, page=25)
|
||||
adj = ui.adjustment(100, 25, page=25, adjustable=True)
|
||||
|
||||
while True:
|
||||
|
||||
@@ -370,8 +374,8 @@ init python:
|
||||
sr = renpy.render(Solid("#0ff4"), w, h, st, at)
|
||||
rv.blit(sr, (minx, miny))
|
||||
|
||||
text.append("Imagemap rectangle: %r" % ((minx, miny, maxx, maxy),))
|
||||
text.append("Cropping rectangle: %r" % ((minx, miny, w, h),))
|
||||
# text.append("Imagemap rectangle: %r" % ((minx, miny, maxx, maxy),))
|
||||
text.append("Rectangle: %r" % ((minx, miny, w, h),))
|
||||
|
||||
if self.mouse:
|
||||
mx, my = self.mouse
|
||||
@@ -466,4 +470,32 @@ label _image_location_picker:
|
||||
# ...
|
||||
|
||||
renpy.jump("_image_location_picker")
|
||||
|
||||
label _filename_list:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
f = file("files.txt", "w")
|
||||
|
||||
for dirname, dirs, files in os.walk(config.gamedir):
|
||||
|
||||
dirs.sort()
|
||||
files.sort()
|
||||
|
||||
for fn in files:
|
||||
fn = os.path.join(dirname, fn)
|
||||
fn = fn[len(config.gamedir) + 1:]
|
||||
print >>f, fn
|
||||
print fn
|
||||
|
||||
f.close()
|
||||
|
||||
renpy.launch_editor(["files.txt"], transient=1)
|
||||
|
||||
|
||||
jump _developer_screen
|
||||
|
||||
|
||||
init python:
|
||||
config.underlay.append(im.Tile("_transparent_tile.png"))
|
||||
|
||||
|
||||
@@ -188,8 +188,11 @@ init python:
|
||||
else:
|
||||
base += 1
|
||||
|
||||
return base + int((int(filename) - 1) / per_page)
|
||||
|
||||
try:
|
||||
return base + int((int(filename) - 1) / per_page)
|
||||
except:
|
||||
return base
|
||||
|
||||
# Processes a screenshot.
|
||||
def _file_picker_process_screenshot(s):
|
||||
return s
|
||||
|
||||
@@ -133,7 +133,7 @@ init python:
|
||||
a channel.
|
||||
"""
|
||||
|
||||
def __init__(self, name, mixer, enable='True', sound='None', channel=0):
|
||||
def __init__(self, name, mixer, enable='True', sound='None', channel="sound"):
|
||||
"""
|
||||
@param name: The name of this preference, as shown to the user.
|
||||
|
||||
@@ -360,15 +360,18 @@ init python hide:
|
||||
_VolumePreference(u"Music Volume",
|
||||
'music',
|
||||
'config.has_music')
|
||||
|
||||
_VolumePreference(u"Sound Volume",
|
||||
'sfx',
|
||||
'config.has_sound',
|
||||
'config.sample_sound')
|
||||
'config.sample_sound',
|
||||
'sound')
|
||||
|
||||
_VolumePreference(u'Voice Volume',
|
||||
'voice',
|
||||
'config.has_voice',
|
||||
'config.sample_voice',
|
||||
2)
|
||||
'voice')
|
||||
|
||||
_JumpPreference(u'Joystick...',
|
||||
'joystick_preferences_screen',
|
||||
|
||||
@@ -151,8 +151,11 @@ init python:
|
||||
else:
|
||||
base += 1
|
||||
|
||||
return base + int((int(filename) - 1) / per_page)
|
||||
|
||||
try:
|
||||
return base + int((int(filename) - 1) / per_page)
|
||||
except:
|
||||
return base
|
||||
|
||||
# Processes a screenshot.
|
||||
def _file_picker_process_screenshot(s):
|
||||
return s
|
||||
|
||||
@@ -77,12 +77,12 @@ init python:
|
||||
ime.button("Joystick", ui.jumps("joystick_preferences_screen"), False)
|
||||
|
||||
def play_sound():
|
||||
renpy.sound.play(config.sample_sound)
|
||||
renpy.music.play(config.sample_sound, channel="sound")
|
||||
|
||||
ime.button("Sound Test", play_sound, False)
|
||||
|
||||
def play_voice():
|
||||
renpy.sound.play(config.sample_sound, channel=2)
|
||||
renpy.music.play(config.sample_sound, channel="voice")
|
||||
|
||||
ime.button("Voice Test", play_voice, False)
|
||||
|
||||
@@ -124,11 +124,14 @@ init python:
|
||||
_preferences.set_volume('sfx', v / 128.0)
|
||||
def set_voice(v):
|
||||
_preferences.set_volume('voice', v / 128.0)
|
||||
|
||||
ime.bar("Music Volume", 128, int(_preferences.get_volume('music') * 128), set_music)
|
||||
ime.bar("Sound Volume", 128, int(_preferences.get_volume('sfx') * 128), set_sound)
|
||||
ime.bar("Voice Volume", 128, int(_preferences.get_volume('voice') * 128), set_voice)
|
||||
|
||||
if config.has_music:
|
||||
ime.bar("Music Volume", 128, int(_preferences.get_volume('music') * 128), set_music)
|
||||
if config.has_sound:
|
||||
ime.bar("Sound Volume", 128, int(_preferences.get_volume('sfx') * 128), set_sound)
|
||||
if config.has_voice:
|
||||
ime.bar("Voice Volume", 128, int(_preferences.get_volume('voice') * 128), set_voice)
|
||||
|
||||
ime.close()
|
||||
ui.interact(mouse="gamemenu")
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python:
|
||||
|
||||
layout.provides('joystick_preferences')
|
||||
|
||||
label joystick_preferences_screen:
|
||||
|
||||
$ renpy.show_screen('joystick_preferences')
|
||||
$ ui.interact()
|
||||
|
||||
jump _noisy_return
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python:
|
||||
|
||||
layout.provides('load_save')
|
||||
|
||||
label load_screen:
|
||||
|
||||
$ renpy.show_screen('load')
|
||||
$ ui.interact()
|
||||
jump _noisy_return
|
||||
|
||||
label save_screen:
|
||||
|
||||
$ renpy.show_screen('save')
|
||||
$ ui.interact()
|
||||
jump _noisy_return
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python:
|
||||
|
||||
layout.provides('main_menu')
|
||||
|
||||
label main_menu_screen:
|
||||
|
||||
$ renpy.show_screen("main_menu")
|
||||
$ ui.interact()
|
||||
|
||||
return
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python:
|
||||
|
||||
layout.provides('preferences')
|
||||
|
||||
label preferences_screen:
|
||||
|
||||
$ renpy.show_screen('preferences')
|
||||
$ ui.interact()
|
||||
|
||||
jump _noisy_return
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
|
||||
# See LICENSE.txt for license details.
|
||||
|
||||
init python hide:
|
||||
|
||||
layout.provides('yesno_prompt')
|
||||
|
||||
def yesno_prompt(screen, message):
|
||||
return renpy.call_screen('yesno_prompt', message=message, yes_action=Return(True), no_action=Return(False))
|
||||
|
||||
layout.yesno_prompt = yesno_prompt
|
||||
|
After Width: | Height: | Size: 266 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 489 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 236 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 356 B |
|
After Width: | Height: | Size: 289 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 255 B |
|
After Width: | Height: | Size: 359 B |
|
After Width: | Height: | Size: 405 B |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 763 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 524 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 781 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 545 B |
|
After Width: | Height: | Size: 611 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 816 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 529 B |
|
After Width: | Height: | Size: 315 B |
|
After Width: | Height: | Size: 246 B |
|
After Width: | Height: | Size: 184 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 384 B |
|
After Width: | Height: | Size: 206 B |
|
After Width: | Height: | Size: 266 B |
|
After Width: | Height: | Size: 204 B |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 412 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 436 B |
@@ -1 +0,0 @@
|
||||
dist/console.exe
|
||||
@@ -9,6 +9,9 @@ import time
|
||||
import zlib
|
||||
import compileall
|
||||
import shutil
|
||||
import subprocess
|
||||
import makeupdate
|
||||
import time
|
||||
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
|
||||
@@ -20,7 +23,7 @@ def data(fn):
|
||||
if fn.startswith("renpy.app"):
|
||||
return rv
|
||||
|
||||
if fn.endswith(".rpy") or fn.endswith(".py") or fn.endswith(".txt"):
|
||||
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")
|
||||
|
||||
@@ -87,7 +90,11 @@ def tree(root):
|
||||
|
||||
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
|
||||
@@ -113,41 +120,44 @@ def main():
|
||||
|
||||
prefix = sys.argv[1]
|
||||
|
||||
# Update the update-version.txt file.
|
||||
p = subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE)
|
||||
revno = p.stdout.read().strip() + "-" + str(time.time())
|
||||
p.wait()
|
||||
|
||||
f = file("lib/update-version.txt", "w")
|
||||
f.write(revno + " base\n")
|
||||
f.close()
|
||||
|
||||
# Compile all the python files.
|
||||
compileall.compile_dir("renpy/", ddir=prefix + "/renpy/", force=1)
|
||||
|
||||
os.environ['RENPY_PATH_ELIDE'] = '/home/tom/ab/renpy:' + prefix
|
||||
|
||||
# Chmod the mac app.
|
||||
os.chmod("./renpy.app/Contents/MacOS/Ren'Py Launcher", 0755)
|
||||
|
||||
# Chmod down renpy.py, for now.
|
||||
os.chmod("renpy.py", 0644)
|
||||
|
||||
# Compile the various games
|
||||
for i in [ 'tutorial/game', 'launcher', 'template/game', 'the_question/game' ]:
|
||||
os.system("./renpy.sh --compile --game " + i)
|
||||
|
||||
|
||||
files = [ ]
|
||||
more_files = [ ]
|
||||
|
||||
files.append("CHANGELOG.txt")
|
||||
files.append("LICENSE.txt")
|
||||
files.extend(tree("common"))
|
||||
more_files.append("console.exe")
|
||||
files.extend(tree("launcher"))
|
||||
files.extend(tree("tutorial"))
|
||||
# files.extend(tree("dse"))
|
||||
files.extend(tree("the_question"))
|
||||
|
||||
# editor = tree("editor")
|
||||
# editor.remove("editor/scite.exe")
|
||||
# files.append("editor/scite.exe")
|
||||
# more_files.extend(editor)
|
||||
|
||||
more_files.extend(tree("jedit"))
|
||||
|
||||
# files.extend(tree("extras"))
|
||||
more_files.extend(tree("lib"))
|
||||
more_files.extend(tree("lib/linux-x86"))
|
||||
|
||||
|
||||
module_files = [
|
||||
"lib/pysdlsound/linmixer.py",
|
||||
"lib/pysdlsound/__init__.py",
|
||||
@@ -175,34 +185,30 @@ def main():
|
||||
"_renpybidi.c",
|
||||
"renpybidicore.c",
|
||||
"_renpybidi.pyx",
|
||||
"_renpy_pysdlgl.c",
|
||||
"_renpy_pysdlgl.pyx",
|
||||
"_renpy_tegl.c",
|
||||
"maketegl.py",
|
||||
"maketegl.txt",
|
||||
]
|
||||
|
||||
for i in module_files:
|
||||
files.append('module/' + i)
|
||||
|
||||
more_files.append('python25.dll')
|
||||
more_files.append('msvcr71.dll')
|
||||
files.extend(tree('renpy'))
|
||||
more_files.extend(tree('renpy.app'))
|
||||
more_files.append('renpy.code')
|
||||
more_files.append('renpy.exe')
|
||||
files.append('renpy.py')
|
||||
|
||||
more_files.append('python26.dll')
|
||||
more_files.append('msvcr90.dll')
|
||||
more_files.append('Microsoft.VC90.CRT.manifest')
|
||||
more_files.extend(tree('renpy.app'))
|
||||
more_files.append('renpy.exe')
|
||||
more_files.append("console.exe")
|
||||
more_files.append('renpy.sh')
|
||||
|
||||
files.extend(tree('template'))
|
||||
# files.extend(tree('tools'))
|
||||
files.extend(tree('doc'))
|
||||
|
||||
files.append('doc/index.html')
|
||||
files.append('doc/common.css')
|
||||
files.append('doc/docs.css')
|
||||
files.append('doc/monobook.css')
|
||||
files.append('doc/monobook2.css')
|
||||
files.append('doc/shared.css')
|
||||
files.extend(tree('doc/reference'))
|
||||
files.extend(tree('doc/tutorials'))
|
||||
files.extend(tree('doc/images'))
|
||||
|
||||
files.sort()
|
||||
more_files.sort()
|
||||
|
||||
@@ -211,7 +217,9 @@ def main():
|
||||
zipup("dists/" + prefix + "-sdk.zip", prefix, files + more_files)
|
||||
print "----"
|
||||
tarup("dists/" + prefix + "-sdk.tar.bz2", prefix, files + more_files)
|
||||
print "----"
|
||||
tarup("dists/" + prefix + "-source.tar.bz2", prefix, files)
|
||||
print "----"
|
||||
|
||||
# Make the 7zip.
|
||||
os.chdir("dists")
|
||||
@@ -224,13 +232,23 @@ def main():
|
||||
|
||||
os.system("7z a " + prefix + "-sdk.7z " + prefix)
|
||||
os.system("cat ../7z.sfx " + prefix + "-sdk.7z > " + prefix + "-sdk.7z.exe""")
|
||||
shutil.rmtree(prefix)
|
||||
os.unlink(prefix + "-sdk.7z")
|
||||
|
||||
|
||||
os.chdir("..")
|
||||
|
||||
if os.path.exists("updates/prerelease"):
|
||||
shutil.rmtree("updates/prerelease")
|
||||
|
||||
os.rename("dists/" + prefix, "updates/prerelease")
|
||||
os.unlink("updates/prerelease/lib/update-version.txt")
|
||||
|
||||
makeupdate.make_update("updates/prerelease", revno)
|
||||
|
||||
os.chmod("renpy.py", 0755)
|
||||
|
||||
print
|
||||
print "Did you remember to rebuild the exe after the last change?"
|
||||
print "Did you run me with renpython -OO?"
|
||||
print "Was ming using the right crt?"
|
||||
print "Did you update renpy.py and launcher/script_version.rpy?"
|
||||
print "Did you run with a RENPY_SCALE_FACTOR?"
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#bodyContent {
|
||||
font-size: medium;
|
||||
background: #fff;
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.editsection {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#bodyContent a.external {
|
||||
background: none;
|
||||
padding-right: 0px;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
wget http://www.renpy.org/w/skins/common/shared.css -O shared.css
|
||||
wget http://www.renpy.org/w/skins/monobook/main.css -O monobook.css
|
||||
wget 'http://www.renpy.org/w/index.php?title=MediaWiki:Common.css&usemsgcache=yes&action=raw&ctype=text/css&smaxage=18000' -O common.css
|
||||
wget 'http://www.renpy.org/w/index.php?title=MediaWiki:Monobook.css&usemsgcache=yes&action=raw&ctype=text/css&smaxage=18000' -O monobook2.css
|
||||
|
||||
rm -Rf www.renpy.org
|
||||
wget -e robots=off -m -I /wiki/renpy/doc/reference/,/wiki/renpy/doc/tutorials/,/w/images -m http://www.renpy.org/wiki/renpy/doc/index
|
||||
|
||||
rm -Rf images
|
||||
mkdir -p images
|
||||
cp `find www.renpy.org -name \*.png -type f` images
|
||||
|
||||
No jpgs yet.
|
||||
cp `find www.renpy.org -name \*.jpg -type f` images
|
||||
|
||||
rm -Rf reference tutorials
|
||||
python2.5 process.py
|
||||
@@ -1,164 +0,0 @@
|
||||
#!/usr/bin/python2.4
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
# import xml.etree.ElementTree as elementtree
|
||||
# sys.modules['elementtree'] = elementtree
|
||||
|
||||
# from elementtree.ElementTree import ElementTree, Element, SubElement, tostring, fromstring
|
||||
# from elementtidy import TidyHTMLTreeBuilder
|
||||
|
||||
from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring, fromstring
|
||||
from elementtidy import TidyHTMLTreeBuilder
|
||||
|
||||
# Removes everyhing we don't care about from the wikipages.
|
||||
def remove_crap(n):
|
||||
|
||||
classes = n.attrib.get("class", "").split()
|
||||
|
||||
if "editsection" in classes:
|
||||
return None
|
||||
if "printfooter" in classes:
|
||||
return None
|
||||
if "magnify" in classes:
|
||||
return None
|
||||
|
||||
|
||||
id = n.attrib.get("id", None)
|
||||
|
||||
if "catlinks" == id:
|
||||
return None
|
||||
|
||||
newchildren = [ ]
|
||||
for i in n:
|
||||
i = remove_crap(i)
|
||||
if i is not None:
|
||||
newchildren.append(i)
|
||||
|
||||
n[:] = newchildren
|
||||
|
||||
if n.tag == "a" and not n.text:
|
||||
n.text = "SPACE REMOVE ME PLEASE"
|
||||
|
||||
return n
|
||||
|
||||
def process(src, dst, nav):
|
||||
|
||||
if nav:
|
||||
nav = fromstring(nav)
|
||||
|
||||
base = "../" * (len(dst.split('/')) - 1)
|
||||
|
||||
if dst.startswith("./"):
|
||||
base = ""
|
||||
|
||||
# tree = TidyHTMLTreeBuilder.parse(src)
|
||||
|
||||
|
||||
code = file(src).read()
|
||||
code = code.replace(" ", u"\u00a0".encode("utf-8"))
|
||||
tree = fromstring(code)
|
||||
|
||||
XHTML = "{http://www.w3.org/1999/xhtml}"
|
||||
|
||||
for elem in tree.getiterator():
|
||||
if elem.tag.startswith(XHTML):
|
||||
elem.tag = elem.tag[len(XHTML):]
|
||||
|
||||
by_id = dict()
|
||||
|
||||
for n in tree.getiterator():
|
||||
if "id" in n.attrib:
|
||||
by_id[n.attrib["id"]] = n
|
||||
|
||||
html = Element("html")
|
||||
head = SubElement(html, "head")
|
||||
title = SubElement(head, "title")
|
||||
title.text = tree.findtext(".//title")
|
||||
head = SubElement(head, "link", rel="stylesheet", href=base + "shared.css")
|
||||
head = SubElement(head, "link", rel="stylesheet", href=base + "monobook.css")
|
||||
head = SubElement(head, "link", rel="stylesheet", href=base + "common.css")
|
||||
head = SubElement(head, "link", rel="stylesheet", href=base + "monobook2.css")
|
||||
head = SubElement(head, "link", rel="stylesheet", href=base + "docs.css")
|
||||
|
||||
body = SubElement(html, "body")
|
||||
# gw = SubElement(body, "div", id="globalWrapper")
|
||||
# cc = SubElement(gw, "div", id="column-content")
|
||||
# content = SubElement(cc, "div", id="content")
|
||||
|
||||
bc = by_id['bodyContent']
|
||||
body.append(bc)
|
||||
|
||||
bc.remove(by_id['siteSub'])
|
||||
bc.remove(by_id['contentSub'])
|
||||
bc.remove(by_id['jump-to-nav'])
|
||||
|
||||
for n in bc.findall(".//a"):
|
||||
if "href" in n.attrib:
|
||||
href = n.attrib['href']
|
||||
|
||||
if href.startswith("/wiki/Image:") or href.startswith("/w/"):
|
||||
n.attrib['href'] = 'http://www.renpy.org' + href
|
||||
continue
|
||||
|
||||
if href.startswith("#"):
|
||||
continue
|
||||
|
||||
if href.startswith("http:"):
|
||||
continue
|
||||
|
||||
href = href.replace("/wiki/renpy/doc/", base)
|
||||
|
||||
if "#" in href:
|
||||
href.replace("#", ".html#")
|
||||
else:
|
||||
href += ".html"
|
||||
|
||||
n.attrib['href'] = href
|
||||
|
||||
for n in bc.findall(".//img"):
|
||||
src = n.attrib["src"]
|
||||
src = base + "images" + src[src.rfind("/"):]
|
||||
n.attrib["src"] = src
|
||||
|
||||
|
||||
if nav:
|
||||
hr = Element("hr")
|
||||
bc[:] = [ nav ] + list(bc) + [ hr, nav ]
|
||||
|
||||
html = remove_crap(html)
|
||||
|
||||
doc = tostring(html)
|
||||
doc = doc.replace("SPACE REMOVE ME PLEASE", "")
|
||||
file(dst, "w").write(doc)
|
||||
|
||||
|
||||
def process_dir(src, dst, nav):
|
||||
try:
|
||||
os.makedirs(dst)
|
||||
except:
|
||||
pass
|
||||
|
||||
for fn in os.listdir(src):
|
||||
if os.path.isdir(src + "/" + fn):
|
||||
continue
|
||||
|
||||
if fn.endswith(".1"):
|
||||
continue
|
||||
|
||||
print src + "/" + fn
|
||||
|
||||
process(src + "/" + fn, dst + "/" + fn + ".html", nav)
|
||||
|
||||
nav = '<p class="docnav"><a href="../index.html">documentation index</a></p>'
|
||||
process_dir("www.renpy.org/wiki/renpy/doc/tutorials", "tutorials", nav)
|
||||
|
||||
nav = '<p class="docnav"><a href="../index.html">documentation index</a> ◦ <a href="Reference_Manual.html">reference manual</a> ◦ <a href="Function_Index.html">function index</a></p>'
|
||||
process_dir("www.renpy.org/wiki/renpy/doc/reference", "reference", nav)
|
||||
|
||||
nav = '<p class="docnav"><a href="../../index.html">documentation index</a> ◦ <a href="../Reference_Manual.html">reference manual</a> ◦ <a href="../Function_Index.html">function index</a></p>'
|
||||
process_dir("www.renpy.org/wiki/renpy/doc/reference/functions", "reference/functions", nav)
|
||||
|
||||
nav = ''
|
||||
process_dir("www.renpy.org/wiki/renpy/doc/", ".", nav)
|
||||
@@ -5,40 +5,7 @@
|
||||
import struct
|
||||
import sys
|
||||
import array
|
||||
|
||||
# The starting point of the resource segment in the file.
|
||||
RESOURCE_BASE=0x3600
|
||||
|
||||
# The virtual memory location the resource segment is loaded
|
||||
# to.
|
||||
RESOURCE_VIRTUAL=0x6000
|
||||
|
||||
# The offset of the field that tells us with the alignment need be.
|
||||
ALIGNMENT_FIELD = 0x130
|
||||
|
||||
# The start of the .rsrc segment header.
|
||||
RSRC_HEADER = 0x268
|
||||
|
||||
# Locations in the file where we need to patch in the resource
|
||||
# segment length.
|
||||
RESOURCE_LENGTH_PATCHES = [ 0x0184, RSRC_HEADER + 0x8 ]
|
||||
|
||||
# Locations in the file where we need to patch in the padded
|
||||
# resource segment length.
|
||||
RESOURCE_PADDED_PATCHES = [ RSRC_HEADER + 0x10 ]
|
||||
|
||||
# Locations in the file where we need to patch in the change in the
|
||||
# size of the resource segement (and hence the change in the file's
|
||||
# total size.)
|
||||
SIZE_DELTA_PATCHES = [ 0x148 ]
|
||||
|
||||
# A location in the file that will be checked to be sure it matches
|
||||
# RESOURCE_BASE.
|
||||
CHECK_ADDRESS = RSRC_HEADER + 0x14
|
||||
|
||||
# A location in the file that will be checked to make sure it matches
|
||||
# RESOURCE_VIRTUAL
|
||||
CHECK_ADDRESS2 = RSRC_HEADER + 0xc
|
||||
import pefile
|
||||
|
||||
# This class performs various operations on memory-loaded binary files,
|
||||
# including modifications.
|
||||
@@ -89,8 +56,7 @@ class BinFile(object):
|
||||
def substring(self, start, len):
|
||||
return self.a[start:start+len].tostring()
|
||||
|
||||
def __init__(self, fn):
|
||||
data = open(fn, "rb").read()
|
||||
def __init__(self, data):
|
||||
self.a = array.array('B')
|
||||
self.a.fromstring(data)
|
||||
|
||||
@@ -98,50 +64,53 @@ class BinFile(object):
|
||||
# These functions parse data out of the file. In these functions, offset is
|
||||
# relative to the start of the file.
|
||||
|
||||
# The virtual address of the resource segment.
|
||||
resource_virtual = 0
|
||||
|
||||
# This parses a data block out of the resources.
|
||||
def parse_data(offset):
|
||||
pe.seek(RESOURCE_BASE + offset)
|
||||
data_offset = pe.u32()
|
||||
data_len = pe.u32()
|
||||
code_page = pe.u32()
|
||||
pe.u32()
|
||||
def parse_data(bf, offset):
|
||||
bf.seek(offset)
|
||||
data_offset = bf.u32()
|
||||
data_len = bf.u32()
|
||||
code_page = bf.u32()
|
||||
bf.u32()
|
||||
|
||||
l = [ ]
|
||||
|
||||
pe.seek(data_offset + RESOURCE_BASE - RESOURCE_VIRTUAL)
|
||||
bf.seek(data_offset - resource_virtual)
|
||||
for i in range(data_len):
|
||||
l.append(chr(pe.u8()))
|
||||
l.append(chr(bf.u8()))
|
||||
|
||||
return (code_page, "".join(l))
|
||||
|
||||
# This parses a resource directory.
|
||||
def parse_directory(offset):
|
||||
def parse_directory(bf, offset):
|
||||
|
||||
pe.seek(RESOURCE_BASE + offset)
|
||||
char = pe.u32()
|
||||
timedate = pe.u32()
|
||||
major = pe.u16()
|
||||
minor = pe.u16()
|
||||
n_named = pe.u16()
|
||||
n_id = pe.u16()
|
||||
bf.seek(offset)
|
||||
char = bf.u32()
|
||||
timedate = bf.u32()
|
||||
major = bf.u16()
|
||||
minor = bf.u16()
|
||||
n_named = bf.u16()
|
||||
n_id = bf.u16()
|
||||
|
||||
entries = [ ]
|
||||
|
||||
for i in range(n_named + n_id):
|
||||
entries.append((pe.u32(), pe.u32()))
|
||||
entries.append((bf.u32(), bf.u32()))
|
||||
|
||||
rv = { }
|
||||
|
||||
for name, value in entries:
|
||||
|
||||
if name & 0x80000000:
|
||||
pe.seek((name & 0x7fffffff) + RESOURCE_BASE)
|
||||
name = pe.name()
|
||||
bf.seek((name & 0x7fffffff))
|
||||
name = bf.name()
|
||||
|
||||
if value & 0x80000000:
|
||||
value = parse_directory(value & 0x7fffffff)
|
||||
value = parse_directory(bf, value & 0x7fffffff)
|
||||
else:
|
||||
value = parse_data(value)
|
||||
value = parse_data(bf, value)
|
||||
|
||||
rv[name] = value
|
||||
|
||||
@@ -182,8 +151,6 @@ 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)
|
||||
@@ -204,7 +171,7 @@ class Packer(object):
|
||||
|
||||
daddr = len(self.data) + self.data_offset
|
||||
|
||||
self.entries += struct.pack("<IIII", daddr + RESOURCE_VIRTUAL, len(data), codepage, 0)
|
||||
self.entries += struct.pack("<IIII", daddr + resource_virtual, len(data), codepage, 0)
|
||||
self.data += data
|
||||
|
||||
# if len(self.data) % 1 == 1:
|
||||
@@ -212,9 +179,6 @@ class Packer(object):
|
||||
|
||||
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))
|
||||
@@ -245,7 +209,7 @@ class Packer(object):
|
||||
# This loads in an icon file, and returns a dictionary that is suitable for
|
||||
# use in the resources of an exe file.
|
||||
def load_icon(fn):
|
||||
f = BinFile(fn)
|
||||
f = BinFile(file(fn, "rb").read())
|
||||
|
||||
f.seek(0)
|
||||
f.u16()
|
||||
@@ -289,51 +253,73 @@ def load_icon(fn):
|
||||
# This is the main function that should be called externally, that copies over
|
||||
# the icons.
|
||||
def change_icons(oldexe, icofn):
|
||||
global pe
|
||||
pe = BinFile(oldexe)
|
||||
global resource_virtual
|
||||
|
||||
# Check that RESOURCE_BASE and RESOURCE_VIRTUAL are still valid.
|
||||
pe.seek(CHECK_ADDRESS)
|
||||
if pe.u32() != RESOURCE_BASE:
|
||||
raise Exception("RESOURCE_BASE is no longer correct. Please check all relocations.")
|
||||
pe = pefile.PE(oldexe)
|
||||
|
||||
pe.seek(CHECK_ADDRESS2)
|
||||
if pe.u32() != RESOURCE_VIRTUAL:
|
||||
raise Exception("RESOURCE_VIRTUAL is no longer correct. Please check all relocations.")
|
||||
for s in pe.sections:
|
||||
if s.Name == ".rsrc\0\0\0":
|
||||
rsrc_section = s
|
||||
break
|
||||
else:
|
||||
raise Exception("Couldn't find resource section.")
|
||||
|
||||
resources = parse_directory(0)
|
||||
# show_resources(resources, "")
|
||||
base = rsrc_section.PointerToRawData
|
||||
resource_virtual = rsrc_section.VirtualAddress
|
||||
|
||||
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, "")
|
||||
# show_resources(resources, "")
|
||||
|
||||
rsrc = Packer().pack(resources)
|
||||
rsrc_len = len(rsrc)
|
||||
|
||||
pe.seek(ALIGNMENT_FIELD)
|
||||
alignment = pe.u32()
|
||||
|
||||
alignment = pe.OPTIONAL_HEADER.SectionAlignment
|
||||
|
||||
# print "Alignment is", alignment
|
||||
|
||||
if len(rsrc) % alignment:
|
||||
pad = alignment - (len(rsrc) % alignment)
|
||||
padding = "RENPYVNE" * (pad / 8 + 1)
|
||||
padding = padding[:pad]
|
||||
rsrc += padding
|
||||
|
||||
padded_len = len(rsrc)
|
||||
|
||||
for addr in RESOURCE_LENGTH_PATCHES:
|
||||
pe.set_u32(addr, rsrc_len)
|
||||
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
|
||||
|
||||
for addr in RESOURCE_PADDED_PATCHES:
|
||||
pe.seek(addr)
|
||||
size_delta = padded_len - pe.u32()
|
||||
pe.set_u32(addr, padded_len)
|
||||
# Resource size.
|
||||
pe.OPTIONAL_HEADER.DATA_DIRECTORY[2].Size += newsize - virsize
|
||||
|
||||
for addr in SIZE_DELTA_PATCHES:
|
||||
pe.seek(addr)
|
||||
pe.set_u32(addr, pe.u32() + size_delta)
|
||||
# Compute the total size of the image.
|
||||
total_size = 0
|
||||
|
||||
for i in pe.sections:
|
||||
|
||||
|
||||
return pe.tostring()[:RESOURCE_BASE] + rsrc
|
||||
sec_size = i.Misc_VirtualSize
|
||||
sec_size = sec_size - (sec_size % alignment) + alignment
|
||||
print sec_size
|
||||
|
||||
total_size += sec_size
|
||||
|
||||
pe.OPTIONAL_HEADER.SizeOfImage = total_size
|
||||
|
||||
return pe.write()[:base] + rsrc
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -108,7 +108,7 @@ init python:
|
||||
return rv
|
||||
|
||||
|
||||
def switch_theme(name):
|
||||
def switch_theme(theme_function, name):
|
||||
"""
|
||||
Switches the theme of the current project to the named theme.
|
||||
"""
|
||||
@@ -130,7 +130,7 @@ init python:
|
||||
m = re.match(r' theme.(\w+)\(', l)
|
||||
if m:
|
||||
if m.group(1) in theme_functions:
|
||||
l = theme_templates[td["theme"]] % td
|
||||
l = theme_templates[theme_function] % td
|
||||
changed = True
|
||||
|
||||
out.write(l + "\n")
|
||||
@@ -160,29 +160,26 @@ init python:
|
||||
|
||||
##########################################################################
|
||||
# Code that handles display.
|
||||
|
||||
|
||||
current_theme_function = None
|
||||
current_theme = None
|
||||
|
||||
def show_theme(name, target):
|
||||
def show_theme(function, name, target):
|
||||
"""
|
||||
Changes from the current theme to the roundrect theme named
|
||||
`name`.
|
||||
Changes from the current theme to the theme named `name`.
|
||||
"""
|
||||
|
||||
if current_theme == name:
|
||||
if current_theme_function == function and current_theme == name:
|
||||
return
|
||||
|
||||
store.current_theme_function = function
|
||||
store.current_theme = name
|
||||
|
||||
td = theme_data[name].copy()
|
||||
kind = td["theme"]
|
||||
del td["theme"]
|
||||
|
||||
if kind == "roundrect":
|
||||
td["rounded_window"] = False
|
||||
td["rounded_window"] = False
|
||||
|
||||
renpy.style.restore(style_backup)
|
||||
getattr(theme, kind)(**td)
|
||||
getattr(theme, function)(**td)
|
||||
customize_styles()
|
||||
renpy.style.rebuild()
|
||||
|
||||
@@ -264,7 +261,7 @@ label repeat_choose_theme:
|
||||
button(name,
|
||||
ui.returns(function),
|
||||
"",
|
||||
hovered=curried_show_theme(exemplar, "repeat_choose_theme"),
|
||||
hovered=curried_show_theme(function, exemplar, "repeat_choose_theme"),
|
||||
unhovered=does_nothing)
|
||||
|
||||
ui.close() # vbox
|
||||
@@ -292,7 +289,8 @@ label repeat_choose_color_scheme:
|
||||
|
||||
tip = _(u"Please choose a color scheme for your project.")
|
||||
|
||||
themes = [ k for k,v in theme_data.iteritems() if v["theme"] == theme_function ]
|
||||
|
||||
themes = theme_data.keys()
|
||||
themes.sort()
|
||||
|
||||
screen()
|
||||
@@ -307,9 +305,9 @@ label repeat_choose_color_scheme:
|
||||
|
||||
for i in themes:
|
||||
button(i,
|
||||
curried_switch_theme(i),
|
||||
curried_switch_theme(theme_function, i),
|
||||
"",
|
||||
hovered=curried_show_theme(i, "repeat_choose_color_scheme"),
|
||||
hovered=curried_show_theme(theme_function, i, "repeat_choose_color_scheme"),
|
||||
unhovered=does_nothing)
|
||||
|
||||
ui.close() # vbox
|
||||
|
||||
@@ -0,0 +1,536 @@
|
||||
import os
|
||||
import os.path
|
||||
import zipfile
|
||||
import tarfile
|
||||
import time
|
||||
import sys
|
||||
import struct
|
||||
import zlib
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
|
||||
import binascii
|
||||
import change_icon
|
||||
|
||||
import argparse
|
||||
|
||||
# The directory containing the project that we'll be distributing.
|
||||
project_path = None
|
||||
|
||||
# The path to the Ren'Py base directory.
|
||||
renpy_base = None
|
||||
|
||||
# A function that is called to give information about what is going
|
||||
# on now.
|
||||
def info(title, body):
|
||||
return
|
||||
|
||||
# A function that is called to give a progress report.
|
||||
def progress(title, total, amount):
|
||||
amount += 1
|
||||
|
||||
if amount % 25 == 0:
|
||||
print title, amount, "of", total
|
||||
|
||||
# A translation function.
|
||||
def _(s):
|
||||
return s
|
||||
|
||||
# These are files that are ignored wherever they are found in a
|
||||
# distribution.
|
||||
ignored_files = (
|
||||
"thumbs.db",
|
||||
"traceback.txt",
|
||||
"errors.txt",
|
||||
"files.txt",
|
||||
"saves"
|
||||
)
|
||||
|
||||
# These are files (and directories) that are ignored when found in
|
||||
# the root directory of the distribution.
|
||||
root_ignored_files = (
|
||||
"common",
|
||||
"renpy",
|
||||
"renpy.code",
|
||||
"python23.dll",
|
||||
"python24.dll",
|
||||
"python25.dll",
|
||||
"msvcr71.dll",
|
||||
"lib",
|
||||
"iliad-icon.png",
|
||||
"manifest.xml",
|
||||
"icon.ico",
|
||||
"icon.icns",
|
||||
"launcherinfo.py",
|
||||
"archived",
|
||||
)
|
||||
|
||||
# Extensions that should be made executable.
|
||||
executable_extensions = (
|
||||
"MacOS",
|
||||
"so",
|
||||
"dylib",
|
||||
".sh",
|
||||
"python",
|
||||
"python.real",
|
||||
)
|
||||
|
||||
class MyZipFile(zipfile.ZipFile):
|
||||
"""
|
||||
Modified ZipFile class that can insert a file into the archive,
|
||||
using a supplied ZipInfo object. Code comes from the writestr
|
||||
and write methods of ZipFile.
|
||||
"""
|
||||
|
||||
def write_file_with_zipinfo(self, filename, zinfo, compress_type=None):
|
||||
"""Put the bytes from filename into the archive under the name
|
||||
arcname."""
|
||||
st = os.stat(filename)
|
||||
|
||||
if compress_type is None:
|
||||
zinfo.compress_type = self.compression
|
||||
else:
|
||||
zinfo.compress_type = compress_type
|
||||
|
||||
zinfo.file_size = st.st_size
|
||||
zinfo.flag_bits = 0x00
|
||||
zinfo.header_offset = self.fp.tell() # Start of header bytes
|
||||
|
||||
self._writecheck(zinfo)
|
||||
self._didModify = True
|
||||
|
||||
fp = open(filename, "rb")
|
||||
|
||||
# Must overwrite CRC and sizes with correct data later
|
||||
zinfo.CRC = CRC = 0
|
||||
zinfo.compress_size = compress_size = 0
|
||||
zinfo.file_size = file_size = 0
|
||||
|
||||
self.fp.write(zinfo.FileHeader())
|
||||
|
||||
if zinfo.compress_type == zipfile.ZIP_DEFLATED:
|
||||
cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
|
||||
zlib.DEFLATED, -15)
|
||||
else:
|
||||
cmpr = None
|
||||
while 1:
|
||||
buf = fp.read(1024 * 64)
|
||||
if not buf:
|
||||
break
|
||||
file_size = file_size + len(buf)
|
||||
CRC = binascii.crc32(buf, CRC)
|
||||
if cmpr:
|
||||
buf = cmpr.compress(buf)
|
||||
compress_size = compress_size + len(buf)
|
||||
self.fp.write(buf)
|
||||
fp.close()
|
||||
if cmpr:
|
||||
buf = cmpr.flush()
|
||||
compress_size = compress_size + len(buf)
|
||||
self.fp.write(buf)
|
||||
zinfo.compress_size = compress_size
|
||||
else:
|
||||
zinfo.compress_size = file_size
|
||||
|
||||
zinfo.CRC = CRC
|
||||
zinfo.file_size = file_size
|
||||
|
||||
# Seek backwards and write CRC and file sizes
|
||||
position = self.fp.tell() # Preserve current position in file
|
||||
self.fp.seek(zinfo.header_offset + 14, 0)
|
||||
self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size,
|
||||
zinfo.file_size))
|
||||
|
||||
self.fp.seek(position, 0)
|
||||
self.filelist.append(zinfo)
|
||||
self.NameToInfo[zinfo.filename] = zinfo
|
||||
|
||||
def tree(
|
||||
src,
|
||||
dest,
|
||||
exclude_suffix=[ ".pyc", "~", ".bak", ".old", ".new" ],
|
||||
exclude_prefix=[ "#", "." ],
|
||||
exclude_files = set(ignored_files),
|
||||
root_exclude_prefix = [ ],
|
||||
root_exclude_suffix = [ ".py", ".sh", ".app" ],
|
||||
root_exclude_files = set(root_ignored_files),
|
||||
root=False):
|
||||
|
||||
"""
|
||||
Returns a list of source-filename, destination-filename pairs.
|
||||
"""
|
||||
|
||||
if dest[0] != "/":
|
||||
raise Exception("Destination must begin with /: %r" % dest)
|
||||
|
||||
src = src.rstrip('/')
|
||||
dest = dest.rstrip('/')
|
||||
|
||||
def include(fn, is_root):
|
||||
"""
|
||||
Returns True if the file should be included in the list of
|
||||
files we are copying.
|
||||
"""
|
||||
|
||||
for i in exclude_suffix:
|
||||
if fn.endswith(i):
|
||||
return False
|
||||
|
||||
for i in exclude_prefix:
|
||||
if fn.startswith(i):
|
||||
return False
|
||||
|
||||
if fn in exclude_files:
|
||||
return False
|
||||
|
||||
if not root or not is_root:
|
||||
return True
|
||||
|
||||
for i in root_exclude_suffix:
|
||||
if fn.endswith(i):
|
||||
return False
|
||||
|
||||
for i in root_exclude_prefix:
|
||||
if fn.startswith(i):
|
||||
return False
|
||||
|
||||
if fn in root_exclude_files:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
rv = [ ]
|
||||
|
||||
# Walk the tree, including what is necessary.
|
||||
for srcdir, dirs, files in os.walk(src):
|
||||
|
||||
is_root = (srcdir == src)
|
||||
|
||||
srcdir += "/"
|
||||
destdir = dest + srcdir[len(src):]
|
||||
destdir.replace("\\", "/")
|
||||
|
||||
rv.append((srcdir, destdir))
|
||||
|
||||
for fn in files:
|
||||
|
||||
if not include(fn, is_root):
|
||||
continue
|
||||
|
||||
sfn = srcdir + fn
|
||||
dfn = destdir + fn
|
||||
|
||||
rv.append((sfn, dfn))
|
||||
|
||||
dirs[:] = [ i for i in dirs if include(i, is_root) ]
|
||||
|
||||
rv = [ (a.replace("\\", "/"), b.replace("\\", "/")) for a, b in rv ]
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def make_zip(t, filename, files, file_data):
|
||||
"""
|
||||
This creates `filename`.zip, containing `files`, placed in the
|
||||
`filename` directory. `file_data` is a map from source file to
|
||||
replacement data.
|
||||
"""
|
||||
|
||||
files.sort(key=lambda a : a[1])
|
||||
progress_len = len(files)
|
||||
|
||||
fn = os.path.join(os.path.dirname(project_path), filename)
|
||||
|
||||
zf = MyZipFile(fn + ".zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
for i, (fn, an) in enumerate(files):
|
||||
|
||||
progress(t, progress_len, i)
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
zi = zipfile.ZipInfo(filename + an)
|
||||
|
||||
s = os.stat(fn)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
for i in executable_extensions:
|
||||
if os.path.dirname(fn).endswith(i) or fn.endswith(i):
|
||||
zi.external_attr = long(0100777) << 16
|
||||
break
|
||||
else:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
|
||||
if fn in file_data:
|
||||
data = file_data[fn]
|
||||
zf.writestr(zi, data)
|
||||
else:
|
||||
zf.write_file_with_zipinfo(fn, zi)
|
||||
|
||||
zf.close()
|
||||
|
||||
def make_tar(t, filename, files):
|
||||
"""
|
||||
Makes a tarfile, as above.
|
||||
"""
|
||||
|
||||
files.sort(key=lambda a : a[1])
|
||||
progress_len = len(files)
|
||||
|
||||
fn = os.path.join(os.path.dirname(project_path), filename)
|
||||
|
||||
tf = tarfile.open(fn + ".tar.bz2", "w:bz2")
|
||||
tf.dereference = True
|
||||
|
||||
for j, (fn, an) in enumerate(files):
|
||||
|
||||
progress(t, progress_len, j)
|
||||
|
||||
info = tf.gettarinfo(fn, filename + an)
|
||||
|
||||
perms = 0666
|
||||
|
||||
if info.isdir():
|
||||
perms = 0777
|
||||
|
||||
for i in executable_extensions:
|
||||
if fn.endswith(i):
|
||||
perms = 0777
|
||||
|
||||
info.mode = perms
|
||||
info.uid = 1000
|
||||
info.gid = 1000
|
||||
info.uname = "renpy"
|
||||
info.gname = "renpy"
|
||||
|
||||
if info.isreg():
|
||||
tf.addfile(info, file(fn, "rb"))
|
||||
else:
|
||||
tf.addfile(info)
|
||||
|
||||
tf.close()
|
||||
|
||||
|
||||
def distribute(
|
||||
_project_path,
|
||||
_renpy_base,
|
||||
base_name,
|
||||
executable_name,
|
||||
ignore_extensions,
|
||||
documentation_extensions,
|
||||
build_windows,
|
||||
build_linux,
|
||||
build_mac,
|
||||
build_all):
|
||||
|
||||
global project_path
|
||||
global renpy_base
|
||||
project_path = _project_path
|
||||
renpy_base = _renpy_base
|
||||
|
||||
base_name = base_name.encode("utf-8")
|
||||
executable_name = executable_name.encode("utf-8")
|
||||
ignore_extensions = ignore_extensions.encode("utf-8")
|
||||
documentation_extensions = documentation_extensions.encode("utf-8")
|
||||
|
||||
# Convert some of these to more useful formats.
|
||||
ignore_extensions = [ i.strip() for i in ignore_extensions.split() ]
|
||||
documentation_extensions = [ i.strip() for i in documentation_extensions.split() ]
|
||||
|
||||
# Scan for the files we want to include in the various distributions.
|
||||
info(_(u"Scanning..."), "")
|
||||
|
||||
# Files included in the various distributions.
|
||||
multi_files = [ ]
|
||||
win_files = [ ]
|
||||
linux_files = [ ]
|
||||
mac_files = [ ]
|
||||
|
||||
# A map from source file name to replacement data to be placed in
|
||||
# that file.
|
||||
file_data = { }
|
||||
|
||||
|
||||
######################################################################
|
||||
# Multi files.
|
||||
|
||||
rb = renpy_base.replace("\\", "/") + "/"
|
||||
|
||||
# Project files.
|
||||
multi_files.extend(tree(project_path, "/", root=True, exclude_suffix=ignore_extensions))
|
||||
multi_files.append((rb + "renpy.py", "/" + executable_name + ".py"))
|
||||
|
||||
# Renpy files.
|
||||
multi_files.extend(tree(rb + "common", "/common"))
|
||||
multi_files.extend(tree(rb + "renpy", "/renpy"))
|
||||
multi_files.append((rb + "LICENSE.txt", "/renpy/LICENSE.txt"))
|
||||
|
||||
def add_script_version(fn, ignore_extensions=ignore_extensions, multi_files=multi_files, rb=rb):
|
||||
"""
|
||||
Add a script_version file if it does not already exist, and if the
|
||||
extension is allowed by the game.
|
||||
"""
|
||||
|
||||
for a, b in multi_files:
|
||||
if b == "/game/" + fn:
|
||||
return
|
||||
|
||||
for i in ignore_extensions:
|
||||
if fn.endswith(i):
|
||||
return
|
||||
|
||||
multi_files.append((rb + "launcher/" + fn, "/game/" + fn))
|
||||
|
||||
add_script_version("script_version.rpy")
|
||||
add_script_version("script_version.rpyc")
|
||||
|
||||
|
||||
######################################################################
|
||||
# Windows files.
|
||||
|
||||
if build_windows or build_all:
|
||||
|
||||
win_files.append((rb + "renpy.exe", "/" + executable_name + ".exe"))
|
||||
win_files.append((rb + "python26.dll", "/python26.dll"))
|
||||
win_files.append((rb + "msvcr90.dll", "/msvcr90.dll"))
|
||||
win_files.append((rb + "Microsoft.VC90.CRT.manifest", "/Microsoft.VC90.CRT.manifest"))
|
||||
|
||||
win_files.append((rb + "lib", "/lib"))
|
||||
win_files.extend(tree(rb + "lib/windows-x86", "/lib/windows-x86"))
|
||||
|
||||
if os.path.exists(project_path + "/icon.ico"):
|
||||
file_data[rb + "renpy.exe"] = change_icon.change_icons(
|
||||
rb + "renpy.exe",
|
||||
project_path + "/icon.ico",
|
||||
)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Linux files.
|
||||
|
||||
if build_linux or build_all:
|
||||
|
||||
linux_files.append((rb + "renpy.sh", "/" + executable_name + ".sh"))
|
||||
linux_files.append((rb + "lib", "/lib"))
|
||||
linux_files.append((rb + "lib/python", "/lib/python"))
|
||||
linux_files.extend(tree(rb + "lib/linux-x86", "/lib/linux-x86"))
|
||||
|
||||
# Warning: The tar.bz2 builder doesn't support file_data.
|
||||
|
||||
|
||||
######################################################################
|
||||
# Mac (non-app) files.
|
||||
|
||||
if build_mac or build_all:
|
||||
mac_files = tree(rb + "renpy.app",
|
||||
"/" + executable_name + ".app")
|
||||
|
||||
# Rename executable.
|
||||
mac_files = [ (fn, an.replace("Ren'Py Launcher", executable_name)) for (fn, an) in mac_files ]
|
||||
|
||||
# Plist file.
|
||||
quoted_name = executable_name.replace("&", "&").replace("<", "<")
|
||||
info_plist = file(rb + "renpy.app/Contents/Info.plist", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
file_data[rb + "renpy.app/Contents/Info.plist"] = info_plist
|
||||
|
||||
# Launcher script.
|
||||
quoted_name = executable_name.replace("\"", "\\\"")
|
||||
launcher_py = file(rb + "renpy.app/Contents/Resources/launcher.py", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
file_data[rb + "renpy.app/Contents/Resources/launcher.py"] = launcher_py
|
||||
|
||||
# Icon file.
|
||||
if os.path.exists(project_path + "/icon.icns"):
|
||||
icon_data = file(project_path + "/icon.icns", "rb").read()
|
||||
file_data[rb + "renpy.app/Contents/Resources/launcher.icns"] = icon_data
|
||||
|
||||
|
||||
######################################################################
|
||||
# Now, build the various distributions.
|
||||
|
||||
if build_windows:
|
||||
make_zip(
|
||||
_(u"Building Windows..."),
|
||||
base_name + "-win32",
|
||||
multi_files + win_files,
|
||||
file_data)
|
||||
|
||||
if build_linux:
|
||||
make_tar(
|
||||
_(u"Building Linux..."),
|
||||
base_name + "-linux-x86",
|
||||
multi_files + linux_files)
|
||||
|
||||
|
||||
if build_mac:
|
||||
|
||||
# Reorganize the files so all the non application files live inside
|
||||
# the application. If there's documentation involved, then it
|
||||
# lives in both places.
|
||||
macapp_files = [ ]
|
||||
|
||||
for fn, an in multi_files + mac_files:
|
||||
if not an.startswith("/" + executable_name + ".app"):
|
||||
new_an = "/" + executable_name + ".app/Contents/Resources/autorun" + an
|
||||
macapp_files.append((fn, new_an))
|
||||
|
||||
if an.rindex('/') == 0:
|
||||
for i in documentation_extensions:
|
||||
if fn.endswith(i):
|
||||
macapp_files.append((fn, an))
|
||||
break
|
||||
else:
|
||||
macapp_files.append((fn, an))
|
||||
|
||||
make_zip(
|
||||
_(u"Building Macintosh..."),
|
||||
base_name + "-mac",
|
||||
macapp_files,
|
||||
file_data)
|
||||
|
||||
|
||||
if build_all:
|
||||
make_zip(
|
||||
_(u"Building Combined..."),
|
||||
base_name + "-all",
|
||||
multi_files + win_files + linux_files + mac_files,
|
||||
file_data)
|
||||
|
||||
def main():
|
||||
|
||||
ap = argparse.ArgumentParser(description="Prepare a Ren'Py game for distribution.")
|
||||
|
||||
ap.add_argument("project_path", type=str, help="The path to the directory containing the project.")
|
||||
ap.add_argument("base_name", type=str, help="The base name of the archive files produced.")
|
||||
ap.add_argument("executable_name", type=str, help="The name of the executables produced.")
|
||||
ap.add_argument("--renpy-base", type=str, default=None, help="The path to the Ren'Py distribution.")
|
||||
|
||||
ap.add_argument("--ignore-extensions", type=str, default="~ .bak", help="A space-separated list of extensions to ignore.")
|
||||
ap.add_argument("--documentation-extensions", type=str, default="txt html", help="A space-separated list of extensions to treat as documentation.")
|
||||
|
||||
ap.add_argument("--build-windows", action="store_true", default=False, help="Build the Windows distribution.")
|
||||
ap.add_argument("--build-mac", action="store_true", default=False, help="Build the Mac OS X distribution.")
|
||||
ap.add_argument("--build-linux", action="store_true", default=False, help="Build the Windows distribution.")
|
||||
ap.add_argument("--build-all", action="store_true", default=False, help="Build the All Platforms distribution.")
|
||||
|
||||
args = ap.parse_args()
|
||||
|
||||
renpy_base = args.renpy_base
|
||||
if renpy_base is None:
|
||||
renpy_base = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
|
||||
|
||||
distribute(
|
||||
args.project_path,
|
||||
renpy_base,
|
||||
base_name=args.base_name,
|
||||
executable_name=args.executable_name,
|
||||
ignore_extensions=args.ignore_extensions,
|
||||
documentation_extensions=args.documentation_extensions,
|
||||
build_windows=args.build_windows,
|
||||
build_mac=args.build_mac,
|
||||
build_linux=args.build_linux,
|
||||
build_all=args.build_all)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,236 +1,21 @@
|
||||
# This file contains the code needed to build a Ren'Py distribution.
|
||||
|
||||
init python:
|
||||
import os
|
||||
import os.path
|
||||
import zipfile
|
||||
import tarfile
|
||||
import time
|
||||
import sys
|
||||
import struct
|
||||
import zlib
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
init 12 python:
|
||||
|
||||
import binascii
|
||||
|
||||
import pefile
|
||||
|
||||
# These are files that are ignored wherever they are found in a
|
||||
# distribution.
|
||||
ignored_files = (
|
||||
"thumbs.db",
|
||||
"traceback.txt",
|
||||
"errors.txt",
|
||||
"saves"
|
||||
)
|
||||
import distribute
|
||||
|
||||
# These are files (and directories) that are ignored when found in
|
||||
# the root directory of the distribution.
|
||||
root_ignored_files = (
|
||||
"common",
|
||||
"renpy",
|
||||
"renpy.code",
|
||||
"python23.dll",
|
||||
"python24.dll",
|
||||
"python25.dll",
|
||||
"msvcr71.dll",
|
||||
"lib",
|
||||
"iliad-icon.png",
|
||||
"manifest.xml",
|
||||
"icon.ico",
|
||||
"icon.icns",
|
||||
"launcherinfo.py",
|
||||
"archived",
|
||||
)
|
||||
distribute.progress = progress
|
||||
distribute.info = info
|
||||
distribute._ = _
|
||||
|
||||
# Extensions that should be made executable.
|
||||
executable_extensions = (
|
||||
"MacOS",
|
||||
"so",
|
||||
"dylib",
|
||||
".sh",
|
||||
"python",
|
||||
"python.real",
|
||||
)
|
||||
|
||||
|
||||
def tree(
|
||||
src,
|
||||
dest,
|
||||
exclude_suffix=[ ".pyc", "~", ".bak" ],
|
||||
exclude_prefix=[ "#", "." ],
|
||||
exclude_files = set(ignored_files),
|
||||
root_exclude_prefix = [ ],
|
||||
root_exclude_suffix = [ ".py", ".sh", ".app" ],
|
||||
root_exclude_files = set(root_ignored_files),
|
||||
root=False):
|
||||
|
||||
"""
|
||||
Returns a list of source-filename, destination-filename pairs.
|
||||
"""
|
||||
|
||||
if dest[0] != "/":
|
||||
raise Exception("Destination must begin with /: %r" % dest)
|
||||
|
||||
src = src.rstrip('/')
|
||||
dest = dest.rstrip('/')
|
||||
|
||||
def include(fn, is_root):
|
||||
"""
|
||||
Returns True if the file should be included in the list of
|
||||
files we are copying.
|
||||
"""
|
||||
|
||||
for i in exclude_suffix:
|
||||
if fn.endswith(i):
|
||||
return False
|
||||
|
||||
for i in exclude_prefix:
|
||||
if fn.startswith(i):
|
||||
return False
|
||||
|
||||
if fn in exclude_files:
|
||||
return False
|
||||
|
||||
if not root or not is_root:
|
||||
return True
|
||||
|
||||
for i in root_exclude_suffix:
|
||||
if fn.endswith(i):
|
||||
return False
|
||||
|
||||
for i in root_exclude_prefix:
|
||||
if fn.startswith(i):
|
||||
return False
|
||||
|
||||
if fn in root_exclude_files:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
rv = [ ]
|
||||
|
||||
# Walk the tree, including what is necessary.
|
||||
for srcdir, dirs, files in os.walk(src):
|
||||
|
||||
is_root = (srcdir == src)
|
||||
|
||||
srcdir += "/"
|
||||
destdir = dest + srcdir[len(src):]
|
||||
destdir.replace("\\", "/")
|
||||
|
||||
rv.append((srcdir, destdir))
|
||||
|
||||
for fn in files:
|
||||
|
||||
if not include(fn, is_root):
|
||||
continue
|
||||
|
||||
sfn = srcdir + fn
|
||||
dfn = destdir + fn
|
||||
|
||||
rv.append((sfn, dfn))
|
||||
|
||||
dirs[:] = [ i for i in dirs if include(i, is_root) ]
|
||||
|
||||
rv = [ (a.replace("\\", "/"), b.replace("\\", "/")) for a, b in rv ]
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def make_zip(t, filename, files, file_data):
|
||||
"""
|
||||
This creates `filename`.zip, containing `files`, placed in the
|
||||
`filename` directory. `file_data` is a map from source file to
|
||||
replacement data.
|
||||
"""
|
||||
|
||||
files.sort(key=lambda a : a[1])
|
||||
progress_len = len(files)
|
||||
|
||||
fn = os.path.join(os.path.dirname(project.path), filename)
|
||||
|
||||
zf = MyZipFile(fn + ".zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
for i, (fn, an) in enumerate(files):
|
||||
|
||||
progress(t, progress_len, i)
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
zi = zipfile.ZipInfo(filename + an)
|
||||
|
||||
s = os.stat(fn)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
for i in executable_extensions:
|
||||
if os.path.dirname(fn).endswith(i) or fn.endswith(i):
|
||||
zi.external_attr = long(0100777) << 16
|
||||
break
|
||||
else:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
|
||||
if fn in file_data:
|
||||
data = file_data[fn]
|
||||
zf.writestr(zi, data)
|
||||
else:
|
||||
zf.write_file_with_zipinfo(fn, zi)
|
||||
|
||||
zf.close()
|
||||
|
||||
def make_tar(t, filename, files):
|
||||
"""
|
||||
Makes a tarfile, as above.
|
||||
"""
|
||||
|
||||
files.sort(key=lambda a : a[1])
|
||||
progress_len = len(files)
|
||||
|
||||
fn = os.path.join(os.path.dirname(project.path), filename)
|
||||
|
||||
tf = tarfile.open(fn + ".tar.bz2", "w:bz2")
|
||||
tf.dereference = True
|
||||
|
||||
for j, (fn, an) in enumerate(files):
|
||||
|
||||
progress(t, progress_len, j)
|
||||
|
||||
info = tf.gettarinfo(fn, filename + an)
|
||||
|
||||
perms = 0666
|
||||
|
||||
if info.isdir():
|
||||
perms = 0777
|
||||
|
||||
for i in executable_extensions:
|
||||
if fn.endswith(i):
|
||||
perms = 0777
|
||||
|
||||
info.mode = perms
|
||||
info.uid = 1000
|
||||
info.gid = 1000
|
||||
info.uname = "renpy"
|
||||
info.gname = "renpy"
|
||||
|
||||
if info.isreg():
|
||||
tf.addfile(info, file(fn, "rb"))
|
||||
else:
|
||||
tf.addfile(info)
|
||||
|
||||
tf.close()
|
||||
|
||||
|
||||
def dist_exists(fn):
|
||||
"""
|
||||
Returns true if the given file exists in the renpy directory.
|
||||
"""
|
||||
|
||||
|
||||
return os.path.exists(os.path.join(config.renpy_base, fn))
|
||||
|
||||
|
||||
|
||||
label distribute:
|
||||
|
||||
call lint
|
||||
@@ -370,173 +155,18 @@ label distribute:
|
||||
|
||||
project.save()
|
||||
|
||||
base_name = base_name.encode("utf-8")
|
||||
executable_name = executable_name.encode("utf-8")
|
||||
ignore_extensions = ignore_extensions.encode("utf-8")
|
||||
documentation_extensions = documentation_extensions.encode("utf-8")
|
||||
|
||||
# Convert some of these to more useful formats.
|
||||
ignore_extensions = [ i.strip() for i in ignore_extensions.split() ]
|
||||
documentation_extensions = [ i.strip() for i in documentation_extensions.split() ]
|
||||
|
||||
# Scan for the files we want to include in the various distributions.
|
||||
info(_(u"Scanning..."), "")
|
||||
|
||||
# Files included in the various distributions.
|
||||
multi_files = [ ]
|
||||
win_files = [ ]
|
||||
linux_files = [ ]
|
||||
mac_files = [ ]
|
||||
|
||||
# A map from source file name to replacement data to be placed in
|
||||
# that file.
|
||||
file_data = { }
|
||||
|
||||
|
||||
######################################################################
|
||||
# Multi files.
|
||||
|
||||
rb = config.renpy_base.replace("\\", "/") + "/"
|
||||
|
||||
|
||||
|
||||
|
||||
# Project files.
|
||||
multi_files.extend(tree(project.path, "/", root=True, exclude_suffix=ignore_extensions))
|
||||
multi_files.append((rb + "renpy.py", "/" + executable_name + ".py"))
|
||||
|
||||
# Renpy files.
|
||||
multi_files.extend(tree(rb + "common", "/common"))
|
||||
multi_files.extend(tree(rb + "renpy", "/renpy"))
|
||||
multi_files.append((rb + "LICENSE.txt", "/renpy/LICENSE.txt"))
|
||||
|
||||
def add_script_version(fn, ignore_extensions=ignore_extensions, multi_files=multi_files, rb=rb):
|
||||
"""
|
||||
Add a script_version file if it does not already exist, and if the
|
||||
extension is allowed by the game.
|
||||
"""
|
||||
|
||||
for a, b in multi_files:
|
||||
if b == "/game/" + fn:
|
||||
return
|
||||
|
||||
for i in ignore_extensions:
|
||||
if fn.endswith(i):
|
||||
return
|
||||
|
||||
multi_files.append((rb + "launcher/" + fn, "/game/" + fn))
|
||||
|
||||
add_script_version("script_version.rpy")
|
||||
add_script_version("script_version.rpyc")
|
||||
|
||||
|
||||
######################################################################
|
||||
# Windows files.
|
||||
|
||||
if build_windows or build_all:
|
||||
|
||||
win_files.append((rb + "renpy.exe", "/" + executable_name + ".exe"))
|
||||
win_files.append((rb + "renpy.code", "/renpy.code"))
|
||||
win_files.append((rb + "python25.dll", "/python25.dll"))
|
||||
win_files.append((rb + "msvcr71.dll", "/msvcr71.dll"))
|
||||
|
||||
if os.path.exists(project.path + "/icon.ico"):
|
||||
file_data[rb + "renpy.exe"] = pefile.change_icons(
|
||||
rb + "renpy.exe",
|
||||
project.path + "/icon.ico",
|
||||
)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Linux files.
|
||||
|
||||
if build_linux or build_all:
|
||||
|
||||
linux_files.append((rb + "renpy.sh", "/" + executable_name + ".sh"))
|
||||
linux_files.append((rb + "lib", "/lib"))
|
||||
linux_files.append((rb + "lib/python", "/lib/python"))
|
||||
linux_files.extend(tree(rb + "lib/linux-x86", "/lib/linux-x86"))
|
||||
|
||||
# Warning: The tar.bz2 builder doesn't support file_data.
|
||||
|
||||
distribute.distribute(
|
||||
project.path,
|
||||
config.renpy_base,
|
||||
base_name=base_name,
|
||||
executable_name=executable_name,
|
||||
ignore_extensions=ignore_extensions,
|
||||
documentation_extensions=documentation_extensions,
|
||||
build_windows=build_windows,
|
||||
build_mac=build_mac,
|
||||
build_linux=build_linux,
|
||||
build_all=build_all)
|
||||
|
||||
######################################################################
|
||||
# Mac (non-app) files.
|
||||
|
||||
if build_mac or build_all:
|
||||
mac_files = tree(rb + "renpy.app",
|
||||
"/" + executable_name + ".app")
|
||||
|
||||
# Rename executable.
|
||||
mac_files = [ (fn, an.replace("Ren'Py Launcher", executable_name)) for (fn, an) in mac_files ]
|
||||
|
||||
# Plist file.
|
||||
quoted_name = executable_name.replace("&", "&").replace("<", "<")
|
||||
info_plist = file(rb + "renpy.app/Contents/Info.plist", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
file_data[rb + "renpy.app/Contents/Info.plist"] = info_plist
|
||||
|
||||
# Launcher script.
|
||||
quoted_name = executable_name.replace("\"", "\\\"")
|
||||
launcher_py = file(rb + "renpy.app/Contents/Resources/launcher.py", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
file_data[rb + "renpy.app/Contents/Resources/launcher.py"] = launcher_py
|
||||
|
||||
# Icon file.
|
||||
if os.path.exists(project.path + "/icon.icns"):
|
||||
icon_data = file(project.path + "/icon.icns", "rb").read()
|
||||
file_data[rb + "renpy.app/Contents/Resources/launcher.icns"] = icon_data
|
||||
|
||||
|
||||
######################################################################
|
||||
# Now, build the various distributions.
|
||||
|
||||
if build_windows:
|
||||
make_zip(
|
||||
_(u"Building Windows..."),
|
||||
base_name + "-win32",
|
||||
multi_files + win_files,
|
||||
file_data)
|
||||
|
||||
if build_linux:
|
||||
make_tar(
|
||||
_(u"Building Linux..."),
|
||||
base_name + "-linux-x86",
|
||||
multi_files + linux_files)
|
||||
|
||||
|
||||
if build_mac:
|
||||
|
||||
# Reorganize the files so all the non application files live inside
|
||||
# the application. If there's documentation involved, then it
|
||||
# lives in both places.
|
||||
macapp_files = [ ]
|
||||
|
||||
for fn, an in multi_files + mac_files:
|
||||
if not an.startswith("/" + executable_name + ".app"):
|
||||
new_an = "/" + executable_name + ".app/Contents/Resources/autorun" + an
|
||||
macapp_files.append((fn, new_an))
|
||||
|
||||
if an.rindex('/') == 0:
|
||||
for i in documentation_extensions:
|
||||
if fn.endswith(i):
|
||||
macapp_files.append((fn, an))
|
||||
break
|
||||
else:
|
||||
macapp_files.append((fn, an))
|
||||
|
||||
make_zip(
|
||||
_(u"Building Macintosh..."),
|
||||
base_name + "-mac",
|
||||
macapp_files,
|
||||
file_data)
|
||||
|
||||
|
||||
if build_all:
|
||||
make_zip(
|
||||
_(u"Building Combined..."),
|
||||
base_name + "-all",
|
||||
multi_files + win_files + linux_files + mac_files,
|
||||
file_data)
|
||||
|
||||
# Report success to the user.
|
||||
set_tooltip(_(u"Thank you for choosing Ren'Py."))
|
||||
|
||||
@@ -544,7 +174,7 @@ label distribute:
|
||||
ui.vbox()
|
||||
|
||||
title(_(u"Success"))
|
||||
text(_(u"The distributions have been built. Be sure to test them before release.\n\nNote that unpacking and repacking the Macintosh, Linux, or Combined distributions on Windows is not supported.\n\nPlease announce your release at the {a=http://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}, so we can add it to the Ren'Py web site."))
|
||||
text(_(u"The distributions have been built. Be sure to test them before release.\n\nNote that unpacking and repacking the Macintosh, Linux, or Combined distributions on Windows is not supported.\n\nPlease announce your release at the {a=http://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}, and add it to {a=http://games.renpy.org}games.renpy.org{/a}."))
|
||||
|
||||
ui.null(height=20)
|
||||
|
||||
@@ -553,76 +183,3 @@ label distribute:
|
||||
ui.close()
|
||||
interact()
|
||||
|
||||
|
||||
init python:
|
||||
|
||||
class MyZipFile(zipfile.ZipFile):
|
||||
"""
|
||||
Modified ZipFile class that can insert a file into the archive,
|
||||
using a supplied ZipInfo object. Code comes from the writestr
|
||||
and write methods of ZipFile.
|
||||
"""
|
||||
|
||||
|
||||
def write_file_with_zipinfo(self, filename, zinfo, compress_type=None):
|
||||
"""Put the bytes from filename into the archive under the name
|
||||
arcname."""
|
||||
st = os.stat(filename)
|
||||
|
||||
if compress_type is None:
|
||||
zinfo.compress_type = self.compression
|
||||
else:
|
||||
zinfo.compress_type = compress_type
|
||||
|
||||
zinfo.file_size = st.st_size
|
||||
zinfo.flag_bits = 0x00
|
||||
zinfo.header_offset = self.fp.tell() # Start of header bytes
|
||||
|
||||
self._writecheck(zinfo)
|
||||
self._didModify = True
|
||||
|
||||
fp = open(filename, "rb")
|
||||
|
||||
# Must overwrite CRC and sizes with correct data later
|
||||
zinfo.CRC = CRC = 0
|
||||
zinfo.compress_size = compress_size = 0
|
||||
zinfo.file_size = file_size = 0
|
||||
|
||||
self.fp.write(zinfo.FileHeader())
|
||||
|
||||
if zinfo.compress_type == zipfile.ZIP_DEFLATED:
|
||||
cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
|
||||
zlib.DEFLATED, -15)
|
||||
else:
|
||||
cmpr = None
|
||||
while 1:
|
||||
buf = fp.read(1024 * 64)
|
||||
if not buf:
|
||||
break
|
||||
file_size = file_size + len(buf)
|
||||
CRC = binascii.crc32(buf, CRC)
|
||||
if cmpr:
|
||||
buf = cmpr.compress(buf)
|
||||
compress_size = compress_size + len(buf)
|
||||
self.fp.write(buf)
|
||||
fp.close()
|
||||
if cmpr:
|
||||
buf = cmpr.flush()
|
||||
compress_size = compress_size + len(buf)
|
||||
self.fp.write(buf)
|
||||
zinfo.compress_size = compress_size
|
||||
else:
|
||||
zinfo.compress_size = file_size
|
||||
|
||||
zinfo.CRC = CRC
|
||||
zinfo.file_size = file_size
|
||||
|
||||
# Seek backwards and write CRC and file sizes
|
||||
position = self.fp.tell() # Preserve current position in file
|
||||
self.fp.seek(zinfo.header_offset + 14, 0)
|
||||
self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size,
|
||||
zinfo.file_size))
|
||||
|
||||
self.fp.seek(position, 0)
|
||||
self.filelist.append(zinfo)
|
||||
self.NameToInfo[zinfo.filename] = zinfo
|
||||
|
||||
@@ -221,6 +221,27 @@ init 11 python:
|
||||
|
||||
interact()
|
||||
|
||||
def pauseinfo(t, message):
|
||||
"""
|
||||
Displays an error to the user, and lets him click to return to
|
||||
`target`.
|
||||
"""
|
||||
|
||||
set_tooltip("")
|
||||
|
||||
screen()
|
||||
|
||||
ui.vbox()
|
||||
title(t)
|
||||
text(message)
|
||||
|
||||
ui.null(height=20)
|
||||
|
||||
button(_(u"Ok"), ui.returns(True), None)
|
||||
ui.close()
|
||||
|
||||
interact()
|
||||
|
||||
def info(t, message):
|
||||
"""
|
||||
Displays an informational message to the user, and immediately
|
||||
|
||||
@@ -100,6 +100,9 @@ init -1 python hide:
|
||||
## Set this to False if the game does not have any sound effects.
|
||||
config.sound = False
|
||||
|
||||
# Disable opengl.
|
||||
config.gl_enable = False
|
||||
|
||||
python early:
|
||||
config.save_directory = "launcher-2"
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ init python:
|
||||
import sys
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
# Set the projects directory to None if it no longer exists.
|
||||
if persistent.projects_directory is not None:
|
||||
if not os.path.isdir(persistent.projects_directory):
|
||||
persistent.projects_directory = None
|
||||
|
||||
ZWSP = u"\u200B"
|
||||
|
||||
@@ -220,7 +225,7 @@ label launch:
|
||||
set_tooltip(_(u"%s has been launched.") % project.name.capitalize())
|
||||
|
||||
store.game_proc = proc
|
||||
|
||||
|
||||
jump top
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
def k(s):
|
||||
s = s.replace(" ", "")
|
||||
s = s.replace(":", "")
|
||||
s = s.replace("\n", "")
|
||||
|
||||
return int(s, 16)
|
||||
|
||||
modulus = k("""
|
||||
00:c2:e6:31:c6:7d:b3:cf:57:12:91:cf:b4:2c:9d:
|
||||
25:17:cf:21:f8:ac:5b:1d:c1:95:56:9d:1c:1c:d5:
|
||||
eb:67:ca:0a:a4:3f:e5:9c:6c:10:6e:4a:7a:2c:c2:
|
||||
d6:e3:3f:84:6d:b1:6f:70:3d:05:4e:06:91:3c:51:
|
||||
28:3f:b1:26:a5:be:6e:a6:14:a1:09:95:87:10:4d:
|
||||
c3:4b:44:fd:e0:a6:9d:f8:1f:50:ca:8a:0d:fd:86:
|
||||
7d:39:74:af:af:4e:05:8b:bd:93:b5:9b:6a:85:ca:
|
||||
1e:47:25:ca:f1:31:47:10:3e:a2:26:79:d2:00:34:
|
||||
f4:c5:a8:db:b6:36:2b:70:ef:14:8c:44:41:02:11:
|
||||
64:31:d4:d8:cd:7b:a7:e1:af:25:2c:a4:31:fb:84:
|
||||
c7:bc:6e:7c:fb:6a:46:5d:ee:bb:5f:74:96:a1:fe:
|
||||
13:79:55:e8:c4:74:77:1c:ea:6a:8e:a8:cb:89:da:
|
||||
20:db:88:18:e5:4a:f9:93:43:03:53:c3:d8:a3:2c:
|
||||
73:ea:8c:64:55:da:cf:a5:c7:11:70:ce:d4:51:3c:
|
||||
2c:19:06:3c:23:0c:d6:02:a5:95:28:b7:b0:34:1f:
|
||||
5d:32:38:e0:01:f2:12:b5:b2:8f:6b:83:83:06:6c:
|
||||
e0:ca:ec:e5:45:3e:75:79:f4:bf:47:e2:56:cd:8a:
|
||||
7b:cc:c7:0d:14:af:00:f6:e0:64:e2:30:a3:6c:ed:
|
||||
05:1e:33:9a:88:8b:0d:31:48:2b:02:65:61:4b:cd:
|
||||
84:90:c5:83:ba:93:1f:b7:78:7f:ec:4e:e9:bc:02:
|
||||
03:86:c2:a9:00:87:4c:e1:bb:d8:e7:b2:12:a6:9b:
|
||||
ab:9f:24:6f:6d:fe:09:60:22:d9:45:c2:20:55:70:
|
||||
27:9d:3a:84:fb:57:9a:d3:d0:d2:d3:18:25:8c:40:
|
||||
f8:2c:15:98:de:2e:2d:be:b4:dd:6e:24:2b:07:0b:
|
||||
21:08:a6:db:30:df:5c:7f:50:6f:be:b7:2e:40:28:
|
||||
58:85:89:de:4e:c7:66:af:fc:05:1c:c7:4d:d1:d2:
|
||||
fa:2c:00:1a:0e:47:5f:30:b6:e6:90:fe:99:96:42:
|
||||
4d:17:d3:13:36:7b:76:1c:36:c6:31:f3:a8:b0:9c:
|
||||
33:a1:b3:e9:40:51:b9:29:1d:b4:36:2a:20:0e:c0:
|
||||
f7:fb:a9:db:18:e0:67:ca:5d:d7:46:03:17:32:04:
|
||||
35:24:5a:fe:0a:1e:7b:96:8b:0a:fb:3c:f6:94:92:
|
||||
ab:d8:7d:ed:e4:2b:64:d7:ab:8d:11:89:e3:80:9d:
|
||||
28:59:da:de:6f:55:30:30:78:9a:06:30:5b:a4:ff:
|
||||
7a:70:49:b6:8c:9a:66:c0:a8:77:74:ca:f5:02:05:
|
||||
63:8c:83
|
||||
""")
|
||||
|
||||
exponent = 0x10001
|
||||
|
||||
@@ -83,7 +83,7 @@ label top:
|
||||
_(u"Visit the Ren'Py games list, at http://games.renpy.org."))
|
||||
|
||||
button(_(u"Quit"),
|
||||
renpy.quit,
|
||||
ui.jumps("launcher_quit"),
|
||||
_(u"Causes the launcher to exit."))
|
||||
|
||||
button(_(u"Options"),
|
||||
@@ -105,11 +105,14 @@ label top:
|
||||
ui.null()
|
||||
|
||||
ui.null()
|
||||
|
||||
|
||||
|
||||
ui.close()
|
||||
ui.close()
|
||||
|
||||
if update_allowed:
|
||||
ui.key("U", Jump("update"))
|
||||
|
||||
interact()
|
||||
|
||||
# ProcessBehavior can return True, which sends us here.
|
||||
@@ -133,7 +136,8 @@ label renpy_games_list:
|
||||
set_tooltip(_(u"Now showing the Ren'Py Games List in your web browser."))
|
||||
|
||||
jump top
|
||||
|
||||
|
||||
label launcher_quit:
|
||||
label confirm_quit:
|
||||
$ renpy.quit()
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
init -999:
|
||||
$ config.script_version = (6, 10, 2)
|
||||
$ config.script_version = (6, 11, 2)
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
init python:
|
||||
LAUNCHER_RPYS = set(['options.rpy', 'strings.rpy', 'transupdate.rpy', 'choose_theme.rpy', 'archiver.rpy', 'project.rpy', 'script_version.rpy', 'new.rpy', 'themes_data.rpy', 'opts.rpy', 'interface.rpy', 'projectsdir.rpy', 'distribute.rpy', 'script.rpy', 'editor.rpy'])
|
||||
LAUNCHER_RPYS = set(['options.rpy', 'strings.rpy', 'transupdate.rpy', 'choose_theme.rpy', 'archiver.rpy', 'project.rpy', 'script_version.rpy', 'new.rpy', 'updater.rpy', 'themes_data.rpy', 'opts.rpy', 'interface.rpy', 'projectsdir.rpy', 'update_interface.rpy', 'distribute.rpy', 'script.rpy', 'editor.rpy'])
|
||||
|
||||
TRANSLATION_STRINGS = [
|
||||
|
||||
u"Graphics Acceleration",
|
||||
u"Automatically Choose",
|
||||
u"Prefer Software Renderer",
|
||||
u"Prefer OpenGL Renderer",
|
||||
u"Continue",
|
||||
u"Are you sure?",
|
||||
u"Are you sure you want to delete this save?",
|
||||
u"Are you sure you want to overwrite your save?",
|
||||
@@ -64,14 +69,13 @@ init python:
|
||||
u"Joystick...",
|
||||
u"Joystick Configuration",
|
||||
u"Voice Volume",
|
||||
u"Developer Menu",
|
||||
u"Return to the developer menu",
|
||||
u"Reload Game (Shift+R)",
|
||||
u"Reload Game (Shift + R)",
|
||||
u"Variable Viewer",
|
||||
u"Return to the developer menu",
|
||||
u"Theme Test",
|
||||
u"Style Hierarchy",
|
||||
u"FPS Meter",
|
||||
u"Image Location Picker",
|
||||
u"Filename List",
|
||||
u"Done",
|
||||
u"Auto",
|
||||
u"Quick",
|
||||
@@ -104,6 +108,16 @@ init python:
|
||||
u"Choose Theme",
|
||||
u"Please choose a color scheme for your project.",
|
||||
u"Choose Color Scheme",
|
||||
u"Base Name",
|
||||
u"Please enter in the base name for your distribution. This name is used to generate the names of directories and archive files. Usually, this is the name of your game, plus a version number, like \"moonlight-1.0\".",
|
||||
u"Executable Name",
|
||||
u"Please enter a name for the executables in your distribution. This should not include an extension, as that will be added automatically.",
|
||||
u"Ignore Extensions",
|
||||
u"Please enter a space-separated list of file extensions. Files with these extensions will not be included in the built distributions.",
|
||||
u"Documentation Extensions",
|
||||
u"Please enter a space separated list of documentation extensions. Files in the base directory with these extensions will have a second copy stored outside of the Macintosh application.",
|
||||
u"Thank you for choosing Ren'Py.",
|
||||
u"The distributions have been built. Be sure to test them before release.\n\nNote that unpacking and repacking the Macintosh, Linux, or Combined distributions on Windows is not supported.\n\nPlease announce your release at the {a=http://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}, and add it to {a=http://games.renpy.org}games.renpy.org{/a}.",
|
||||
u"Building Distributions",
|
||||
u"I've just performed a lint on your project. If it contains errors, you should say no and fix them.\nPlease also check {a=http://www.renpy.org/wiki/renpy/Download_Ren'Py}www.renpy.org{/a} to see if updates or fixes are available.\n\nDo you want to continue?",
|
||||
u"Base Name:",
|
||||
@@ -125,21 +139,6 @@ init python:
|
||||
u"Zip distribution for the Windows x86, Linux x86, Macintosh x86 and Macintosh ppc platforms.",
|
||||
u"Build",
|
||||
u"Start building the distributions.",
|
||||
u"Base Name",
|
||||
u"Please enter in the base name for your distribution. This name is used to generate the names of directories and archive files. Usually, this is the name of your game, plus a version number, like \"moonlight-1.0\".",
|
||||
u"Executable Name",
|
||||
u"Please enter a name for the executables in your distribution. This should not include an extension, as that will be added automatically.",
|
||||
u"Ignore Extensions",
|
||||
u"Please enter a space-separated list of file extensions. Files with these extensions will not be included in the built distributions.",
|
||||
u"Documentation Extensions",
|
||||
u"Please enter a space separated list of documentation extensions. Files in the base directory with these extensions will have a second copy stored outside of the Macintosh application.",
|
||||
u"Scanning...",
|
||||
u"Building Windows...",
|
||||
u"Building Linux...",
|
||||
u"Building Macintosh...",
|
||||
u"Building Combined...",
|
||||
u"Thank you for choosing Ren'Py.",
|
||||
u"The distributions have been built. Be sure to test them before release.\n\nNote that unpacking and repacking the Macintosh, Linux, or Combined distributions on Windows is not supported.\n\nPlease announce your release at the {a=http://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}, so we can add it to the Ren'Py web site.",
|
||||
u"The editor has been set from the RENPY_EDITOR environment variable, and cannot be changed.",
|
||||
u"Choose Editor",
|
||||
u"Please choose the editor that will be use to edit scripts and display errors. More editors can be downloaded from {a=http://www.renpy.org/wiki/renpy/Editors}the Ren'Py website{/a}.",
|
||||
@@ -154,6 +153,7 @@ init python:
|
||||
u"Something with that name already exists in the projects directory.",
|
||||
u"Creating Project",
|
||||
u"Please wait while we create the project.",
|
||||
u"Could not create the project directory. The error was: %s",
|
||||
u"%s Launcher",
|
||||
u"Launcher Options",
|
||||
u"Using RENPY_EDITOR",
|
||||
@@ -177,7 +177,10 @@ init python:
|
||||
u"Choose Projects Directory",
|
||||
u"Please choose the directory containing your projects.",
|
||||
u"Could not run zenity. The projects directory has been set to the directory immediately above the directory containing Ren'Py.",
|
||||
u"Tutorial Game",
|
||||
u"Launches the Ren'Py tutorial game.",
|
||||
u"Update Ren'Py",
|
||||
u"Updates Ren'Py to the latest version.",
|
||||
u"Now showing the Ren'Py documentation in your web browser.",
|
||||
u"Now showing the Ren'Py Games List in your web browser.",
|
||||
u"Launch",
|
||||
@@ -204,6 +207,11 @@ init python:
|
||||
u"Change Ren'Py launcher options.",
|
||||
u"Ren'Py Help",
|
||||
u"Open the Ren'Py documentation in a web browser.",
|
||||
u"Tutorial Game",
|
||||
u"Retrieving catalog",
|
||||
u"Checking files",
|
||||
u"Making directories.",
|
||||
u"Downloading updated files",
|
||||
u"Renaming files",
|
||||
u"Fixing permissions.",
|
||||
]
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@ init 1 python:
|
||||
# This is a list of (theme name, theme function, theme exemplar) tuples.
|
||||
themes = [
|
||||
("Roundrect", "roundrect", "Basic Blue"),
|
||||
("Bordered", "bordered", "Dramatic Flesh"),
|
||||
("Diamond", "diamond", "Colorblind"),
|
||||
("TV", "tv", "Fine China"),
|
||||
("Glow", "glow", "Really Red"),
|
||||
]
|
||||
|
||||
# This is a map from theme function to template text that sensibly calls
|
||||
@@ -57,6 +61,11 @@ init 1 python:
|
||||
## do so below.
|
||||
)"""
|
||||
|
||||
theme_templates["bordered"] = theme_templates["roundrect"].replace("roundrect", "bordered")
|
||||
theme_templates["diamond"] = theme_templates["roundrect"].replace("roundrect", "diamond")
|
||||
theme_templates["tv"] = theme_templates["roundrect"].replace("roundrect", "tv")
|
||||
theme_templates["glow"] = theme_templates["roundrect"].replace("roundrect", "glow")
|
||||
|
||||
# This is a map from theme name to the code needed to implement that
|
||||
# theme.
|
||||
theme_data = {
|
||||
@@ -66,7 +75,6 @@ init 1 python:
|
||||
'gm_root': '#dcebff',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#dcebff',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#003c78',
|
||||
'widget_hover': '#0050a0',
|
||||
'widget_selected': '#ffffc8',
|
||||
@@ -77,7 +85,6 @@ init 1 python:
|
||||
'gm_root': '#000000',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#000000',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#000000',
|
||||
'widget_hover': '#830000',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -88,7 +95,6 @@ init 1 python:
|
||||
'gm_root': '#393939',
|
||||
'label': '#c2c2c2',
|
||||
'mm_root': '#393939',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#898989',
|
||||
'widget_hover': '#464646',
|
||||
'widget_selected': '#F2F2F2',
|
||||
@@ -99,7 +105,6 @@ init 1 python:
|
||||
'gm_root': '#D0B4BA',
|
||||
'label': '#805C40',
|
||||
'mm_root': '#D0B4BA',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#ECC7D0',
|
||||
'widget_hover': '#E1D4C9',
|
||||
'widget_selected': '#805C40',
|
||||
@@ -110,7 +115,6 @@ init 1 python:
|
||||
'gm_root': '#FDF5E3',
|
||||
'label': '#502F13',
|
||||
'mm_root': '#FDF5E3',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#D96B00',
|
||||
'widget_hover': '#FD9B1C',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -121,7 +125,6 @@ init 1 python:
|
||||
'gm_root': '#2a201f',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#2a201f',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#BF7C51',
|
||||
'widget_hover': '#dda570',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -132,7 +135,6 @@ init 1 python:
|
||||
'gm_root': '#FBF9DF',
|
||||
'label': '#698071',
|
||||
'mm_root': '#FBF9DF',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#F5D4EE',
|
||||
'widget_hover': '#F0DDFF',
|
||||
'widget_selected': '#000000',
|
||||
@@ -143,7 +145,6 @@ init 1 python:
|
||||
'gm_root': '#b0b8ba',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#b0b8ba',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#8699a7',
|
||||
'widget_hover': '#9eb1ad',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -154,7 +155,6 @@ init 1 python:
|
||||
'gm_root': '#F7F7FA',
|
||||
'label': '#39435E',
|
||||
'mm_root': '#F7F7FA',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#6A7183',
|
||||
'widget_hover': '#1A2B47',
|
||||
'widget_selected': '#E3E3E4',
|
||||
@@ -165,7 +165,6 @@ init 1 python:
|
||||
'gm_root': '#D98989',
|
||||
'label': '#5D1010',
|
||||
'mm_root': '#D98989',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#F09898',
|
||||
'widget_hover': '#D6C5BB',
|
||||
'widget_selected': '#B31E1E',
|
||||
@@ -176,7 +175,6 @@ init 1 python:
|
||||
'gm_root': '#E6E6E6',
|
||||
'label': '#D9D9D9',
|
||||
'mm_root': '#E6E6E6',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#D9D9D9',
|
||||
'widget_hover': '#F0F2F2',
|
||||
'widget_selected': '#737373',
|
||||
@@ -187,7 +185,6 @@ init 1 python:
|
||||
'gm_root': '#1A140E',
|
||||
'label': '#F1EBE5',
|
||||
'mm_root': '#1A140E',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#4D3B29',
|
||||
'widget_hover': '#996E45',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -198,7 +195,6 @@ init 1 python:
|
||||
'gm_root': '#1A0001',
|
||||
'label': '#1A0001',
|
||||
'mm_root': '#1A0001',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#777777',
|
||||
'widget_hover': '#73735C',
|
||||
'widget_selected': '#000000',
|
||||
@@ -209,7 +205,6 @@ init 1 python:
|
||||
'gm_root': '#A84A3E',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#A84A3E',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#A89E7D',
|
||||
'widget_hover': '#8DB6B9',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -220,7 +215,6 @@ init 1 python:
|
||||
'gm_root': '#ffd0d0',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#ffd0d0',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#963232',
|
||||
'widget_hover': '#c83232',
|
||||
'widget_selected': '#ffffc8',
|
||||
@@ -231,7 +225,6 @@ init 1 python:
|
||||
'gm_root': '#B4CDD4',
|
||||
'label': '#94C7D4',
|
||||
'mm_root': '#B4CDD4',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#F2E6AA',
|
||||
'widget_hover': '#FCFCA4',
|
||||
'widget_selected': '#1A5766',
|
||||
@@ -242,7 +235,6 @@ init 1 python:
|
||||
'gm_root': '#B09D5A',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#B09B4F',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#753D00',
|
||||
'widget_hover': '#B19A48',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -253,7 +245,6 @@ init 1 python:
|
||||
'gm_root': '#000000',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#000000',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#333333',
|
||||
'widget_hover': '#000000',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -264,7 +255,6 @@ init 1 python:
|
||||
'gm_root': '#695640',
|
||||
'label': '#F2EDC4',
|
||||
'mm_root': '#695640',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#7A674F',
|
||||
'widget_hover': '#BDA77D',
|
||||
'widget_selected': '#FDFBEE',
|
||||
@@ -275,7 +265,6 @@ init 1 python:
|
||||
'gm_root': '#F7F7C5',
|
||||
'label': '#FCFCD7',
|
||||
'mm_root': '#F7F7C5',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#FFE06D',
|
||||
'widget_hover': '#E38A4F',
|
||||
'widget_selected': '#996600',
|
||||
@@ -286,7 +275,6 @@ init 1 python:
|
||||
'gm_root': '#FBF9EA',
|
||||
'label': '#F1EBE5',
|
||||
'mm_root': '#FBF9EA',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#33271C',
|
||||
'widget_hover': '#ECE7C4',
|
||||
'widget_selected': '#ffffff',
|
||||
@@ -297,7 +285,6 @@ init 1 python:
|
||||
'gm_root': '#e5f1e5',
|
||||
'label': '#ffffff',
|
||||
'mm_root': '#e5f1e5',
|
||||
'theme': 'roundrect',
|
||||
'widget': '#7AA27B',
|
||||
'widget_hover': '#A3C7A3',
|
||||
'widget_selected': '#ffffff',
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# This is an early version of an interface for the updater. For now, we just
|
||||
# assume that the user wants to update the prerelease channel, and the
|
||||
# base tag.
|
||||
|
||||
init python:
|
||||
import os
|
||||
import time
|
||||
|
||||
version_fn = os.path.join(config.basedir, "lib", "update-version.txt")
|
||||
update_allowed = os.path.exists(version_fn)
|
||||
|
||||
label update:
|
||||
|
||||
python hide:
|
||||
|
||||
try:
|
||||
info("Checking for update...", "")
|
||||
|
||||
old_version = file(version_fn, "rb").read()
|
||||
updater = Updater(config.basedir, 'http://update.renpy.org/renpy/updates/prerelease', [ 'base' ])
|
||||
|
||||
# Check the version.
|
||||
version, verbose_version = updater.check_version(old_version)
|
||||
|
||||
if version is None:
|
||||
pauseinfo("Up To Date", "Your version of Ren'Py is up to date.")
|
||||
renpy.jump("top")
|
||||
|
||||
|
||||
if not yesno("Update Available", "Would you like to update to %s?" % verbose_version):
|
||||
renpy.jump("top")
|
||||
|
||||
# If we've made it this far, the user has decided that he wants
|
||||
# to try an update.
|
||||
|
||||
for what, amount, limit in updater.step():
|
||||
progress(what, limit, amount)
|
||||
|
||||
f = file(version_fn, "wb")
|
||||
f.write(version)
|
||||
f.close()
|
||||
|
||||
pauseinfo("Update complete.", "The update has finished. Ren'Py will now restart.")
|
||||
|
||||
if sys.platform == "win32" and sys.argv[0].lower().endswith(".exe"):
|
||||
proc = subprocess.Popen([sys.argv[0], config.basedir])
|
||||
else:
|
||||
proc = subprocess.Popen([sys.executable, sys.argv[0], config.basedir])
|
||||
|
||||
renpy.quit()
|
||||
|
||||
|
||||
except UpdateException, e:
|
||||
error('The update has failed, with the error message: %s' % e.args[0])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
init python:
|
||||
|
||||
import urllib2
|
||||
import bz2
|
||||
import os
|
||||
import hashlib
|
||||
import public
|
||||
|
||||
class UpdateException(Exception):
|
||||
"""
|
||||
The exception that we return if the update fails.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
class Updater(object):
|
||||
"""
|
||||
A class that attempts to update a tree of files, with a reasonable
|
||||
degree of safety, security, speed, and progress reporting.
|
||||
"""
|
||||
|
||||
def __init__(self, local, remote, tags):
|
||||
"""
|
||||
Create a new updater.
|
||||
|
||||
`local`
|
||||
The name of the local directory where the files are stored.
|
||||
`remote`
|
||||
The remote url base.
|
||||
`tags`
|
||||
A list of tags to update.
|
||||
"""
|
||||
|
||||
self.local = local
|
||||
self.remote = remote
|
||||
|
||||
# The remote version we're upgrading to.
|
||||
self.version = None
|
||||
|
||||
# A list of directory names.
|
||||
self.directories = [ ]
|
||||
|
||||
# A list of file, bz2-size, adler32 tuples.
|
||||
self.files = [ ]
|
||||
|
||||
# Xbit files.
|
||||
self.xbit = [ ]
|
||||
|
||||
# The tags we use.
|
||||
self.tags = set(tags)
|
||||
|
||||
def snarf(self, url):
|
||||
"""
|
||||
Gets the url as a string.
|
||||
"""
|
||||
|
||||
url = self.remote + "/" + url
|
||||
|
||||
try:
|
||||
u = urllib2.urlopen(url, None, 5)
|
||||
return u.read()
|
||||
except Exception, e:
|
||||
raise UpdateException("Could not download %r: %r" % (url, e))
|
||||
|
||||
def retrieve(self, relative):
|
||||
"""
|
||||
Downloads the bz2-compressed file, and then decompresses it into
|
||||
relative.new.
|
||||
"""
|
||||
|
||||
bz = os.path.join(self.local, relative + ".new.bz2")
|
||||
new = os.path.join(self.local, relative + ".new")
|
||||
|
||||
url = self.remote + "/" + relative + ".bz2"
|
||||
|
||||
try:
|
||||
u = urllib2.urlopen(url, None, 5)
|
||||
|
||||
f = file(bz, "wb")
|
||||
f.write(u.read())
|
||||
f.close()
|
||||
|
||||
u.close()
|
||||
|
||||
bzf = bz2.BZ2File(bz, "rb")
|
||||
f = file(new, "wb")
|
||||
|
||||
while True:
|
||||
buf = bzf.read(1024 * 1024)
|
||||
|
||||
if not buf:
|
||||
break
|
||||
|
||||
f.write(buf)
|
||||
|
||||
f.close()
|
||||
bzf.close()
|
||||
|
||||
os.unlink(bz)
|
||||
|
||||
except Exception, e:
|
||||
raise UpdateException("Could not download %r: %r" % (url, e))
|
||||
|
||||
|
||||
def check_version(self, version):
|
||||
"""
|
||||
Checks to see if version is still up to date. Returns a new-version,
|
||||
verbose-version string. new-version is an internal representation
|
||||
of the version being downloaded, while verbose-version is a
|
||||
string that can be presented to the user.
|
||||
|
||||
The `version` argument should be given the new-version returned
|
||||
from the last successful update. new-version is None if we are
|
||||
up to date.
|
||||
"""
|
||||
|
||||
remote_version = self.snarf("version")
|
||||
|
||||
self.version, verbose_version = remote_version.split("\n", 1)
|
||||
self.version += " " + " ".join(sorted(self.tags))
|
||||
|
||||
if self.version.strip() == version.strip():
|
||||
return None, verbose_version
|
||||
else:
|
||||
return self.version, verbose_version
|
||||
|
||||
def verify_hash(self, relative, digest):
|
||||
"""
|
||||
Verifies that the file `relative` has the hash value `digest`.
|
||||
"""
|
||||
|
||||
fn = os.path.join(self.local, relative)
|
||||
|
||||
if not os.path.exists(fn):
|
||||
return False
|
||||
|
||||
hash = hashlib.sha256()
|
||||
|
||||
try:
|
||||
f = file(fn, "rb")
|
||||
|
||||
while True:
|
||||
data = f.read(1024 * 1024)
|
||||
|
||||
if not data:
|
||||
break
|
||||
|
||||
if not "renpy.app" in fn:
|
||||
if fn.endswith(".rpy") or fn.endswith(".rpym") or fn.endswith(".py") or fn.endswith(".txt"):
|
||||
data = data.replace("\n", "\r\n")
|
||||
data = data.replace("\r\r\n", "\r\n")
|
||||
|
||||
hash.update(data)
|
||||
|
||||
f.close()
|
||||
|
||||
except:
|
||||
return False
|
||||
|
||||
return hash.hexdigest() == digest
|
||||
|
||||
|
||||
def get_catalog(self):
|
||||
"""
|
||||
Downloads the catalog file from the server, checking the signature
|
||||
as necessary.
|
||||
"""
|
||||
|
||||
self.retrieve("catalog1")
|
||||
catalog_fn = os.path.join(self.local, "catalog1.new")
|
||||
|
||||
verified = False
|
||||
|
||||
try:
|
||||
hash = hashlib.sha256()
|
||||
|
||||
f = file(catalog_fn, "rb")
|
||||
|
||||
# Read control information.
|
||||
for l in f:
|
||||
if l[0] == "-":
|
||||
break
|
||||
|
||||
hash.update(l)
|
||||
|
||||
l = l[:-1]
|
||||
|
||||
a = l.split("\t")
|
||||
|
||||
if a[0] == "file":
|
||||
cmd, digest, size, tag, name = a
|
||||
|
||||
if tag in self.tags:
|
||||
self.files.append((name, digest, int(size)))
|
||||
|
||||
elif a[0] == "dir":
|
||||
cmd, tag, name = a
|
||||
|
||||
if tag in self.tags:
|
||||
self.directories.append(name)
|
||||
|
||||
elif a[0] == "xbit":
|
||||
cmd, name = a
|
||||
self.xbit.append(name)
|
||||
|
||||
else:
|
||||
raise UpdateException("Unknown upgrade command: %r" % l)
|
||||
|
||||
# Compute the unsigned message.
|
||||
unsigned = int("01" + hash.hexdigest(), 16)
|
||||
|
||||
for l in f:
|
||||
a = l[:-1].split("\t")
|
||||
|
||||
if a[0] != "signature":
|
||||
continue
|
||||
|
||||
signature = int(a[1], 16)
|
||||
if pow(signature, public.exponent, public.modulus) == unsigned:
|
||||
verified = True
|
||||
|
||||
f.close()
|
||||
os.unlink(catalog_fn)
|
||||
|
||||
except UpdateException:
|
||||
raise
|
||||
except Exception, e:
|
||||
raise UpdateException("Could not download catalog: %r" % (e,))
|
||||
|
||||
if not verified:
|
||||
raise UpdateException("Could not verify catalog signature.")
|
||||
|
||||
|
||||
def step(self):
|
||||
"""
|
||||
This is a generator that performs the steps in the update
|
||||
process. It yields a (message, complete, total) tuple for
|
||||
each step, and terminates upon success.
|
||||
"""
|
||||
|
||||
yield (u"Retrieving catalog", 0, 1)
|
||||
self.get_catalog()
|
||||
|
||||
updated_files = [ ]
|
||||
download_size = 0
|
||||
|
||||
for i, (name, hash, size) in enumerate(self.files):
|
||||
yield (u"Checking files", i, len(self.files))
|
||||
|
||||
if not self.verify_hash(name, hash):
|
||||
updated_files.append((name, hash, size))
|
||||
download_size += size
|
||||
|
||||
complete_size = 0
|
||||
|
||||
# Todo: Make directories.
|
||||
|
||||
for i, dir in enumerate(self.directories):
|
||||
|
||||
yield (u"Making directories", i, len(self.directories))
|
||||
|
||||
dir = os.path.join(self.local, dir)
|
||||
|
||||
if not os.path.exists(dir):
|
||||
try:
|
||||
os.mkdir(dir)
|
||||
except:
|
||||
raise UpdateException("Couldn't make directory %r." % dir)
|
||||
|
||||
complete = 0
|
||||
|
||||
for name, hash, size in updated_files:
|
||||
|
||||
yield (u"Downloading updated files", complete, len(updated_files))
|
||||
|
||||
if self.verify_hash(name + ".new", hash):
|
||||
complete_size += size
|
||||
continue
|
||||
|
||||
self.retrieve(name)
|
||||
|
||||
if not self.verify_hash(name + ".new", hash):
|
||||
raise UpdateException("Could not verify download of %r." % name)
|
||||
|
||||
complete_size += size
|
||||
complete += 1
|
||||
|
||||
umask = os.umask(0)
|
||||
os.umask(umask)
|
||||
|
||||
for i, (name, hash, size) in enumerate(updated_files):
|
||||
|
||||
yield (u"Renaming files", i, len(updated_files))
|
||||
|
||||
fn = os.path.join(self.local, name)
|
||||
|
||||
if os.path.exists(fn + ".old"):
|
||||
os.unlink(fn + ".old")
|
||||
|
||||
if os.path.exists(fn):
|
||||
os.rename(fn, fn + ".old")
|
||||
|
||||
os.rename(fn + ".new", fn)
|
||||
|
||||
if fn.endswith(".py") and os.path.exists(fn + 'o'):
|
||||
os.unlink(fn + 'o')
|
||||
|
||||
for i, name in enumerate(self.xbit):
|
||||
yield (u"Fixing permissions", i, len(self.xbit))
|
||||
|
||||
fn = os.path.join(self.local, name)
|
||||
|
||||
if os.path.exists(fn):
|
||||
os.chmod(fn, 0777 & (~umask))
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
|
||||
# up = Updater("/tmp/renpy-1", "file:///tmp/renpy-6.11.0", [ "base" ])
|
||||
# version, verbose_version = up.check_version(1)
|
||||
|
||||
# for message, done, total in up.step():
|
||||
# print message, "(%d/%d)" % (done, total)
|
||||
|
||||
# print version
|
||||
# print verbose_version
|
||||
|
||||
|
||||
@@ -1,534 +0,0 @@
|
||||
# This file contains the code needed to build a Ren'Py distribution.
|
||||
|
||||
init python:
|
||||
import zipfile
|
||||
import tarfile
|
||||
import os
|
||||
import os.path
|
||||
import time
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
import pefile
|
||||
|
||||
# Returns true if a file or directory should not be included in
|
||||
# the distribution
|
||||
|
||||
ignored_files = ("thumbs.db",
|
||||
"launcherinfo.py",
|
||||
"traceback.txt",
|
||||
"errors.txt",
|
||||
"icon.ico",
|
||||
"icon.icns"
|
||||
)
|
||||
|
||||
|
||||
root_ignored_files = (
|
||||
"common",
|
||||
"renpy",
|
||||
"renpy.code",
|
||||
"python23.dll",
|
||||
"python24.dll",
|
||||
"python25.dll",
|
||||
"msvcr71.dll",
|
||||
"lib",
|
||||
"iliad-icon.png",
|
||||
"manifest.xml"
|
||||
)
|
||||
|
||||
def ignored(fn, dir, dest, root):
|
||||
if fn[0] == ".":
|
||||
return True
|
||||
|
||||
for i in store.ignore_extensions:
|
||||
if fn.endswith(i):
|
||||
return True
|
||||
|
||||
if fn.lower() in ignored_files:
|
||||
return True
|
||||
|
||||
if fn == "saves":
|
||||
return True
|
||||
|
||||
if fn == "archived":
|
||||
return True
|
||||
|
||||
if root and dir == dest:
|
||||
if fn.endswith(".py") or fn.endswith(".sh") or fn.endswith(".app"):
|
||||
return True
|
||||
|
||||
if fn in root_ignored_files:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def tree(src, dest,
|
||||
exclude_suffix=[ ".pyc", "~", ".bak" ],
|
||||
exclude_prefix=[ ".", '#' ],
|
||||
exclude=ignored_files,
|
||||
exclude_func=ignored,
|
||||
root=False,
|
||||
):
|
||||
|
||||
# Get rid of trailing slashes.
|
||||
if src[-1] == "/":
|
||||
src = src[:-1]
|
||||
|
||||
if dest and dest[-1] == "/":
|
||||
dest = dest[:-1]
|
||||
|
||||
# What should we include?
|
||||
def include(fn, destdir, dest):
|
||||
for i in exclude_suffix:
|
||||
if fn.endswith(i):
|
||||
return False
|
||||
|
||||
for i in exclude_prefix:
|
||||
if fn.startswith(i):
|
||||
return False
|
||||
|
||||
for i in exclude:
|
||||
if i == fn.lower():
|
||||
return False
|
||||
|
||||
if exclude_func and exclude_func(fn, destdir, dest, root):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
rv = [ ]
|
||||
|
||||
# Walk the tree, including what is necessary.
|
||||
for srcdir, dirs, files in os.walk(src):
|
||||
|
||||
if dest:
|
||||
destdir = dest + srcdir[len(src):]
|
||||
else:
|
||||
destdir = srcdir[len(src) + 1:]
|
||||
|
||||
if destdir:
|
||||
rv.append((srcdir, destdir))
|
||||
|
||||
for fn in files:
|
||||
|
||||
if not include(fn, destdir, dest):
|
||||
continue
|
||||
|
||||
sfn = srcdir + "/" + fn
|
||||
|
||||
if destdir:
|
||||
dfn = destdir + "/" + fn
|
||||
else:
|
||||
dfn = fn
|
||||
|
||||
dfn = dfn.replace("\\", "/")
|
||||
|
||||
rv.append((sfn, dfn))
|
||||
|
||||
dirs[:] = [ i for i in dirs if include(i, destdir, dest) ]
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
label distribute:
|
||||
|
||||
python hide:
|
||||
zlib.Z_DEFAULT_COMPRESSION = 9
|
||||
|
||||
store.progress_time = 0
|
||||
|
||||
def progress(tit, n, m, time=time):
|
||||
|
||||
if time.time() < store.progress_time + .1:
|
||||
return
|
||||
|
||||
title(tit)
|
||||
|
||||
mid(message)
|
||||
ui.bar(m, n, xmaximum=200, xalign=0.5)
|
||||
ui.close()
|
||||
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
# Check to see which platforms we can build on.
|
||||
if os.path.exists(config.renpy_base + "/renpy.exe"):
|
||||
windows = True
|
||||
else:
|
||||
windows = False
|
||||
|
||||
if os.path.exists(config.renpy_base + "/lib/linux-x86"):
|
||||
linux = True
|
||||
else:
|
||||
linux = False
|
||||
|
||||
if os.path.exists(config.renpy_base + "/lib/linux-iliad"):
|
||||
iliad = True
|
||||
else:
|
||||
iliad = False
|
||||
|
||||
if os.path.exists(config.renpy_base + "/renpy.app"):
|
||||
mac = True
|
||||
else:
|
||||
mac = False
|
||||
|
||||
if not (windows or mac or linux or iliad):
|
||||
store.error(u"Can't Distribute", u"Ren'Py is missing files required for distribution. Please download the full package from {a=http://www.renpy.org/}www.renpy.org{/a}.", "tools_menu")
|
||||
|
||||
lint()
|
||||
|
||||
store.message = ""
|
||||
|
||||
title(_(u"Building Distributions"))
|
||||
|
||||
mid()
|
||||
text(u"I've just performed a lint on your project. If it contains errors, you should say no and fix them.\nCheck {a=http://www.renpy.org/wiki/renpy/Download_Ren'Py}www.renpy.org{/a} to see if updates or fixes are available.\n\nDo you want to continue?")
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button(u"Yes", clicked=ui.returns(True))
|
||||
button(u"No", clicked=ui.returns(False))
|
||||
ui.close()
|
||||
|
||||
if not interact():
|
||||
renpy.jump("tools")
|
||||
|
||||
|
||||
# if not windows or not mac or not linux:
|
||||
# store.message = "The full version of Ren'Py can build for Windows, Mac, and Linux. Download it from www.renpy.org."
|
||||
|
||||
title(u"Building Distributions")
|
||||
|
||||
mid()
|
||||
text(u"Distributions will be built for the following platforms:")
|
||||
|
||||
spacer()
|
||||
|
||||
if windows:
|
||||
text(u"Windows 2000+", style='launcher_input')
|
||||
|
||||
if linux:
|
||||
text(u"Linux x86", style='launcher_input')
|
||||
|
||||
if iliad:
|
||||
text(u"iLiad", style='launcher_input')
|
||||
|
||||
if mac:
|
||||
text(u"Mac OS X 10.4+", style='launcher_input')
|
||||
|
||||
spacer()
|
||||
|
||||
|
||||
# TODO: If missing platforms, prompt for a DL.
|
||||
|
||||
text(u"Is this okay?")
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button(u"Yes", clicked=ui.returns(True))
|
||||
button(u"No", clicked=ui.returns(False))
|
||||
ui.close()
|
||||
|
||||
if not interact():
|
||||
renpy.jump("tools")
|
||||
|
||||
default_name = project.info.get('distribution_base', project.name)
|
||||
|
||||
name = prompt(u"Building Distributions",
|
||||
u"Please enter a base name for the directories making up this distribution.",
|
||||
"tools",
|
||||
default_name,
|
||||
u"This usually should include a name and version number, like 'moonlight_walks-1.0'.")
|
||||
|
||||
name = name.strip()
|
||||
|
||||
if not name:
|
||||
store.error(u"Error", u"The distribution name should not be empty.", "tools_menu")
|
||||
|
||||
try:
|
||||
name = name.encode("ascii")
|
||||
except:
|
||||
store.error(u"Error", u"Distribution names must be ASCII. This is because archive file formats do not support non-ASCII characters in a uniform way.", "tools_menu")
|
||||
|
||||
project.info['distribution_base'] = name
|
||||
|
||||
ignore_extensions = project.info.get('ignore_extensions', "~ .bak")
|
||||
ignore_extensions = prompt(u"Building Distributions", u"Please enter a space separated list of the file extensions you do not want included in the distribution.", "tools", ignore_extensions)
|
||||
store.ignore_extensions = [ i.strip() for i in ignore_extensions.strip().split() ]
|
||||
project.info['ignore_extensions'] = ignore_extensions
|
||||
|
||||
project.save()
|
||||
|
||||
# Figure out the files that will make up the distribution.
|
||||
|
||||
multi = [ ]
|
||||
|
||||
# This finds the files and directories in the tree, and includes
|
||||
# them in the result.
|
||||
|
||||
|
||||
# renpy and common directories.
|
||||
multi.extend(tree(config.renpy_base + "/renpy", "renpy"))
|
||||
multi.append((config.renpy_base + "/LICENSE.txt", "renpy/LICENSE.txt"))
|
||||
multi.extend(tree(config.commondir, "common"))
|
||||
|
||||
# Include the project.
|
||||
multi.extend(tree(project.path, '',
|
||||
exclude_suffix = [ ],
|
||||
exclude_prefix = [ ],
|
||||
exclude=[ ],
|
||||
root=True))
|
||||
|
||||
shortgamedir = project.gamedir[len(project.path)+1:]
|
||||
|
||||
|
||||
def add_script_version(fn, multi=multi, shortgamedir=shortgamedir):
|
||||
|
||||
for a, b in multi:
|
||||
if b == shortgamedir + "/" + fn:
|
||||
return
|
||||
|
||||
for i in store.ignore_extensions:
|
||||
if fn.endswith(i):
|
||||
return
|
||||
|
||||
multi.append((config.gamedir + "/" + fn, shortgamedir + "/" + fn))
|
||||
|
||||
add_script_version("script_version.rpy")
|
||||
add_script_version("script_version.rpyc")
|
||||
|
||||
# renpy.py
|
||||
multi.append((config.renpy_base + "/renpy.py",
|
||||
project.name + ".py"))
|
||||
|
||||
# Windows Zip
|
||||
if windows:
|
||||
win_files = [
|
||||
( config.renpy_base + "/renpy.exe", project.name + ".exe"),
|
||||
( config.renpy_base + "/renpy.code", "renpy.code" ),
|
||||
( config.renpy_base + "/python25.dll", "python25.dll" ),
|
||||
( config.renpy_base + "/msvcr71.dll", "msvcr71.dll" ),
|
||||
]
|
||||
|
||||
win_data = { }
|
||||
if os.path.exists(project.path + "/icon.ico"):
|
||||
win_data[project.name + ".exe"] = pefile.change_icons(
|
||||
config.renpy_base + "/renpy.exe",
|
||||
project.path + "/icon.ico",
|
||||
)
|
||||
|
||||
zf = zipfile.ZipFile(name + ".zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
progress_len = len(multi) + len(win_files)
|
||||
store.message = u"Be sure to announce your project at the Lemma Soft Forums."
|
||||
|
||||
for i, (fn, an) in enumerate(multi + win_files):
|
||||
progress(u"Building Windows", i, progress_len)
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
zi = zipfile.ZipInfo(name + "/" + an)
|
||||
|
||||
s = os.stat(fn)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
zi.external_attr = long(0100666) << 16
|
||||
data = file(fn, "rb").read()
|
||||
|
||||
data = win_data.get(an, data)
|
||||
|
||||
zf.writestr(zi, data)
|
||||
|
||||
|
||||
zf.close()
|
||||
|
||||
|
||||
# Linux Tar Bz2
|
||||
if linux:
|
||||
|
||||
linux_files = [
|
||||
(config.renpy_base + "/lib/linux-x86", "lib/linux-x86"),
|
||||
(config.renpy_base + "/renpy.sh", project.name + ".sh"),
|
||||
(config.renpy_base + "/lib/python", "lib/python"),
|
||||
]
|
||||
|
||||
|
||||
linux_files.extend(tree(config.renpy_base + "/lib/linux-x86", "lib/linux-x86"))
|
||||
|
||||
tf = tarfile.open(name + "-linux-x86.tar.bz2", "w:bz2")
|
||||
tf.dereference = True
|
||||
|
||||
progress_len = len(multi) + len(linux_files)
|
||||
store.message = u"If appropriate, please submit your game to www.renai.us."
|
||||
|
||||
for j, i in enumerate(multi + linux_files):
|
||||
|
||||
progress(u"Building Linux", j, progress_len)
|
||||
|
||||
fn, an = i
|
||||
|
||||
info = tf.gettarinfo(fn, name + "-linux-x86/" + an)
|
||||
|
||||
if info.isdir():
|
||||
perms = 0777
|
||||
elif info.name.endswith(".sh"):
|
||||
perms = 0777
|
||||
elif info.name.endswith(".so"):
|
||||
perms = 0777
|
||||
elif info.name.endswith("python"):
|
||||
perms = 0777
|
||||
elif info.name.endswith("python.real"):
|
||||
perms = 0777
|
||||
else:
|
||||
perms = 0666
|
||||
|
||||
info.mode = perms
|
||||
info.uid = 1000
|
||||
info.gid = 1000
|
||||
info.uname = "renpy"
|
||||
info.gname = "renpy"
|
||||
|
||||
if info.isreg():
|
||||
tf.addfile(info, file(fn, "rb"))
|
||||
else:
|
||||
tf.addfile(info)
|
||||
|
||||
tf.close()
|
||||
|
||||
|
||||
# iLiad Tar Bz2
|
||||
if iliad:
|
||||
|
||||
iliad_files = [
|
||||
(config.renpy_base + "/lib", "lib"),
|
||||
(config.renpy_base + "/renpy-iliad.sh", project.name + ".sh"),
|
||||
(config.renpy_base + "/lib/python", "lib/python"),
|
||||
(config.renpy_base + "/manifest.xml", "manifest.xml"),
|
||||
(config.renpy_base + "/iliad-icon.png", "iliad-icon.png"),
|
||||
]
|
||||
|
||||
iliad_files.extend(tree(config.renpy_base + "/lib/linux-iliad", "lib/linux-iliad"))
|
||||
|
||||
iliad_data = { }
|
||||
|
||||
manifest = file(config.renpy_base + "/manifest.xml", "r").read()
|
||||
manifest = manifest.replace("GAMENAME", project.name)
|
||||
iliad_data["manifest.xml"] = manifest
|
||||
|
||||
zf = zipfile.ZipFile(name + "-iLiad.zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
progress_len = len(multi) + len(iliad_files)
|
||||
store.message = u"We thank Hixbooks for sponsoring iLiad support."
|
||||
|
||||
for i, (fn, an) in enumerate(multi + iliad_files):
|
||||
|
||||
progress(u"Building iLiad", i, progress_len)
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
zi = zipfile.ZipInfo(project.name + "/" + an)
|
||||
|
||||
s = os.stat(fn)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
for ext in [ ".sh", ".so", "python", "python.real" ]:
|
||||
if fn.endswith(ext):
|
||||
zi.external_attr = long(0100777) << 16
|
||||
data = file(fn, "rb").read()
|
||||
break
|
||||
else:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
data = file(fn, "rb").read()
|
||||
|
||||
data = iliad_data.get(an, data)
|
||||
zf.writestr(zi, data)
|
||||
|
||||
zf.close()
|
||||
|
||||
if mac:
|
||||
|
||||
mac_files = tree(config.renpy_base + "/renpy.app",
|
||||
project.name + ".app")
|
||||
|
||||
mac_files = [ (fn, an.replace("Ren'Py Launcher", project.name)) for (fn, an) in mac_files ]
|
||||
|
||||
# Data replacement for macintosh.
|
||||
mac_data = { }
|
||||
|
||||
quoted_name = project.name.replace("&", "&").replace("<", "<")
|
||||
info_plist = file(config.renpy_base + "/renpy.app/Contents/Info.plist", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
mac_data[project.name + ".app/Contents/Info.plist"] = info_plist
|
||||
|
||||
quoted_name = project.name.replace("\"", "\\\"")
|
||||
launcher_py = file(config.renpy_base + "/renpy.app/Contents/Resources/launcher.py", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
mac_data[project.name + ".app/Contents/Resources/launcher.py"] = launcher_py
|
||||
|
||||
if os.path.exists(project.path + "/icon.icns"):
|
||||
icon_data = file(project.path + "/icon.icns", "rb").read()
|
||||
mac_data[project.name + ".app/Contents/Resources/launcher.icns"] = icon_data
|
||||
|
||||
zf = zipfile.ZipFile(name + "-mac.zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
progress_len = len(multi) + len(mac_files)
|
||||
store.message = u"Thank you for choosing Ren'Py."
|
||||
|
||||
for i, (fn, an) in enumerate(multi + mac_files):
|
||||
|
||||
progress(u"Building Mac OS X", i, progress_len)
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
zi = zipfile.ZipInfo(name + "-mac/" + an)
|
||||
|
||||
s = os.stat(fn)
|
||||
zi.date_time = time.gmtime(s.st_mtime)[:6]
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.create_system = 3
|
||||
|
||||
if os.path.dirname(fn).endswith("MacOS") or fn.endswith(".so") or fn.endswith(".dylib"):
|
||||
zi.external_attr = long(0100777) << 16
|
||||
data = file(fn, "rb").read()
|
||||
else:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
data = file(fn, "rb").read()
|
||||
|
||||
data = mac_data.get(an, data)
|
||||
zf.writestr(zi, data)
|
||||
|
||||
zf.close()
|
||||
|
||||
|
||||
# Announce Success
|
||||
|
||||
store.message = ""
|
||||
|
||||
title(u"Success")
|
||||
|
||||
mid()
|
||||
text(u"The distribution(s) have been built. Be sure to test them before release.")
|
||||
|
||||
spacer()
|
||||
|
||||
if mac:
|
||||
text(u"Note that unpacking and repacking Mac zips and Linux tarballs on Windows isn't supported.")
|
||||
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button(u"Return", clicked=ui.returns(True))
|
||||
ui.close()
|
||||
|
||||
interact()
|
||||
|
||||
|
||||
jump tools
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# This file contains logic for detecting an editor, and for selecting
|
||||
# the default editor.
|
||||
|
||||
init:
|
||||
python hide:
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
if not config.editor:
|
||||
|
||||
editor = os.path.normpath(config.renpy_base + "/jedit/jedit.jar")
|
||||
|
||||
if os.path.exists(editor):
|
||||
|
||||
editor = renpy.shell_escape(editor)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
config.editor = 'javaw.exe -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
config.editor_transient = 'javaw.exe -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
else:
|
||||
config.editor = 'java -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
config.editor_transient = 'java -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
|
||||
if config.editor:
|
||||
os.environ['RENPY_EDITOR'] = config.editor
|
||||
if config.editor_transient:
|
||||
os.environ['RENPY_EDITOR_TRANSIENT'] = config.editor_transient
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,792 +0,0 @@
|
||||
python early:
|
||||
config.save_directory = "launcher-1"
|
||||
|
||||
init:
|
||||
|
||||
python:
|
||||
# Set up the window.
|
||||
config.screen_width = 350
|
||||
config.screen_height = 450
|
||||
config.window_title = "Ren'Py Launcher"
|
||||
|
||||
# Disable sound and joystick.
|
||||
config.sound = False
|
||||
config.joystick = False
|
||||
|
||||
# Disables autosave (we can't save/load)
|
||||
config.has_autosave = False
|
||||
|
||||
# Create some launcher styles.
|
||||
style.create('launcher_button', 'button')
|
||||
style.create('launcher_button_text', 'button_text')
|
||||
style.create('launcher_title_label', 'default')
|
||||
style.create('launcher_label', 'default')
|
||||
style.create('launcher_input', 'default')
|
||||
style.create('launcher_text', 'default')
|
||||
style.create('launcher_bottom_vbox', 'vbox')
|
||||
style.create('launcher_mid_vbox', 'vbox')
|
||||
|
||||
style_backup = renpy.style.backup()
|
||||
|
||||
_launcher_per_page = 8
|
||||
|
||||
# Choose the roundrect theme for the buttons.
|
||||
layout.compat()
|
||||
theme.roundrect(launcher=True)
|
||||
|
||||
style.hyperlink_text.color = "#0ff"
|
||||
|
||||
config.underlay = [
|
||||
renpy.Keymap(
|
||||
quit = renpy.quit_event,
|
||||
iconify = renpy.iconify,
|
||||
)
|
||||
]
|
||||
|
||||
def quote(c):
|
||||
n = ord(c)
|
||||
if 0x20 <= n <= 0x7f:
|
||||
return c
|
||||
else:
|
||||
return "\\x%02x" % n
|
||||
|
||||
def ifrw(label):
|
||||
if project.info.get("ro", False):
|
||||
return None
|
||||
else:
|
||||
return ui.jumps(label)
|
||||
|
||||
# We don't want the user going into the game menu.
|
||||
def interact():
|
||||
ui.window(background=Solid("#0008"), ypos=1.0, yminimum=80, xmargin=0, ymargin=0)
|
||||
ui.null()
|
||||
|
||||
ui.image("eileen_small.png", xalign=0.0, yalign=1.0)
|
||||
ui.add(DynamicDisplayable("Text(_(store.message), size=14, color='#fff', xpos=100, ypos=375, xmaximum=240)"))
|
||||
ui.text(renpy.version(), xalign=0, yalign=1.0, size=12, color='#000')
|
||||
|
||||
return ui.interact()
|
||||
|
||||
def title(name):
|
||||
ui.window(style='mm_root')
|
||||
ui.null()
|
||||
|
||||
ui.frame(xminimum=350, yminimum=370)
|
||||
ui.viewport(child_size=(2000, None), draggable=True, ymaximum=34)
|
||||
_label_factory(name, "launcher_title", size=28)
|
||||
|
||||
# ui.text(name, xpos=4, ypos=4, size=30, color="#559")
|
||||
|
||||
def text(name, style="launcher_text"):
|
||||
ui.text(_(name), style=style)
|
||||
|
||||
def label(name):
|
||||
_label_factory(name, "launcher")
|
||||
|
||||
def spacer():
|
||||
ui.add(Null(1, 6))
|
||||
|
||||
def mid(focus="mid"):
|
||||
ui.vbox(style='launcher_mid_vbox', focus=focus)
|
||||
|
||||
def bottom(focus="bottom"):
|
||||
ui.vbox(style='launcher_bottom_vbox', focus=focus)
|
||||
|
||||
def button(text, hover_text=None, clicked=None, hovered=None, selected=False):
|
||||
if hover_text:
|
||||
def hovered(hover_text=_(hover_text)):
|
||||
if store.message != hover_text:
|
||||
store.message = hover_text
|
||||
renpy.restart_interaction()
|
||||
|
||||
# ui.button(clicked=clicked, hovered=hovered)
|
||||
# ui.text(text, style="button_text")
|
||||
_button_factory(text, 'launcher', clicked=clicked, hovered=hovered, selected=selected, xmaximum=200)
|
||||
|
||||
|
||||
def prompt(name, message, cancel, default='', hint=''):
|
||||
store.message = _(hint)
|
||||
|
||||
# Creating the project.
|
||||
title(name)
|
||||
|
||||
mid()
|
||||
|
||||
text(message)
|
||||
|
||||
ui.input(default, exclude='{}/\\', style='launcher_input')
|
||||
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button("Cancel", clicked=ui.jumps("main"))
|
||||
ui.close()
|
||||
|
||||
return interact()
|
||||
|
||||
def error(name, message, target):
|
||||
store.message = ''
|
||||
|
||||
# Creating the project.
|
||||
title(name)
|
||||
|
||||
mid()
|
||||
text(message)
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button("Cancel", clicked=ui.jumps(target))
|
||||
ui.close()
|
||||
|
||||
return interact()
|
||||
|
||||
|
||||
def paged_menu(tit, choices, message, per_page=None, cancel='main'):
|
||||
|
||||
if per_page is None:
|
||||
per_page = _launcher_per_page
|
||||
|
||||
page = 0
|
||||
pages = (len(choices) - 1) / per_page
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
store.message = message
|
||||
|
||||
title(tit)
|
||||
|
||||
mid(focus="paged_menu")
|
||||
|
||||
for name, desc, ret, hovered, selected in choices[page * per_page:(page + 1) * per_page]:
|
||||
if len(name) > 19:
|
||||
name = name[:18] + u"\u2026"
|
||||
button(name, desc, clicked=ui.returns(("return", ret)), hovered=hovered, selected=selected)
|
||||
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
|
||||
if pages >= 1:
|
||||
|
||||
if page < pages:
|
||||
button(u"Next Page", u"Go to the next page of projects.", clicked=ui.returns(("page", page + 1)))
|
||||
else:
|
||||
button(u"Next Page")
|
||||
|
||||
if page > 0:
|
||||
button(u"Previous Page", u"Go to the previous page of projects.", clicked=ui.returns(("page", page - 1)))
|
||||
else:
|
||||
button(u"Previous Page")
|
||||
|
||||
button(u"Cancel", u"Return to the top menu.", ui.jumps(cancel))
|
||||
|
||||
ui.close()
|
||||
|
||||
cmd, arg = interact()
|
||||
|
||||
if cmd == "repeat":
|
||||
continue
|
||||
|
||||
if cmd == "page":
|
||||
page = arg
|
||||
continue
|
||||
|
||||
if cmd == "return":
|
||||
return arg
|
||||
|
||||
class ProcessBehavior(renpy.display.layout.Null):
|
||||
|
||||
def __init__(self, proc):
|
||||
super(ProcessBehavior, self).__init__()
|
||||
|
||||
self.proc = proc
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if self.proc.poll() is not None:
|
||||
return True
|
||||
|
||||
renpy.game.interface.timeout(.25)
|
||||
|
||||
class Project(object):
|
||||
def __init__(self, name, path, gamedir, info):
|
||||
# name
|
||||
self.name = name
|
||||
|
||||
# path to project
|
||||
self.path = path
|
||||
|
||||
# gamedir
|
||||
self.gamedir = gamedir
|
||||
|
||||
self.info = info
|
||||
|
||||
import re
|
||||
|
||||
def upper(m):
|
||||
return m.group(0).upper()
|
||||
|
||||
title = re.sub(r'^.', upper, name)
|
||||
title = re.sub(r'\s+\S', upper, title)
|
||||
self.title = title
|
||||
|
||||
def save(self):
|
||||
import os
|
||||
|
||||
f = file(self.path + "/" + "launcherinfo.py.new", "w")
|
||||
for k, v in self.info.iteritems():
|
||||
f.write("%s = %r\n" % (k, v))
|
||||
f.close()
|
||||
|
||||
try:
|
||||
os.rename(self.path + "/launcherinfo.py.new", self.path + "/launcherinfo.py")
|
||||
except:
|
||||
os.unlink(self.path + "/launcherinfo.py")
|
||||
os.rename(self.path + "/launcherinfo.py.new", self.path + "/launcherinfo.py")
|
||||
|
||||
|
||||
def load_project(dir, name):
|
||||
import os.path
|
||||
|
||||
# Ignore unicode files.
|
||||
for i in name:
|
||||
if ord(i) >= 127:
|
||||
return
|
||||
|
||||
if os.path.isdir(dir + "/game"):
|
||||
gamedir = dir + "/game"
|
||||
elif os.path.isdir(dir + "/data"):
|
||||
gamedir = dir + "/data"
|
||||
else:
|
||||
return
|
||||
|
||||
desc = u""
|
||||
|
||||
info = dict()
|
||||
info["description"] = desc
|
||||
|
||||
if os.path.exists(dir + "/launcherinfo.py"):
|
||||
source = file(dir + "/launcherinfo.py", "rU").read().decode("utf8")
|
||||
if source[0] == u'\ufeff':
|
||||
source = source[1:]
|
||||
source = source.encode("raw_unicode_escape")
|
||||
|
||||
exec source in info
|
||||
|
||||
del info["__builtins__"]
|
||||
|
||||
store.projects.append(Project(name, dir, gamedir, info))
|
||||
|
||||
def load_projects():
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
store.projects = [ ]
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
if cwd == config.renpy_base:
|
||||
dirs = [ cwd ]
|
||||
else:
|
||||
dirs = [ config.renpy_base, cwd ]
|
||||
|
||||
for d in dirs:
|
||||
|
||||
contents = os.listdir(d)
|
||||
contents.sort()
|
||||
|
||||
for dd in contents:
|
||||
|
||||
dir = d + "/" + dd
|
||||
|
||||
if os.path.isdir(dir):
|
||||
load_project(dir, dd)
|
||||
|
||||
if not store.projects:
|
||||
raise Exception("The launcher will not function without any projects.")
|
||||
|
||||
|
||||
def lint():
|
||||
|
||||
import renpy.subprocess as subprocess
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
store.message = u"Lint in progress."
|
||||
title(u"Lint")
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
lf = file("lint.txt", "w+")
|
||||
|
||||
if hasattr(sys, "winver") and sys.argv[0].lower().endswith(".exe"):
|
||||
proc = subprocess.Popen([config.renpy_base + "/console.exe", "--lint", project.path], stdin=lf, stdout=lf, stderr=lf)
|
||||
else:
|
||||
proc = subprocess.Popen([sys.executable, sys.argv[0], "--lint", project.path], stdout=lf)
|
||||
|
||||
proc.wait()
|
||||
|
||||
lf.close()
|
||||
|
||||
renpy.launch_editor([ "lint.txt" ],transient=1)
|
||||
|
||||
def rmpersistent():
|
||||
|
||||
import renpy.subprocess as subprocess
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
store.message = u"Deleting persistent data."
|
||||
title(u"Delete Persistent")
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
if hasattr(sys, "winver") and sys.argv[0].lower().endswith(".exe"):
|
||||
proc = subprocess.Popen([config.renpy_base + "/console.exe", "--rmpersistent", project.path])
|
||||
else:
|
||||
proc = subprocess.Popen([sys.executable, sys.argv[0], "--rmpersistent", project.path])
|
||||
|
||||
proc.wait()
|
||||
|
||||
label main_menu:
|
||||
return
|
||||
|
||||
label find_project:
|
||||
|
||||
python hide:
|
||||
load_projects()
|
||||
|
||||
wanted = persistent.project or "demo"
|
||||
|
||||
for p in projects:
|
||||
if p.name == wanted:
|
||||
store.project = p
|
||||
break
|
||||
else:
|
||||
store.project = projects[0]
|
||||
|
||||
|
||||
store.game_proc = None
|
||||
|
||||
return
|
||||
|
||||
|
||||
label start:
|
||||
|
||||
call find_project from _call_find_project_1
|
||||
|
||||
label main:
|
||||
|
||||
python:
|
||||
store.message = u"What do you want to do?"
|
||||
|
||||
label top_menu:
|
||||
|
||||
|
||||
python hide:
|
||||
|
||||
while True:
|
||||
|
||||
title(project.title)
|
||||
|
||||
mid()
|
||||
|
||||
label(u"This Project")
|
||||
|
||||
if not game_proc or game_proc.poll() is not None:
|
||||
clicked = ui.jumps("launch")
|
||||
else:
|
||||
clicked = None
|
||||
|
||||
button(u"Launch",
|
||||
u"Starts the project running.",
|
||||
clicked=clicked)
|
||||
|
||||
|
||||
if config.editor:
|
||||
button(u"Edit Script",
|
||||
u"Edits the script files.",
|
||||
clicked=ui.jumps("edit"))
|
||||
|
||||
|
||||
button(u"Change Theme",
|
||||
u"Changes the color theme of the project.",
|
||||
ifrw("choose_theme"))
|
||||
|
||||
button(u"Game Directory",
|
||||
u"Opens the game directory.",
|
||||
clicked=ui.jumps("game_directory"))
|
||||
|
||||
|
||||
|
||||
button(u"Tools",
|
||||
u"Shows the tools menu.",
|
||||
clicked=ui.jumps("tools"))
|
||||
|
||||
spacer()
|
||||
|
||||
label(u"Change Project")
|
||||
|
||||
button(u"Select Project",
|
||||
u"Select a project to work with.",
|
||||
clicked=ui.jumps("select_project"))
|
||||
|
||||
button(u"New Project",
|
||||
u"Create a new project from a template.",
|
||||
clicked=ui.jumps("new"))
|
||||
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
button(u"Documentation", u"Read Ren'Py tutorials and manuals.", clicked=ui.jumps("documentation"))
|
||||
button(u"Quit", u"Quit the Ren'Py Launcher.", clicked=ui.jumps("confirm_quit"))
|
||||
ui.close()
|
||||
|
||||
|
||||
if game_proc and game_proc.poll() is None:
|
||||
ui.add(ProcessBehavior(game_proc))
|
||||
|
||||
interact()
|
||||
|
||||
jump top_menu
|
||||
|
||||
label select_project:
|
||||
|
||||
python hide:
|
||||
|
||||
choices = [ (p.name, p.info["description"], p, None, False) for p in projects if not p.info.get("template") ]
|
||||
|
||||
store.project = paged_menu(u"Select a Project", choices, u"Please select a project.")
|
||||
|
||||
persistent.project = store.project.name
|
||||
|
||||
store.game_proc = None
|
||||
|
||||
jump main
|
||||
|
||||
label launch:
|
||||
|
||||
python hide:
|
||||
import renpy.subprocess
|
||||
import sys
|
||||
import os.path
|
||||
import os
|
||||
|
||||
if hasattr(sys, "winver") and sys.argv[0].lower().endswith(".exe"):
|
||||
proc = renpy.subprocess.Popen([sys.argv[0], project.path])
|
||||
else:
|
||||
proc = renpy.subprocess.Popen([sys.executable, sys.argv[0], project.path])
|
||||
|
||||
store.message = _(u"%s has been launched.") % project.title
|
||||
|
||||
store.game_proc = proc
|
||||
|
||||
|
||||
jump top_menu
|
||||
|
||||
|
||||
|
||||
label edit:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
|
||||
|
||||
files = [ project.gamedir + "/" + i for i in os.listdir(project.gamedir) if i.endswith(".rpy") if not i[0] == "."]
|
||||
|
||||
files.sort()
|
||||
|
||||
for i in files[:]:
|
||||
if i.endswith("options.rpy"):
|
||||
files.remove(i)
|
||||
files.insert(0, i)
|
||||
|
||||
for i in files[:]:
|
||||
if i.endswith("script.rpy"):
|
||||
files.remove(i)
|
||||
files.insert(0, i)
|
||||
|
||||
if not renpy.launch_editor(files):
|
||||
error(u"Error", u"Launching the editor failed. You may need Java, which can be downloaded for free from {a=http://www.java.com}java.com{/a}.", "start")
|
||||
|
||||
store.message = _(u"Launched editor with %d script files.") % len(files)
|
||||
|
||||
jump top_menu
|
||||
|
||||
label game_directory:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
import sys
|
||||
|
||||
gamedir = os.path.normpath(project.gamedir)
|
||||
|
||||
if sys.platform == "win32":
|
||||
os.startfile(gamedir)
|
||||
elif platform.mac_ver()[0]:
|
||||
import renpy.subprocess as subprocess
|
||||
subprocess.Popen([ "open", gamedir ])
|
||||
else:
|
||||
import renpy.subprocess as subprocess
|
||||
subprocess.Popen([ "xdg-open", gamedir ])
|
||||
|
||||
|
||||
gamedir = "".join(quote(i) for i in gamedir)
|
||||
store.message = _(u"Opening game directory:\n%s") % gamedir
|
||||
|
||||
jump top_menu
|
||||
|
||||
|
||||
label tools:
|
||||
|
||||
$ store.message = u"Please choose a tool you want to use with this project."
|
||||
|
||||
label tools_menu:
|
||||
|
||||
python hide:
|
||||
|
||||
title(_("Tools: %s") % project.title)
|
||||
|
||||
mid()
|
||||
|
||||
label(u"Anytime")
|
||||
|
||||
button(u"Check Script (Lint)",
|
||||
u"Checks the game's script for likely errors. This should be run before releasing.",
|
||||
clicked=ui.jumps("lint"))
|
||||
|
||||
|
||||
button(u"Delete Persistent",
|
||||
u"Deletes the game's persistent data.",
|
||||
clicked=ui.jumps("rmpersistent"))
|
||||
|
||||
# button("Quick Backup",
|
||||
# "Makes a backup copy of the project. You also need to make backups somewhere other then this computer.",
|
||||
# clicked=ui.jumps("backup"))
|
||||
|
||||
spacer()
|
||||
|
||||
label(u"Release Day")
|
||||
|
||||
button(u"Add From to Calls",
|
||||
u"Adds a from clause to each of the call statements in your script.",
|
||||
clicked=ifrw("add_from_to_calls"))
|
||||
|
||||
button(u"Archive Files",
|
||||
u"Archive files found under the game and archived directories.",
|
||||
clicked=ifrw("archive_files"))
|
||||
|
||||
button(u"Build Distributions",
|
||||
u"Build distributions for the platforms supported by Ren'Py.",
|
||||
clicked=ui.jumps("distribute"))
|
||||
|
||||
ui.close()
|
||||
|
||||
bottom()
|
||||
|
||||
button(u"Back",
|
||||
u"Goes back to the top menu.",
|
||||
clicked=ui.jumps("main"))
|
||||
|
||||
ui.close()
|
||||
|
||||
interact()
|
||||
|
||||
label lint:
|
||||
|
||||
python hide:
|
||||
lint()
|
||||
|
||||
store.message = u"A lint report should appear shortly."
|
||||
|
||||
jump tools_menu
|
||||
|
||||
|
||||
|
||||
label archive_files:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import renpy.tools.archiver as archiver
|
||||
|
||||
extensions = project.info.get('archive_extensions', "*.png *.gif *.jpg")
|
||||
extensions = prompt(u"Archiving Files", u"Please enter a space separated list of the file patterns you want archived.", "tools", extensions)
|
||||
if not extensions.strip():
|
||||
renpy.jumps("tools_menu")
|
||||
project.info['archive_extensions'] = extensions
|
||||
extensions = [ i.strip() for i in extensions.strip().split() ]
|
||||
|
||||
|
||||
base = project.info.get('archive_base', "data")
|
||||
base = prompt(u"Archiving Files", u"Please enter the name of the archive file, without the .rpa extension.", "tools", base)
|
||||
base = base.strip()
|
||||
if not base:
|
||||
renpy.jumps("tools_menu")
|
||||
project.info['archive_base'] = base
|
||||
|
||||
project.save()
|
||||
|
||||
# Tell the user we're archiving images.
|
||||
title(u"Archiving Files")
|
||||
store.message = u"Please wait while we archive files."
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
|
||||
gamedir = project.gamedir
|
||||
archived = project.path + "/archived"
|
||||
|
||||
files = [ ]
|
||||
prefix = gamedir + "/" + base
|
||||
|
||||
def should_archive(fn, extensions=extensions):
|
||||
import fnmatch
|
||||
|
||||
fn = fn.lower()
|
||||
|
||||
if fn[0] == ".":
|
||||
return False
|
||||
|
||||
if fn == "presplash.png":
|
||||
return False
|
||||
if fn == "presplash.jpg":
|
||||
return False
|
||||
|
||||
for e in extensions:
|
||||
if fnmatch.fnmatch(fn, e):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
archived_files = set()
|
||||
|
||||
for bdir in (gamedir, archived):
|
||||
|
||||
for dirname, dirs, filenames in os.walk(bdir):
|
||||
|
||||
# Ignore svn.
|
||||
dirs[:] = [ i for i in dirs if not i[0] == '.' ]
|
||||
|
||||
for fn in filenames:
|
||||
|
||||
fullfn = dirname + "/" + fn
|
||||
shortfn = fullfn[len(bdir)+1:]
|
||||
|
||||
if shortfn in archived_files:
|
||||
continue
|
||||
|
||||
if not should_archive(shortfn):
|
||||
continue
|
||||
|
||||
files.append((fullfn, shortfn))
|
||||
archived_files.add(shortfn)
|
||||
|
||||
archiver.archive(prefix, files)
|
||||
|
||||
# f = file(gamedir + "/images.rpy", "w")
|
||||
# print >>f, "init:"
|
||||
# print >>f, " $ config.archives.append('images')"
|
||||
# f.close()
|
||||
|
||||
for fullfn, shortfn in files:
|
||||
afn = archived + "/" + shortfn
|
||||
|
||||
if fullfn == afn:
|
||||
continue
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(afn))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.rename(fullfn, afn)
|
||||
except:
|
||||
os.rename(afn, afn + ".old")
|
||||
os.rename(fullfn, afn)
|
||||
os.unlink(afn + ".old")
|
||||
|
||||
store.message = u"The files have been added to the archive, and moved into the archived directory."
|
||||
|
||||
jump tools_menu
|
||||
|
||||
label backup:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
|
||||
# Tell the user we're archiving images.
|
||||
title(u"Making Backup")
|
||||
store.message = u"Please wait while we make a backup."
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
try:
|
||||
os.mkdir('backups')
|
||||
except:
|
||||
pass
|
||||
|
||||
while True:
|
||||
|
||||
btime = str(int(time.time()))
|
||||
bdir = "backups/%s.%s" % (project.name, btime)
|
||||
|
||||
if not os.path.exists(bdir):
|
||||
break
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
shutil.copytree(project.path, bdir)
|
||||
|
||||
store.message = _(u"The backup was placed into %s.") % bdir
|
||||
|
||||
jump tools_menu
|
||||
|
||||
|
||||
label add_from_to_calls:
|
||||
|
||||
python hide:
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
|
||||
title(u"Add From to Calls")
|
||||
store.message = u"Please wait while we add from clauses to call statements."
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
import renpy.tools.add_from as add_from
|
||||
|
||||
add_from.add_from(project.gamedir, config.commondir)
|
||||
|
||||
store.message = _(u"Done adding from clauses to call statements. You may want to remove the .bak files created.")
|
||||
|
||||
jump tools_menu
|
||||
|
||||
label rmpersistent:
|
||||
|
||||
python hide:
|
||||
rmpersistent()
|
||||
store.message = _(u"Done deleting persistent data.")
|
||||
|
||||
jump tools_menu
|
||||
|
||||
|
||||
label confirm_quit:
|
||||
$ renpy.quit()
|
||||
|
||||
label documentation:
|
||||
python hide:
|
||||
import webbrowser
|
||||
webbrowser.open_new("file:///" + config.renpy_base + "/doc/index.html")
|
||||
store.message = _(u"Now showing the Ren'Py documentation in your web browser.")
|
||||
|
||||
jump top_menu
|
||||
@@ -1,167 +0,0 @@
|
||||
label new:
|
||||
|
||||
python hide:
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import time
|
||||
|
||||
|
||||
# Select a template.
|
||||
|
||||
choices = [ (p.name, p.info["description"], p, None, False) for p in projects if p.info.get("template", None)]
|
||||
|
||||
template = paged_menu(u"Select a Template", choices, u"Please select a project to use as a template for your project.")
|
||||
|
||||
# Choose project name.
|
||||
|
||||
name = prompt(u"Project Name", u"Type the name of your new project, and press enter.\n", "main")
|
||||
name = name.strip()
|
||||
|
||||
error = None
|
||||
|
||||
if not name:
|
||||
error = u"Please enter a non-empty project name."
|
||||
elif os.path.exists(name):
|
||||
error = u"A file or directory named '%s' already exists." % name
|
||||
else:
|
||||
try:
|
||||
name = name.encode("ascii")
|
||||
except:
|
||||
error = u"Project names must be ASCII. This is because the ZIP file format does not support non-ASCII characters in a uniform way."
|
||||
|
||||
if error:
|
||||
store.error(u"Error", error, "main")
|
||||
|
||||
# Tell the user we're creating the project.
|
||||
title(u"Creating Project")
|
||||
store.message = u"Please wait while we create the project."
|
||||
ui.pausebehavior(0)
|
||||
interact()
|
||||
|
||||
# Here is where we actually create the project.
|
||||
|
||||
import shutil
|
||||
|
||||
shutil.copytree(template.path, name)
|
||||
|
||||
unlink = template.info.get("unlink", [ ])
|
||||
unlink += [ 'launcherinfo.py' ]
|
||||
|
||||
for i in unlink:
|
||||
if os.path.exists(name + "/" + i):
|
||||
os.unlink(name + "/" + i)
|
||||
|
||||
for dir, dirs, files in os.walk(name):
|
||||
for d in list(dirs):
|
||||
if d.startswith("."):
|
||||
dirs.remove(d)
|
||||
dn = dir + "/" + d
|
||||
shutil.rmtree(dn, True)
|
||||
|
||||
# Change the save directory.
|
||||
options = file(name + "/game/options.rpy").read()
|
||||
save_dir = "%s-%d" % (name, time.time())
|
||||
options = options.replace("template-1220804310", save_dir)
|
||||
file(name + "/game/options.rpy", "w").write(options)
|
||||
|
||||
persistent.project = name
|
||||
|
||||
call find_project from _call_find_project_2
|
||||
|
||||
label choose_theme:
|
||||
|
||||
python hide:
|
||||
|
||||
# Select a color scheme.
|
||||
|
||||
themes = theme_data.keys()
|
||||
themes.sort()
|
||||
|
||||
choices = [ ]
|
||||
for i in themes:
|
||||
|
||||
def hovered(i=i):
|
||||
td = theme_data[i].copy()
|
||||
engine = td["theme"]
|
||||
del td["theme"]
|
||||
|
||||
if engine == "roundrect":
|
||||
renpy.style.restore(style_backup)
|
||||
theme.roundrect(launcher=True, **td)
|
||||
renpy.style.rebuild()
|
||||
return ("repeat", 0)
|
||||
|
||||
choices.append((i, None, i, hovered, False))
|
||||
|
||||
color_theme = paged_menu(u"Select a Theme", choices, u"Please select a color theme for your project. You can always change the colors later.", cancel='color_theme_cancel')
|
||||
|
||||
# Restore default theme.
|
||||
renpy.style.restore(style_backup)
|
||||
theme.roundrect(launcher=True)
|
||||
renpy.style.rebuild()
|
||||
|
||||
ofn = project.path + "/game/options.rpy"
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
if not os.path.exists(ofn):
|
||||
error(u"Changing Theme", u"The options file does not seem to exist.", "main")
|
||||
|
||||
inf = file(ofn, "rU")
|
||||
outf = file(ofn + ".new", "w")
|
||||
|
||||
td = theme_data[color_theme]
|
||||
|
||||
# TODO: Make this less specific to roundrect. Need to figure out
|
||||
# how to switch themes, rather than just recolor them.
|
||||
|
||||
changing = False
|
||||
changed = False
|
||||
|
||||
for l in inf:
|
||||
|
||||
if re.match(r'\s*theme.roundrect\(', l):
|
||||
changing = True
|
||||
changed = True
|
||||
elif re.match(r'\s*\)', l):
|
||||
changing = False
|
||||
elif changing:
|
||||
|
||||
def repl(m, td=td):
|
||||
return m.group(1) + m.group(2) + " = \"" + td.get(m.group(2), m.group(3)) + "\","
|
||||
|
||||
l = re.sub(r'^(\s*)(\w+) = "([\da-fA-F#]+)",', repl, l)
|
||||
|
||||
outf.write(l)
|
||||
|
||||
outf.close()
|
||||
inf.close()
|
||||
|
||||
try:
|
||||
os.rename(ofn + ".new", ofn)
|
||||
except:
|
||||
|
||||
# I hate windows.
|
||||
os.rename(ofn, ofn + ".old")
|
||||
os.rename(ofn + ".new", ofn)
|
||||
os.unlink(ofn + ".old")
|
||||
|
||||
if not changed:
|
||||
error(u"Changing Theme", u"Could not modify options.rpy, perhaps it was edited too much.", "main")
|
||||
|
||||
jump main
|
||||
|
||||
|
||||
|
||||
label color_theme_cancel:
|
||||
|
||||
python hide:
|
||||
|
||||
# Restore default theme.
|
||||
renpy.style.restore(style_backup)
|
||||
theme.roundrect(launcher=True)
|
||||
renpy.style.rebuild()
|
||||
|
||||
jump main
|
||||