Compare commits

..

27 Commits

Author SHA1 Message Date
tom 8e7ffc881b Starting 4.3 release campaign. 2004-12-11 04:10:32 +00:00
tom d9ccfb84c2 More 4.3 hacking. 2004-12-09 05:20:28 +00:00
tom 845d47dca9 Bug fix, keymaps, and imagemap unselected. 2004-12-08 23:27:40 +00:00
tom d654be1585 Fixed bug that cause predict to cause an exception. 2004-10-18 13:41:21 +00:00
tom 4896b15327 Bug fixes? 2004-10-18 13:40:55 +00:00
tom 5ea9d436ce *** empty log message *** 2004-09-25 19:43:36 +00:00
tom c05e4e528e *** empty log message *** 2004-09-24 20:25:43 +00:00
tom e10488b77a *** empty log message *** 2004-09-24 02:31:54 +00:00
tom 86e0cb3331 *** empty log message *** 2004-09-23 22:20:34 +00:00
tom c6397c08af *** empty log message *** 2004-09-22 04:49:09 +00:00
tom f9db64231d *** empty log message *** 2004-09-22 04:39:38 +00:00
tom f3c3c67def *** empty log message *** 2004-09-22 00:15:05 +00:00
tom 6d316a9c78 *** empty log message *** 2004-09-21 23:54:02 +00:00
tom 6e7e68b31a Reorganizing to use common directory. 2004-09-13 18:16:40 +00:00
tom a24e6b2af1 *** empty log message *** 2004-09-12 13:51:22 +00:00
tom 597b01c26b Ready for 4.1 release? 2004-09-12 11:53:36 +00:00
tom a262eb0f60 *** empty log message *** 2004-09-11 18:30:37 +00:00
tom 92006d237c 4.0 Release 2004-09-06 20:33:05 +00:00
tom 1427336746 Feature complete. 2004-09-05 22:49:30 +00:00
tom c35ed8a7cd Before changing fill implementation. 2004-09-04 18:30:42 +00:00
tom 90f47eacf3 In the process of removing with. 2004-09-04 15:33:24 +00:00
tom ee093925f5 Before surface rewrite. 2004-08-31 14:33:13 +00:00
tom f686a810a7 *** empty log message *** 2004-08-31 03:43:43 +00:00
tom e2a12284d5 *** empty log message *** 2004-08-29 02:51:34 +00:00
tom 10b4064a53 *** empty log message *** 2004-08-25 02:18:07 +00:00
tom f1ea5289aa *** empty log message *** 2004-08-24 00:07:26 +00:00
tom a26ed9c328 *** empty log message *** 2004-08-23 01:21:57 +00:00
791 changed files with 9838 additions and 157545 deletions
-54
View File
@@ -1,54 +0,0 @@
*.rpyc
*.rpyb
*.rpymc
*.pyc
*.pyo
*~
*.bak
saves
tmp
cache
log.txt
errors.txt
traceback.txt
styles.txt
/android
/build
/dist
/dists
/renpy.app
/jedit
/lint.txt
/renpy.code
/*testing*
/screenshot*
/renpy.exe
/lib
/lib.old
/doc
/.pydevproject
/.pydevproject.bak
/.project
/.settings
/LICENSE.txt
/templates/english/README.html
/the_question/README.html
/tutorial/README.html
/renpy/angle/*.pyx
/renpy/angle/*.pxd
/renpy-ppc.zip
/module/build
/module/gen
/editra
/launcher/game/theme
/launcher/game/script_version.rpy
dl
renpy/vc_version.py
.externalToolBuilders
rapt-*
BIN
View File
Binary file not shown.
+244
View File
@@ -0,0 +1,244 @@
New in 4.3
----------
Now, when the library first starts up, it tries calling the
"splashscreen" label, if it exists. The splashscreen will not be
called in the case of a full reset (known to the user as a return to
the main menu).
Added a new text property, antialias, that controls the antialiasing
of text. Also made the font property optionally take a comma-separated
list of font names, which are searched for in the
Added a new class, DynamicCharacter, which is now the preferred way of
having a character with a changable and/or user-input name.
A new random number generator has been implemented as
renpy.random. This random number generator cooperates with rollback,
always producing the same random numbers when a rollback occurs.
Added a set of UI functions, that allow the user to build up a user
interface themselves. These could be useful when implementing more
complex games, such as those that require the user to schedule a day
in advance. Also new is a new imagebutton, a button consisting of two
images.
Sticky postions have been implemented. Enabling this (using the
variable config.sticky_positions) cause the at clause corresponding to
a given character to be remembered, allowing the character to change
emotion without changing places on the screen (or requiring a second
at clause).
Rewrote the implementation of preferences, to clean up the code. Moved
it into its own file, preferences.rpy. Also, made it possible for a
user to add his own preferences into the system, although that isn't
really recommended.
The various imagemap functions now have a new parameter, unselected,
which gives an image to use when a hotspot is present but not
hovered. This lets us distinguish between between hotspots that are
present and exist, and hotspots that are totally absent. This could be
used to implement something like an image gallery that only displays
unlocked images.
Implemented config.keymap, which allows the changing of keys and mouse
buttons that trigger various Ren'Py events.
There's now a new look for loading and saving games, that allows 10
saves to be presented at once. I strongly recommend removing the
library.file_page_length line at the start of your game scripts, if
it exists.
Fixed a bug in sound.init that lead to crashes in some cases.
Fixed a bug in ast.Node.predict that was causing an exception when
config.debug was turned on.
New in 4.2
----------
Ren'Py now ships with a common directory that is used to store the
library files, as well as the files needed by a minimal game. (Such as
a default font.) The idea here is to allow one to copy a game
directory from one version of Ren'Py to another, and have it just
work.
One can upgrade from 4.1 to 4.2 by deleting script.rpy, script.rpyc,
library.rpy, and library.rpyc, and then copying in the game
directory.
We've also eliminated the default background images. To go back to the
images used with Ren'Py 4.1, add the following lines to your script,
and copy the images out of the 4.1 distribution, or your 4.1 based
game.
[code]
init:
$ style.mm_root_window.background = Image("mainmenu.jpg")
$ style.gm_root_window.background = Image("gamemenu.jpg")
$ style.window.background = Frame("frame.png", 125, 25)
[/code]
Fixed several bugs with the archiver. This version just might actually
work on Windows.
Added a new variable, config.hard_rollback_limit, which limits the
number of steps the user can rollback the game, interactively. This
limit now defaults to 10 steps. (suggested by Grey)
Added a second parameter to renpy.pause, that allows us to pause until
a particular offset in the background music is reached. (suggested by
Alessio)
Added keyboard mouse controls that can be used to move the mouse
around on the game and main menus. This allows us to manipulate the
game and main menus without having to touch the mouse. This is mostly
for completeness. (suggested by Alessio)
Changed the way in which overlays work. We now have the variable
config.overlay_functions, which contains a list of functions, each of
which returns a list of displayables that will be added to the
screen. (sorta-kinda suggested by Alessio)
Removed renpy.set_overlay, since config.overlay_functions is a more
flexible way of doing the same thing.
Now, defining the label main_menu allows you to totally replace the
main menu with something of your own devising. Changed the
documentation to reflect this, as well as the changes in startup that
happened in 4.1.
Added a program called "add_from", which adds from clauses to all bare
call statements found in the program.
Replaced the menu_selected and menu_unselected styles with a single
menu_choice style which participates in the hover protocol. This may
change user code, if you change the menu colors. To fix this, replace
style.menu_selected.color with style.menu_choice.hover_color, and
style.menu_unselected.color with style.menu_choice.idle_color.
Added the ability to play sound effects, by calling the renpy.play
function. Added a preference that allows the user to control if
sound effects are played or not.
Added sound styles, which are used to define the sounds that are
played when buttons, imagemaps, and menu choices are hovered and
activated. (By default, no such sounds are played.)
Implemented that annoying thing where text is typed on the screen one
character at a time. Also added a preference that allows the user to
disable it. Used all the restraint I could muster to avoid defaulting
that preference to off.
Added the ability to fade out music when changing music
tracks. This is controlled by the config.fade_music variable.
(suggested by Alessio)
Added parameterized images, and the ability to show text as image
using a command like:
[code]
show text "American Bishoujo Presents..."
[/code]
Added a Move function, which can be used in at to allow an image to be
moved on the screen. This is best used when the image is smaller than
the screen. (suggested by Alessio)
Changed the format of archive files, to make them somewhat harder to
reverse-engineer. This requires the user to regenerate the archive
files. To make this easier, we now ship a batch file (called
archive_images.bat) that automatically archives the images found in
the game directory.
Added a new function renpy.wait that is equivalent to the wait
statement, and made it and renpy.pause return True if they are
interrupted, or False if the run to their natural completions. This
now makes it possible to jump somewhere else when the user click,
rather than blindly going to the next label. For example:
[code]
# Actually, this runs before the library main menu.
label main_menu:
scene black
show text "American Bishoujo\nPresents" \
at Move((0.5, 0.0), (0.5, 0.5), 3.0,
xanchor='center', yanchor='bottom')
if renpy.pause(6):
jump _library_main_menu
show text "A PyTom Game" at Position(xpos=0.5, ypos=0.5,
xanchor="center", yanchor="bottom")
if renpy.with(fade) or renpy.pause(4):
jump _library_main_menu
$ renpy.transition(fade)
jump _library_main_menu
[code]
Updated renpy-mode.el to add imenu support, so (X)Emacs users can use
the speedbar to jump around in a script. If you don't know what this
means, you probably don't care.
Improved the comments in the demo script, to make it a better
example. Added a syntax-highlighted version of the demo script to the
tutorial, to make it easier on peoples eyes.
New in 4.1
----------
Added the ability to customize the main menu by giving a list of
buttons on the main menu and the labels that they jump the user to.
Added the ability to center-click to hide any displayed text or menus.
Added the ability to have a color mouse that we can move around the
screen.
Added a persistent object, which has fields that are persistent across
games. Made the preferences part of this object, so that they are
persisted across sessions. For simplicity's sake, made seen_ever part
of that persistent object.
Added a special character called "centered", which causes the text it
displays to be centered in the screen without any window. Added two
new styles (centered_window and centered_text), which are used for
this, and a new property, textalign, which controls the horizontal
alignment of text within the Text object itself.
Keywords are now special in all contexts. So you can no longer include
keywords in image names. Sorry.
Improved parse error messages. They now include the text of the
line and a caret indication the location in the line where the parse
error occurred.
Added a with clause to say statements and menus. This lets one display
dialogue, thoughts, or menus using a transition. In conjunction with
this, changed a bit the semantics of with statements, and with clauses
on show, hide, and scene statements. Rewrote the section on
transitions in the documentation to reflect the new reality.
Added the ability to translate the text of the game menu. Together
with the ability to change the main menu, this makes Ren'Py fully
localizable, except for error messages. Check out the Localization
section in the tutorial for more details.
Added confirmations for quitting and overwriting a save game. This
also includes quitting by trying to close the window.
Added a preferences screen, which lets users change the Ren'Py
preferences. Right now, this includes Windowed/Fullscreen, Music
Enabled/Disabled, CTRL Skips Unread/All messages, and Transitions
controls which transitions are performed.
Added a Pan function which can be used in an at clause. This allows us
to pan over a background image.
-55
View File
@@ -1,55 +0,0 @@
==============================
The Ren'Py Visual Novel Engine
==============================
http://www.renpy.org
Branches
========
Ren'Py development takes place on two branches, ``master`` and
``devel``, as well as the occasional feature branch.
Master
-----
The master branch contains code that can be run using the libraries in
the latest (release or pre-release) version of Ren'Py. It's used for
bugfixes and features that do not require C or Cython code to
implement.
After checking out master, run::
./after_checkout.sh <path-to-renpy>
to link in the libraries from the most recent Ren'Py. (On Windows, you
will need to run this under msys or cygwin.)
Ren'Py can then be run by running renpy.exe, renpy.sh, or renpy.app as
appropriate.
Devel
-----
The devel branch contains code that requires a recompile of modules
implemented in C or Cython. Building devel requires you to have the
prerequisite libraries installed. Then set RENPY_DEPS_INSTALLED to
a \::-separated list of paths containing dependencies. For example::
export RENPY_DEPS_INSTALL=/usr::/usr/lib/x86_64-linux-gnu/
Finally, change into the modules directory, and run::
python setup.py install
Ren'Py can then be run by using python to run renpy.py.
Contributing
============
For bug fixes, documentation improvements, and simple changes, just
make a pull request. For more complex changes, it might make sense
to file an issue so we can discuss the design.
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/env python
import argparse
import os
import subprocess
import sys
from renpy import version_tuple #@UnresolvedImport
version = ".".join(str(i) for i in version_tuple)
short_version = ".".join(str(i) for i in version_tuple[:3])
print "Version", version
ap = argparse.ArgumentParser()
ap.add_argument("--release", action="store_true")
ap.add_argument("--prerelease", action="store_true")
ap.add_argument("--experimental", action="store_true")
ap.add_argument("--no-tag", "-n", action="store_true")
args = ap.parse_args()
if args.release:
links = [ "release", "prerelease", "experimental" ]
tag = True
elif args.prerelease:
links = [ "prerelease", "experimental" ]
tag = True
elif args.experimental:
links = [ "experimental" ]
tag = False
else:
links = [ ]
tag = False
def check_dirty():
if args.no_tag:
return
if subprocess.check_call([ "git", "diff", "--quiet", "HEAD" ]):
print "Directory not checked in: {}".format(os.getcwd())
sys.exit(1)
os.chdir("/home/tom/ab/renpy")
check_dirty()
os.chdir("/home/tom/ab/renpy/android")
check_dirty()
subprocess.check_call([ "./add_renpy.sh", short_version ])
if not args.no_tag:
subprocess.check_call([ "git", "tag", "-a", "rapt-" + version, "-m", "Tagging RAPT release." ])
os.chdir("/home/tom/ab/renpy/dl")
for i in links:
if os.path.exists(i):
os.unlink(i)
os.symlink(short_version, i)
os.chdir("/home/tom/ab/renpy")
if tag and not args.no_tag:
cmd = [ "git", "tag", "-a", version, "-m", "Ren'Py " + version ]
subprocess.check_call(cmd)
os.chdir("/home/tom/ab/website")
subprocess.check_call("./upload.sh")
Executable
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python
# This program adds froms to every unqualified call found in the game
# directory. It's not perfect, but it's better than nothing.
import sys
import os
import re
def find_labels(fn, labels):
f = file(fn, "r")
for l in f:
m = re.match(r'^\s*call\s+\w+\s+from\s+(\w+)\s*$', l)
if m:
labels[m.group(1)] = True
f.close()
def replace_labels(fn, labels):
f = file(fn, "r")
of = file(fn + ".new", "w")
def replaceit(m):
target = m.group(2)
num = 0
while True:
num += 1
label = "_call_%s_%d" % (target, num)
if label not in labels:
break
labels[label] = True
return m.group(1) + "call " + target + " from " + label + m.group(3)
for l in f:
l = re.sub(r'^(\s*)call\s+(\w+)(\s*$)', replaceit, l)
of.write(l)
f.close()
of.close()
try:
os.unlink(fn + ".bak")
except:
pass
os.rename(fn, fn + ".bak")
os.rename(fn + ".new", fn)
def main():
gamedir = "game"
if len(sys.argv) >= 2:
gamedir = sys.argv[1]
print "Processing files in", gamedir
files = [ gamedir + "/" + i for i in os.listdir(gamedir)
if i.endswith(".rpy") ]
labels = { }
for fn in files:
print "Finding labels in", fn
find_labels(fn, labels)
for fn in files:
print "Replacing labels in", fn
replace_labels(fn, labels)
if __name__ == "__main__":
main()
-15
View File
@@ -1,15 +0,0 @@
#!/bin/bash
ROOT="$(dirname $(python -c "import os;print(os.path.realpath('$0'))"))"
ln -s "$ROOT/help.html" "$ROOT/tutorial/README.html"
ln -s "$ROOT/help.html" "$ROOT/the_question/README.html"
ln -s "$ROOT/help.html" "$ROOT/templates/english/README.html"
ln -s "$ROOT/sphinx/source/license.rst" "$ROOT/LICENSE.txt"
if [ "$1" != "" ]; then
ln -s "$1/lib" "$ROOT/lib"
ln -s "$1/renpy.app" "$ROOT"
ln -s "$1/renpy.exe" "$ROOT"
fi
-10
View File
@@ -1,10 +0,0 @@
# This file sets up the normal python modules. It's used to help eclipse
# do type detection, by providing an importable version of the cython code.
from distutils.core import setup
setup(
packages=['renpy', 'renpy.gl', 'renpy.angle', 'renpy.display', 'renpy.audio', 'renpy.text', 'pysdlsound'],
package_dir={ 'pysdlsound' : 'module' },
)
+3
View File
@@ -0,0 +1,3 @@
cd game
..\archiver.exe images *.png *.jpg
pause
Executable
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env python
# The Ren'Py archiver. This builds a Ren'Py archive file, and the
# associated index file. These files are really easy to reverse-engineer,
# but are probably better than nothing.
import sys
import os
import encodings.zlib_codec
import random
import glob
from cPickle import loads, dumps, HIGHEST_PROTOCOL
# The most we will go without inserting some padding. 10k.
padding_every = 10240
# The amount of padding we will add.
padding_max = 32
def randpadding():
plen = random.randint(1, padding_max)
rv = ""
for i in range(0, plen):
rv += chr(random.randint(1, 255))
return rv
def main():
if len(sys.argv) < 3:
print "Usage: %s <file-prefix> <files ...>" % sys.argv[0]
return
prefix = sys.argv[1]
# Archive file.
archivef = file(prefix + ".rpa", "wb")
# Index file.
indexf = file(prefix + ".rpi", "wb")
index = { }
random.seed()
offset = 0
# Needed because windows sucks. It doesn't do globbing on the
# command line.
files = [ ]
for i in sys.argv[2:]:
files.extend(glob.glob(i))
for fn in files:
index[fn] = [ ]
print "Adding %s..." % fn
datafile = file(fn, "rb")
while True:
# Pad with junk.
padding = randpadding()
archivef.write(padding)
offset += len(padding)
# Pick a random block size.
block = random.randint(1, padding_every)
data = datafile.read(block)
if not data:
break
dlen = len(data)
archivef.write(data)
index[fn].append((offset, dlen))
offset += dlen
datafile.close()
archivef.close()
indexf.write(dumps(index, HIGHEST_PROTOCOL).encode("zlib"))
indexf.close()
if __name__ == "__main__":
main()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python
from distutils.core import setup
import py2exe
import sys
if len(sys.argv) != 2:
print "Usage: build_exe.py <prefix>"
print ""
print "Builds <prefix>.exe."
print "Expects icons in <prefix>.ico."
sys.exit(-1)
def program(name):
return dict(script="run_game.py",
icon_resources=[ (0, name + ".ico"),
],
dest_base=name)
programs = [
program(sys.argv[1]),
]
sys.argv[1:] = [ 'py2exe' ]
setup(name="RenPy",
windows=programs,
console=[ "archiver.py", "add_from.py", "console.py" ],
zipfile='lib/renpy.zip',
)
BIN
View File
Binary file not shown.
+55
View File
@@ -0,0 +1,55 @@
This package was debianized by Michael Fedrowitz <michaelf@debian.org>
on Sun, 23 Feb 2003.
It was downloaded from
'http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/'.
Upstream Author: Bitstream, Inc.
Copyright:
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information, contact:
fonts at gnome dot org.
+382
View File
@@ -0,0 +1,382 @@
# This file consists of renpy functions that aren't expected to be
# touched by the user too much. We reserve the _ prefix for names
# defined in the library.
# It's strongly reccomended that you don't edit this file, as future
# releases of Ren'Py will probably change this file to include more
# functionality.
# It's also strongly recommended that you leave this file in the
# game directory, so its functionality is included in your game.
init -500:
python:
# These are settings that the user can tweak to control the
# look of the main menu and the load/save/escape screens.
# Used to store library settings.
library = object()
# The number of files to show at once.
library.file_page_length = 10
# A small amount of padding.
library.padding = 2
# The width of a thumbnail.
library.thumbnail_width = 250
# The height of a thumbnail.
library.thumbnail_height = 188
# The contents of the main menu.
library.main_menu = [
( "Start Game", "start" ),
( "Continue Game", "_continue" ),
( "Quit Game", "_quit" ),
]
# The contents of the game menu choices.
library.game_menu = [
( "return", "Return to Game", "_return"),
( "load", "Load Game", "_load_screen" ),
( "save", "Save Game", "_save_screen" ),
( "prefs", "Preferences", "_prefs_screen" ),
( "mainmenu", "Main Menu", "_full_restart" ),
( "quit", "Quit Game", "_quit_screen" ),
]
# Used to translate strings in the library.
library.translations = { }
# This is updated to give the user an idea of where a save is
# taking place.
save_name = ''
# The function that's used to translate strings in the game menu.
def _(s):
"""
Translates s into another language or something.
"""
if s in library.translations:
return library.translations[s]
else:
return s
# Called to make a screenshot happen.
def _screenshot():
renpy.screenshot("screenshot.bmp")
# Are the windows currently hidden?
_windows_hidden = False
# Hides the windows.
def _hide_windows():
global _windows_hidden
if _windows_hidden:
return
try:
_windows_hidden = True
renpy.interact(renpy.SayBehavior())
finally:
_windows_hidden = False
# Set up the default keymap.
python hide:
# The default keymap.
km = renpy.Keymap(
rollback = renpy.rollback,
screenshot = _screenshot,
toggle_fullscreen = renpy.toggle_fullscreen,
toggle_music = renpy.toggle_music,
game_menu = renpy.curried_call_in_new_context("_game_menu"),
hide_windows = _hide_windows,
)
config.underlay = [ km ]
return
# This is the true starting point of the program. Sssh... Don't
# tell anyone.
label _start:
if renpy.has_label("splashscreen") and not _restart:
call splashscreen
jump _main_menu
# This shows the main menu to the user.
label _main_menu:
# Let the user completely override the main menu.
if renpy.has_label("main_menu"):
jump main_menu
label _library_main_menu:
python hide:
ui.keymousebehavior()
ui.window(style='mm_root_window')
ui.fixed()
ui.window(style='mm_menu_window')
ui.vbox()
for text, label in library.main_menu:
ui.textbutton(text, clicked=ui.returns(label))
ui.close()
ui.close()
store._result = renpy.interact(suppress_overlay = True,
suppress_underlay = True)
# Computed jump to the appropriate label.
$ renpy.jump(_result)
return
# Used to call the game menu.
label _continue:
$ renpy.call_in_new_context("_load_menu")
jump _library_main_menu
##############################################################################
#
# Code for the game menu.
init -500:
python:
# This returns a window containing the game menu navigation
# buttons, set up to jump to the appropriate screen sections.
def _game_nav(selected):
ui.keymousebehavior()
ui.window(style='gm_root_window')
ui.fixed()
ui.window(style='gm_nav_window')
ui.vbox()
for key, label, target in library.game_menu:
style="button"
text_style="button_text"
if key == selected:
style = 'selected_button'
text_style = 'selected_button_text'
ui.textbutton(_(label), style=style, text_style=text_style,
clicked=ui.jumps(target))
ui.close()
ui.close()
def _game_interact():
return renpy.interact(suppress_underlay=True,
suppress_overlay=True)
_file_picker_index = 0
# This is used to render a single filename to the screen.
def _render_filename(index, filename, newest_filename):
if filename is None:
ui.text(_("Save in new slot."), style='file_picker_new_slot')
return
ui.hbox(padding=library.padding)
num = "% 2d." % index
if filename == newest_filename:
ui.text(num, style='file_picker_new')
else:
ui.text(num, style='file_picker_old')
# Do something better about this.
# ui.add(renpy.load_screenshot(filename))
ui.text(renpy.load_extra_info(filename), style='file_picker_extra_info')
ui.close()
# This displays a file picker that can chose a save file from
# the list of save files.
def _file_picker(selected, files):
nsg = renpy.newest_save_game()
while True:
if _file_picker_index >= len(files):
store._file_picker_index -= library.file_page_length
if _file_picker_index < 0:
store._file_picker_index = 0
fpi = _file_picker_index
cur_files = files[fpi:fpi + library.file_page_length]
# Navigation
_game_nav(selected)
ui.window(style='file_picker_window')
ui.hbox()
ui.vbox()
ui.hbox(padding=library.padding * 10)
def tb(cond, label, clicked):
if cond:
style = 'button'
text_style = 'button_text'
else:
style = 'disabled_button'
text_style = 'disabled_button_text'
ui.textbutton(label, style=style, text_style=text_style, clicked=clicked)
tb(fpi > 0, _('Previous Page'), ui.returns(("fpidelta", -1)))
tb(fpi + library.file_page_length < len(files),
_('Next Page'), ui.returns(("fpidelta", +1)))
ui.close() # hbox
for index, i in enumerate(cur_files):
def hover(i=i):
ui.reopen(image_win, True)
if i:
ui.add(renpy.load_screenshot(i))
else:
ui.null()
ui.close()
ui.button(style='file_picker_entry',
clicked=ui.returns(("return", i)),
hovered=hover)
_render_filename(index + fpi + 1, i, nsg)
ui.close() # vbox
image_win = ui.window(style='file_picker_image')
ui.null()
ui.close() # hbox
result = _game_interact()
type, value = result
if type == "return":
return value
if type == "fpidelta":
store._file_picker_index += value * library.file_page_length
def _yesno_prompt(screen, message):
_game_nav(screen)
ui.text(message, style='yesno_prompt')
ui.textbutton(_("Yes"), style='yesno_yes', clicked=ui.returns(True))
ui.textbutton(_("No"), style='yesno_no', clicked=ui.returns(False))
return _game_interact()
# Factored this all into one place, to make our lives a bit easier.
label _take_screenshot:
$ renpy.take_screenshot((library.thumbnail_width, library.thumbnail_height))
return
# Entry points from the game into menu-space.
label _load_menu:
call _take_screenshot
jump _load_screen
label _game_menu:
call _take_screenshot
jump _save_screen
label _confirm_quit:
call _take_screenshot
jump _quit_screen
# Menu screens.
label _load_screen:
python:
_fn = _file_picker("load", renpy.saved_game_filenames() )
python:
renpy.load(_fn)
jump _load_screen
label _save_screen:
$ _fn = _file_picker("save", renpy.saved_game_filenames() + [ None ] )
if not _fn or _yesno_prompt("save", _("Are you sure you want to overwrite your save?")):
python hide:
if save_name:
full_save_name = " - " + save_name
else:
full_save_name = ""
renpy.save(_fn, renpy.time.strftime("%b %d, %H:%M") +
full_save_name)
jump _save_screen
# Asks the user if he wants to quit.
label _quit_screen:
if _yesno_prompt("quit", _("Are you sure you want to end the game?")):
jump _quit
else:
jump _return
label _quit:
$ renpy.quit()
label _full_restart:
$ renpy.full_restart()
# Return to the game, after restoring the keymap.
label _return:
return
# Random nice things to have.
init:
$ centered = Character(None, what_style="centered_text", window_style="centered_window")
image text = renpy.ParameterizedText(style="centered_text")
+146
View File
@@ -0,0 +1,146 @@
# This file contains the code to implement the Ren'Py preferences
# screen.
init -450:
python:
# Used to collect the various preferences the system knows
# about.
library.left_preferences = [ ]
library.right_preferences = [ ]
class _Preference(object):
"""
This is a class that's used to represent a preference that
may be shown to the user.
"""
def __init__(self, name, field, values):
"""
@param name: The name of this preference. It will be
displayed to the user.
@param variable: The field on the _preferences object
that will be assigned the selected value. This field
must exist.
@param values: A list of value name, value, condition
triples. The value name is the name of this value that
will be shown to the user. The value is the literal
python value that will be assigned if this value is
selected. The condition is a condition that will be
evaluated to determine if this is a legal value. If no
conditions are true, this preference will not be
displayed to the user. A condition of None is always
considered to be True.
"""
self.name = name
self.field = field
self.values = values
def render_preference(self):
values = [ (name, val) for name, val, cond in self.values
if cond is None or renpy.eval(cond) ]
if not values:
return
ui.vbox(style='prefs_pref')
ui.text(_(self.name), style='prefs_label')
cur = getattr(_preferences, self.field)
for name, value in values:
style = 'button'
text_style = 'button_text'
if cur == value:
style = 'selected_button'
text_style = 'selected_button_text'
def clicked(value=value):
setattr(_preferences, self.field, value)
return True
ui.textbutton(_(name),
style=style,
text_style=text_style,
clicked=clicked)
ui.close()
python hide:
# Enablers for some preferences.
library.has_music = True
library.has_sound = True
library.has_transitions = True
p1 = _Preference('Display', 'fullscreen', [
('Window', False, None),
('Fullscreen', True, None),
])
p2 = _Preference('Music', 'music', [
('Enabled', True, 'library.has_music'),
('Disabled', False, 'library.has_music'),
])
p3 = _Preference('Sound Effects', 'sound', [
('Enabled', True, 'library.has_sound'),
('Disabled', False, 'library.has_sound'),
])
library.left_preferences = [ p1, p2, p3 ]
p4 = _Preference('CTRL Skips', 'skip_unseen', [
('Seen Messages', False, None),
('All Messages', True, None),
])
p5 = _Preference('Transitions', 'transitions', [
('All', 2, 'library.has_transitions'),
('Some', 1, 'library.has_transitions and default_transition'),
('None', 0, 'library.has_transitions'),
])
p6 = _Preference('Text Display', 'fast_text', [
('Fast', True, 'config.annoying_text_cps'),
('Slow', False, 'config.annoying_text_cps'),
])
library.right_preferences = [ p4, p5, p6 ]
label _prefs_screen:
python hide:
_game_nav("prefs")
ui.vbox(library.padding * 3, style='prefs_left')
for i in library.left_preferences:
i.render_preference()
ui.close()
ui.vbox(library.padding * 3, style='prefs_right')
for i in library.right_preferences:
i.render_preference()
ui.close()
_game_interact()
jump _prefs_screen
+348
View File
@@ -0,0 +1,348 @@
# This file is responsible for creating and defining the default styles
# used by the system.
# This file should be considered part of the Ren'Py library, and not
# something that needs to be modified by the user. Instead, just update
# the appropriate style property in an init: block in your script.
#
# For example, to change the default window backgrounds to a
# transparent dark red, add:
#
# init:
# $ style.window.background = renpy.Solid((128, 0, 0, 128)
#
# to your script. No need to mess around here, it will just make your
# life harder when a new version of Ren'Py is released.
init -250:
python hide:
style.create('default', None,
'The default style that all styles inherit from.')
# Text properties.
style.default.font = "Vera.ttf"
style.default.antialias = True
style.default.size = 22
style.default.color = (255, 255, 255, 255)
style.default.drop_shadow = (2, 2)
style.default.drop_shadow_color = (0, 0, 0, 128)
style.default.minwidth = 0
style.default.textalign = 0
style.default.text_y_fudge = 0
# Change this if you're not using Vera 22.
if renpy.windows():
style.default.line_height_fudge = -4
else:
style.default.line_height_fudge = 0
# Window properties.
style.default.background = None
style.default.xpadding = 0
style.default.ypadding = 0
style.default.xmargin = 0
style.default.ymargin = 0
style.default.xfill = False
style.default.yfill = False
style.default.xminimum = 0 # Includes margins and padding.
style.default.yminimum = 0 # Includes margins and padding.
# Placement properties.
style.default.xpos = 0
style.default.ypos = 0
style.default.xanchor = 'left'
style.default.yanchor = 'top'
# Sound properties.
style.default.hover_sound = None
style.default.activate_sound = None
# The base style for the large windows.
style.create('window', 'default',
'(window, placement) The base style for the windows that contain dialogue, thoughts, and menus.')
style.window.background = Solid((0, 0, 128, 128))
style.window.xpadding = 10
style.window.ypadding = 5
style.window.xmargin = 10
style.window.ymargin = 5
style.window.xfill = True
style.window.yfill = False
style.window.xminimum = 0 # Includes margins and padding.
style.window.yminimum = 150 # Includes margins and padding.
style.window.xpos = 0.5
style.window.ypos = 1.0
style.window.xanchor = 'center'
style.window.yanchor = 'bottom'
# This style controls the default placement of images on the screen.
style.create('image_placement', 'default',
'This style is used to control the default placement of images on the screen.')
style.image_placement.xpos = 0.5
style.image_placement.ypos = 1.0
style.image_placement.xanchor = 'center'
style.image_placement.yanchor = 'bottom'
# Styles that are used for dialogue.
style.create('say_label', 'default',
"""(text) The style that is used by default for
the label of dialogue. The label is used to
indicate who is saying something.""")
style.create('say_dialogue', 'default',
"""(text) The style that is used by default for
the text of dialogue.""")
style.create('say_thought', 'default',
"""(text) The label that is used by default for
the text of thoughts or narration, when no
speaker is given.""")
style.create('say_window', 'window',
'(window, position) The default style for windows containing dialogue and thoughts.')
# Styles that are used for menus.
style.create('menu_caption', 'default',
"""(text) The style that is used to render a menu
caption.""")
style.create('menu_choice', 'default',
"""(text, hover, sound) The style that is used to render a menu choice.""")
style.menu_choice.hover_color = (255, 255, 0, 255) # yellow
style.menu_choice.idle_color = (0, 255, 255, 255) # cyan
style.create('menu_window', 'window',
'(window, position) The default style for windows containing a menu.')
# Styles that are used by input widgets.
style.create('input_text', 'default',
'(text) The style used for the text of an input box.')
style.input_text.color = (255, 255, 0, 255)
style.create('input_prompt', 'default',
'(text) The style used for the prompt of an input box.')
style.create('input_window', 'window',
'(window, position) The style used for the window of an input box.')
# Styles used by centered.
style.create('centered_window', 'default',
'(window) The style that is used for a "window" containing centered text.')
style.create('centered_text', 'default',
'(text) The style used for centered text.')
style.centered_window.xpos = 0.5
style.centered_window.xanchor = 'center'
style.centered_window.xfill = False
style.centered_window.ypos = 0.5
style.centered_window.yanchor = 'center'
style.centered_window.yfill = False
style.centered_window.xpadding = 10
style.centered_text.textalign = 0.5
style.centered_text.xpos = 0.5
style.centered_text.ypos = 0.5
style.centered_text.xanchor = 'center'
style.centered_text.yanchor = 'center'
# Styles that are used by imagemaps
style.create('imagemap', 'image_placement',
'(sound, position) The style that is used for imagemaps.')
# Style that is used by imagebutttons.
style.create('image_button', 'default',
'(window, sound, hover) The default style used for image buttons.')
style.create('image_button_image', 'default',
'The default style used for images inside image buttons.')
# Styles that are used by all other Buttons.
style.create('button', 'default',
'(window, sound, hover) The default style used for buttons in the main and game menus.')
style.button.xpos = 0.5
style.button.xanchor = 'center'
style.create('button_text', 'default',
'(text, hover) The default style used for the label of a button.')
style.button_text.xpos = 0.5
style.button_text.xanchor = 'center'
style.button_text.size = 24
style.button_text.color = (0, 255, 255, 255)
style.button_text.hover_color = (128, 255, 255, 255)
# Selected button.
style.create('selected_button', 'button',
'(window, hover) The style that is used for a selected button (for example, the active screen or a chosen preference).')
style.create('selected_button_text', 'button_text',
'(text, hover) The style that is used for the label of a selected button.')
style.selected_button_text.color = (255, 255, 0, 255)
# Disabled button.
style.create('disabled_button', 'button',
'(window, hover) The style that is used for a disabled button.')
style.disabled_button.hover_sound = None
style.disabled_button.activate_sound = None
style.create('disabled_button_text', 'button_text',
'(text, hover) The style that is used for the label of a disabled button.')
style.disabled_button_text.color = (128, 128, 128, 255)
# Styles that are used when laying out the main menu.
style.create('mm_root_window', 'default',
'(window) The style used for the root window of the main menu. This is primarily used to set a background for the main menu.')
style.mm_root_window.background = Solid((0, 0, 0, 255))
style.create('mm_menu_window', 'default',
'(window, position) A window that contains the choices in the main menu. Change this to change the placement of these choices on the main menu screen.')
style.mm_menu_window.xpos = 0.9
style.mm_menu_window.xanchor = 'right'
style.mm_menu_window.ypos = 0.9
style.mm_menu_window.yanchor = 'bottom'
style.create('mm_button', 'button',
'(window, hover) The style that is used on buttons that are part of the main menu.')
style.create('mm_button_text', 'button_text',
'(text, hover) The style that is used for the labels of buttons that are part of the main menu.')
# Styles that are used to lay out the game menu.
style.create('gm_root_window', 'default',
'(window) The style used for the root window of the game menu. This is primarily used to change the background of the game menu.')
style.gm_root_window.background = Solid((0, 0, 0, 255))
style.create('gm_nav_window', 'default',
'(window, position) The style used by a window containing buttons that allow the user to navigate through the different screens of the game menu.')
style.gm_nav_window.xpos = 0.9
style.gm_nav_window.xanchor = 'right'
style.gm_nav_window.ypos = 0.95
style.gm_nav_window.yanchor = 'bottom'
style.create('file_picker_window', 'default',
'(window, position) A window containing the file picker that is used to choose slots for loading and saving.')
style.file_picker_window.xpos = 10
style.file_picker_window.xanchor = 'left'
style.file_picker_window.ypos = 10
style.file_picker_window.yanchor = 'top'
style.create('file_picker_image', 'default')
style.file_picker_image.xminimum = 280
style.create('file_picker_entry', 'button',
'(window, hover) The style that is used for each of the slots in the file picker.')
style.file_picker_entry.xpadding = 3
style.file_picker_entry.xminimum = 500
style.file_picker_entry.ymargin = 2
style.file_picker_entry.idle_background = Solid((255, 255, 255, 255))
style.file_picker_entry.hover_background = Solid((255, 255, 192, 255))
style.create('file_picker_text', 'default',
'(text) A base style for all text that is displayed in the file picker.')
style.file_picker_text.size = 18
style.create('file_picker_new', 'file_picker_text',
'(text) The style that is applied to the new indicator in the file picker.')
style.create('file_picker_old', 'file_picker_text',
'(text) The style that is applied to the old indicator in the file pciker.')
style.file_picker_new.color = (255, 192, 192, 255)
style.file_picker_old.color = (192, 192, 255, 255)
style.file_picker_new.minwidth = 30
style.file_picker_old.minwidth = 30
style.create('file_picker_extra_info', 'file_picker_text',
'(text) The style that is applied to extra info in the file picker. The extra info is the save time, and the save_name if one exists.')
style.file_picker_extra_info.color = (192, 192, 255, 255)
style.create('file_picker_new_slot', 'file_picker_text',
'(text) The style that is used for the new slot indicator in the file picker.')
style.create('yesno_prompt', 'default',
'(text, position) The style used for the prompt in a yes/no dialog.')
style.yesno_prompt.xpos = 0.5
style.yesno_prompt.xanchor = 'center'
style.yesno_prompt.ypos = 0.25
style.yesno_prompt.yanchor = 'center'
style.create('yesno_yes', 'button',
'(position) The position of the yes button on the screen.')
style.yesno_yes.xpos = 0.33
style.yesno_yes.xanchor = 'center'
style.yesno_yes.ypos = 0.33
style.yesno_yes.yanchor = 'center'
style.create('yesno_no', 'button',
'(position) The position of the no button on the screen.')
style.yesno_no.xpos = 0.66
style.yesno_no.xanchor = 'center'
style.yesno_no.ypos = 0.33
style.yesno_no.yanchor = 'center'
# Preferences
style.create('prefs_label', 'default',
'(text, position) The style that is applied to the label of a block of preferences.')
style.prefs_label.xpos = 0.5
style.prefs_label.xanchor = "center"
style.create('prefs_pref', 'default',
'(position) The position of the box containing an individual preference.')
style.prefs_pref.xpos = 0.5
style.prefs_pref.xanchor = 'center'
style.create('prefs_left', 'default',
'(position) The position of the left column of preferences.')
style.prefs_left.xpos = 0.25
style.prefs_left.xanchor = "center"
style.prefs_left.ypos = 0.05
style.prefs_left.yalign = "top"
style.create('prefs_right', 'default',
'(position) The position of the right column of preferences.')
style.prefs_right.xpos = 0.75
style.prefs_right.xanchor = "center"
style.prefs_right.ypos = 0.05
style.prefs_right.yalign = "top"
-2
View File
@@ -1,2 +0,0 @@
lib\windows-i686\python.exe -OO renpy.py
pause
+207
View File
@@ -0,0 +1,207 @@
init:
# Set up the size of the screen.
$ config.screen_width = 800
$ config.screen_height = 600
# Positions of things on the screen.
$ left = Position(xpos=0.0, xanchor='left')
$ right = Position(xpos=1.0, xanchor='right')
$ center = Position()
# Backgrounds.
image whitehouse = Image("whitehouse.jpg")
# Character pictures.
image eileen happy = Image("9a_happy.png")
image eileen vhappy = Image("9a_vhappy.png")
image eileen concerned = Image("9a_concerned.png")
# Character objects.
$ e = Character('Eileen', color=(200, 255, 200, 255))
# The actual game starts here.
label start:
$ renpy.music_start('sun-flower-slow-drag.mid')
scene whitehouse
show eileen vhappy
"Girl" "Welcome to Ren'Py 4!"
show eileen happy
"Girl" "And welcome to American Bishoujo's former southern base,
just outside of Washington, D.C."
show eileen happy at left
"Girl" "This isn't the view from our former base, but it'll do for
this demo."
show eileen happy
"Girl" "My name is Eileen, and while I plan to star in my own game
one day, for now I'm helping to introduce you to Ren'Py."
e "Ren'Py is an engine that makes it easy to write visual novel
games, by taking care of much of the hard work of writing a
game."
e "For example, displaying a line of dialogue is a single
statement. So is displaying a thought or narration."
"I understand."
e "Dialogue is easy to write. Just put a string on a line by
itself, or to the right of an object name or label string."
e "Since dialogue makes up the bulk of these games, we thought it
should be easy to write."
e "Ren'Py can also display menus that let you alter the flow of
the story."
menu:
"Why don't you try a menu out by picking a number?"
"1":
show eileen concerned
e "You picked one. I don't like odd numbers."
"2":
show eileen vhappy
e "You picked two. Even numbers are lucky!"
show eileen happy
e "There are a number of statements that control what's displayed
on the screen. The image statement is used to introduce
images with names."
scene
e "The scene statement can clear the screen..."
scene whitehouse
e "... or it can clear the screen and then show a background."
show eileen happy
e "The show statement is used to show pictures."
e "When the show statement is used on an image with the same first
name (called a tag) as one already shown, it replaces that picture."
show eileen vhappy
e "This makes it easy for characters to change emotions."
hide eileen
e "The hide statement hides an image."
show eileen happy at center
e "A new feature in Ren'Py 4 is the at clause on images, which
lets you say where you want to show the image at. I can go
from the center of the screen..."
show eileen happy at left
e "... to the left of the screen ..."
show eileen happy at right
e "... to the right of the screen ..."
show eileen happy
e "... and back to the center."
e "Ren'Py supports a variety of control statements, such as jump,
call, return, if, and while statements."
e "Rather than bore you with the details, i'll just tell you to
check grab the Ren'Py tutorial from http://www.bishoujo.us/renpy/."
e "That's just about it for writing scripts. Let me show you some
of the new engine features."
e "The first feature I can show off is the ability to go
full-screen. Hit the 'f' key to try it out, and hit 'f'
again to go back to a window."
show eileen vhappy
e "The next feature, rollback, is really neat."
show eileen happy
menu:
"Would you like to see it?"
"Yes.":
pass
"No.":
jump after_rollback
e "Rollback lets you play the game backwards."
e "It lets you go back and reread a line of dialogue you missed,
or even to go back to a menu and make a different choice if you
made a mistake."
e "We do limit the number of steps someone can rollback."
e "Try it out now, by hitting page up until you get back to the
menu, and then choose 'No' instead of 'Yes'."
show eileen concerned
e "Well, try it."
e "You want to hit page up."
e "Well, whatever, your loss. Moving on."
label after_rollback:
show eileen happy
e "Another new feature works only on Windows. If a game crashes,
a notepad is brought up showing the crash message, to help
you debug what went wrong."
e "The biggest new feature, though, is reasonable
documentation, which you can read at http://www.bishoujo.us/renpy/."
show eileen concerned
e "Since this is just a preview release, there are still a few
things missing."
e "For example, there's no support for loading or saving."
e "We also left out music and animations."
show eileen happy
e "Don't worry, though. Those will be coming in the final release,
which is due out in a few weeks."
e "You can begin making your own game by editing game/script.rpy. That's
the script for the game you're playing now."
e "After you make a change, you have to re-run the game to see
the change take effect."
show eileen vhappy
e "Good luck making your own games!"
return
+611
View File
@@ -0,0 +1,611 @@
# This script, but not the artwork associated with it, is in the
# public domain. Feel free to use it as the basis for your own
# game.
# If you're trying to understand this script, I recommend skipping
# down to the line beginning with 'label start:', at least on your
# first read-through.
# This init block runs first, and sets up all sorts of things that
# are used by the rest of the game. Variables that are set in init
# blocks are _not_ saved, unless they are changed later on in the
# program.
init:
# Set up the size of the screen, and the window title.
$ config.screen_width = 800
$ config.screen_height = 600
$ config.window_title = "The Ren'Py Demo Game"
# Change some styles, to add images in the background of
# the menus and windows.
$ style.mm_root_window.background = Image("mainmenu.jpg")
$ style.gm_root_window.background = Image("gamemenu.jpg")
$ style.window.background = Frame("frame.png", 125, 25)
# Change button styles.
$ style.button.background = Frame("button.png", 25, 10)
$ style.selected_button.background = Frame("button_checked.png", 25, 10)
$ del style.selected_button_text.color
$ style.button_text.drop_shadow = None
$ style.button_text.xpos = 28
$ style.button_text.xanchor = 'left'
$ style.button_text.ypos = 0.6
$ style.button_text.yanchor = 'center'
$ style.button_text.color = (255, 255, 255, 255)
$ style.button_text.hover_color = (255, 255, 0, 255)
$ style.button.xminimum = 250
# Change other styles.
$ style.prefs_label.color = (64, 64, 255, 255)
$ style.yesno_prompt.color = (64, 64, 255, 255)
$ style.file_picker_entry.xpos = 0
$ style.file_picker_entry.xanchor = 'left'
$ style.file_picker_entry.xminimum = 520
$ style.file_picker_text.xpos = 0
$ style.file_picker_text.ypos = 3
$ style.file_picker_text.drop_shadow = None
$ style.file_picker_entry.idle_background = Solid((0, 0, 192, 255))
$ style.file_picker_entry.hover_background = Solid((64, 64, 255, 255))
$ style.file_picker_old.color = (255, 255, 255, 255)
$ style.file_picker_extra_info.color = (255, 255, 255, 255)
$ style.file_picker_new_slot.color = (255, 255, 255, 255)
# These are positions that can be used inside at clauses. We set
# them up here so that they can be used throughout the program.
$ left = Position(xpos=0.0, xanchor='left')
$ right = Position(xpos=1.0, xanchor='right')
$ center = Position()
# Likewise, we set up some transitions that we can use in with
# clauses and statements.
$ fade = Fade(.5, 0, .5) # Fade to black and back.
$ dissolve = Dissolve(0.5)
# Now, we declare the images that are used in the program.
# Backgrounds.
image carillon = Image("carillon.jpg")
image whitehouse = Image("whitehouse.jpg")
image washington = Image("washington.jpg")
image black = Solid((0, 0, 0, 255))
# Character pictures.
image eileen happy = Image("9a_happy.png")
image eileen vhappy = Image("9a_vhappy.png")
image eileen concerned = Image("9a_concerned.png")
# Finally, the character object. This object lets us have the
# character say dialogue without us having to repeatedly type
# her name. It also lets us change the color of her name.
# Character objects.
$ e = Character('Eileen', color=(200, 255, 200, 255))
# The splashscreen is called, if it exists, before the main menu is
# shown the first time. It is not called if the game has restarted.
# We'll comment it out for now.
#
# label splashscreen:
# scene black
# show text "American Bishoujo Presents..." with fade
# $ renpy.pause(1.0)
# hide text with fade
#
# return
# The start label marks the place where the main menu jumps to to
# begin the actual game.
label start:
# The save_name variable sets the name of the save game. Like all
# variables declared outside of init blocks, this variable is
# saved and restored with a save file.
$ save_name = "Introduction"
# This variable is only used by our game. If it's true, it means
# that we won the date.
$ date = False
# Start some music playing in the background.
$ renpy.music_start('sun-flower-slow-drag.mid')
# Now, set up the first scene. We first fade in our washington
# background, and then we dissolve in the image of Eileen on top
# of it.
scene washington with fade
show eileen vhappy with dissolve
# Display a line of dialogue. In this case, we manually specify
# who's saying the line of dialoge.
"Girl" "Hi, and welcome to the Ren'Py 4 demo program."
# This instantly replaces the very happy picture of Eileen with
# one showing her merely happy. It demonstrates how the show
# statement lets characters change emotions.
show eileen happy
# Another line of dialogue.
"Girl" "My name is Eileen, and while I plan to one day star in a
real game, for now I'm here to tell you about Ren'Py."
# This line used the e character object, which displays Eileen's
# name in green. The use of a short name for a character object
# lets us save typing when writing the bulk of the dialogue.
e "Ren'Py is a language and engine for writing and playing visual
novel games."
e "Our goal is to allow people to be able to write the script for
a game, and with very little effort, turn that script into
a working game."
e "I can tell you about the features of Ren'Py games, or how to write
your own game. What do you want to know about?"
# This variable is used to save the choices that have been made in
# the main menu.
$ seen_set = [ ]
label choices:
# We change the save name here.
$ save_name = "Question Menu"
# This is the main menu, that lets the user decide what he wants
# to hear about.
menu:
# The set menu clause ensures that each menu choice can only
# be chosen once.
set seen_set
# This is a menu choice. When chosen, the statements in its
# block are executed.
"What are some features of Ren'Py games?":
# We call the features label. The from clause needs to be
# here to ensure that save games work, even after we
# change the script. It was added automatically.
call features from _call_features_1
# When we're done talking about features, jump back up
# to choices.
jump choices
# Another choice.
"How do I write my own games with it?":
call writing from _call_writing_1
jump choices
# This choice has a condition associated with it. It is only
# displayed if the condition is true (in this case, if we have
# selected at least one other choice has been chosen.)
"Where can I find out more?" if seen_set:
call find_out_more from _call_find_out_more_1
jump choices
"Why are we in Washington, DC?":
call washington from _call_washington_1
jump choices
"I think I've heard enough." if seen_set:
jump ending
# This is the section on writing games.
label writing:
# Change the title of the save games.
$ save_name = "Writing Games"
# We start off with a bunch of dialogue.
e "If you want to write a game, I recommend that you read the
Ren'Py tutorial, which you can get from our web page,
http://www.bishoujo.us/renpy/."
e "But here, we'll go over some of the basics of writing Ren'Py
scripts. It might make sense if you open the source for this
game."
e "The source for this game can be found in the file
game/script.rpy."
e "The goal of Ren'Py is to make writing the game similar to
typing up the script on the computer."
e "For example, a line of dialogue is expressed by putting the
character's name next to the dialogue string."
# A string by itself like this displays without a name associated
# with it. So it's useful for dialogue and narration.
"I somehow remember that strings by themselves are displayed as
thoughts or narration."
e "The menu statement makes it easy to create menus."
e "A number of statements let you control what is shown on the
screen."
# This scene statement has a with clause associated with it. In
# this case (based on what is defined in the init clause at the
# top of this script), it causes a fade to black, and then back
# to the new scene.
scene whitehouse with fade
e "The scene statement clears the scene list, which is the list of
things that are shown on the screen."
# This shows an image, and dissolves it in.
show eileen happy with dissolve
e "The show statement shows another image on the screen."
# The at clause here, displays the character on the left side of
# the screen.
show eileen happy at left with dissolve
e "Images can take at clauses that specify where on the screen
they are shown."
show eileen vhappy at left
e "Showing a new image with the same first part of the name
replaces the image in the scene list."
hide eileen with dissolve
e "Finally, the hide statement hides an image, which is useful
when a character leaves the scene."
show eileen happy with dissolve
e "Don't worry, I'm not going anywhere."
e "The with statement is used to cause transitions to
happen. Transitions like fade..."
# This statement hides the transient stuff from being included
# in the next fade.
with None
# This with statement causes things to fade without changing the
# scene.
with fade
e "... or dissolve ..."
# In this block, the scene statement clears the scene list. So we
# have to reshow the eileen happy image, so that it appears that
# just the background is dissolving. Sneaky.
with None
scene washington
show eileen happy
with dissolve
e "... are easily invoked."
e "As of version 4.2, Ren'Py supports image maps, which are like
another form of menu. Let's try one."
# This is an imagemap. It consists of two images, and a list of
# hotspots. For each hotspot we give the coordinates of the left,
# top, right, and bottom sides, and the value to return if it is
# picked.
$ result = renpy.imagemap("ground.png", "selected.png", [
(100, 100, 300, 400, "eileen"),
(500, 100, 700, 400, "lucy")
])
# We've assigned the chosen result from the imagemap to the
# result variable. We can use an if statement to vary what
# happens based on the user's choice.
if result == "eileen":
show eileen vhappy
e "You picked me!"
elif result == "lucy":
show eileen concerned
e "It looks like you picked Lucy."
# Eileen is being a bit possesive here. :-P
if date:
e "You can forget about Saturday."
$ date = False
show eileen happy
e "Ren'Py supports music, such as what's playing in the
background..."
# This plays a sound effect.
$ renpy.play("18005551212.wav")
e "... and sound effects, like the one that just played."
e "Ren'Py also includes a number of control statements, and even
lets you include python code."
e "Rather than go into this here, you can read all about it in the
tutorial."
e "If you want to make changes, you can edit the script for this
game by editing game/script.rpy"
e "When you've made a change, just re-run the game to see your
change in action."
e "Would you like to know about something else?"
# We return back up to the menu that lets the user pick a topic.
return
# This ends the well-commented portion of this script.
label features:
$ save_name = "Features"
e "By providing a range of useful features, we let game authors
focus on writing their games."
e "What are some of these features? Well, first of all, we take
care of displaying the screen, as well as dialogue and menus."
e "You can navigate through the game using the keyboard or the
mouse. If you've gotten this far, you've probably figured that
out already."
e "If you press 'f', you can toggle fullscreen mode. Pressing 'm'
will toggle music on and off."
e "Right-clicking or pressing escape will bring you to the game
menu."
e "The game menu lets you save or load the game. Ren'Py doesn't
limit the number of save slots available. You can create as
many slots as you can stand."
e "The game menu also lets you restart or quit the game. But you
wouldn't want to do that, would you?"
e "Finally, the game menu lets you set up the game
preferences. These preferences are saved between games."
show eileen vhappy
e "The next feature is really neat."
show eileen happy
menu rollback_menu:
"Would you like to hear about rollback?"
"Yes.":
pass
"No.":
jump after_rollback
e "Rollback is a feature that only Ren'Py has. It lets you go back
in time in a game."
e "For example, you can go back to a menu and save or make a
different choice."
e "You can access it by pressing page up or scrolling up on your
mouse wheel."
e "Why don't you try it by going back to the last menu and
choosing 'No.' instead of 'Yes.'"
e "Press page up or scroll up the mouse wheel."
show eileen concerned
e "Well, are you going to try it?"
e "Your loss."
e "Moving on."
label after_rollback:
show eileen happy
e "Ren'Py gives you a few ways of skipping dialogue. Pressing
control quickly skips dialogue you've seen at least once, ever."
e "Pressing page down or scrolling the mouse wheel down will let
you skip dialogue you've seen this session. This is useful
after a rollback."
e "If you want to try these, you might want to rollback a bit
first, so you can skip over something you've seen already."
e "Finally, Ren'Py has predictive image loading, so you rarely
have to wait for a new image to load."
e "Remember, all these features are built into the engine or
standard library. So every game written with Ren'Py has them."
e "Is there anything else you'd like to know about?"
return
label find_out_more:
$ save_name = "Find Out More"
e "There are a few places you can go to find out more about
Ren'Py."
e "The Ren'Py homepage, http://www.bishoujo.us/renpy/, is probably
the best place to start."
e "There, you can download new versions of Ren'Py, and read the
tutorial online."
e "If you have questions, the best place to ask them is the Ren'Py
forum of the Lemmasoft forums."
e "Just go to http://www.lemmasoft.net/forums/, and click on
Ren'Py."
e "We thank Blue Lemma for hosting our forum."
e "Finally, feel free to email or IM us if you need help. You can
get the addresses to use from http://www.bishoujo.us/renpy/."
e "We really want people to make their own games with Ren'Py, and
if there's anything we can do to help, just tell us."
e "Is there anything I can help you with now?"
return
label washington:
$ save_name = "Washington, DC"
e "We're in Washington, DC because over Summer 2004 American
Bishoujo's home base was just outside of DC."
scene whitehouse
show eileen happy at left
with fade
e "Even though we've moved back to New York, we took a bunch of
pictures, and decided to use them."
show eileen concerned at left
e "It was easier than drawing new pictures for this demo."
show eileen happy at left
e "Do you have a favorite landmark in or around DC?"
menu:
"The White House.":
e "I was supposed to go on a tour of the West Wing, once."
show eileen concerned
e "They wouldn't let us in."
e "The secret service guy who was supposed to show us
around was out of town that day."
e "Too bad."
"The National Mall.":
e "It's always fun to go down to the national mall."
e "You can visit the monuments, or see one of the
museums."
e "I guess you could run out of things to do after a while
but I didn't over the course of a summer."
"The Netherlands Carillon.":
jump netherlands
jump post_netherlands
label netherlands:
show eileen vhappy at left
e "You've been to the Netherlands Carillon?"
scene carillon
show eileen vhappy at left
with dissolve
e "It may not be much to look at but the sound of the bells is
really neat."
e "I love going there. Saturdays during the summer, they have
these recitals in the park where a guy comes and plays the
bells live."
e "You can climb to the top and talk to him, if you're not afraid
of heights."
e "Once, I saw a little girl there, maybe three or four years old.
The guy played the bumblebee song for here, and he even let her play the last
note. It was so cute!"
e "I haven't been there for so long."
menu:
"Would you like to go there sometime?":
e "You mean, together?"
e "Sure, why not. How does next Saturday sound?"
e "It's a date."
$ date = True
"That sounds nice.":
show eileen happy at left
e "Well, it is."
label post_netherlands:
scene washington
show eileen happy
with fade
e "Anyway, is there anything else you want to know about Ren'Py?"
return
label ending:
$ save_name = "Ending"
e "Well, that's okay."
e "I hope you'll consider using Ren'Py for your next game
project."
show eileen vhappy
e "Thanks for viewing this demo!"
if date:
e "And I'll see you on Saturday."
scene black with fade
"Ren'Py and the Ren'Py demo were written by PyTom."
'The background music is "Sun Flower Slow Drag" by S. Joplin
(1868-1917). Thanks to the Mutopia project for making it
available.'
'The author would like to thank everyone who makes original
English-language bishoujo games, and the people on the Lemmasoft forums
who encouraged him.'
"We can't wait to see what you do with this. Good luck!"
$ renpy.full_restart()
Executable → Regular
+100 -196
View File
@@ -1,225 +1,129 @@
#!/home/tom/bin/renpython -O
# Builds a distribution of Ren'Py.
import sys
import os.path
import os
import compileall
import shutil
import subprocess
import argparse
import sys
CWD = os.getcwdu()
def match_times(source, dest):
def copy_tutorial_file(src, dest):
"""
Copies a file from src to dst. Lines between "# tutorial-only" and
"# end-tutorial-only" comments are omitted from the copy.
"""
stat = os.stat(source)
os.utime(dest, (stat.st_atime, stat.st_mtime))
def dosify(s):
return s.replace("\n", "\r\n")
return s
sf = open(src, "rb")
df = open(dest, "wb")
def copy_file(source, dest, license=""):
# True if we want to copy the line.
copy = True
print source, "->", dest
for l in sf:
if "# tutorial-only" in l:
copy = False
elif "# end-tutorial-only" in l:
copy = True
else:
if copy:
df.write(l)
sf = file(source, "rb")
df = file(dest, "wb")
df.write(license)
data = sf.read()
if dest.endswith(".txt") or dest.endswith(".py") or dest.endswith(".rpy") or dest.endswith(".bat"):
data = dosify(data)
df.write(data)
sf.close()
df.close()
match_times(source, dest)
def copy_tree(source, dest, should_copy=lambda fn : True, license=""):
os.makedirs(dest)
for dirpath, dirnames, filenames in os.walk(source):
if "/saves" in dirpath:
continue
if "/CVS" in dirpath:
continue
reldir = dirpath[len(source):]
dstrel = dest + "/" + reldir
for i in dirnames:
if i == "CVS":
continue
os.mkdir(dstrel + "/" + i)
for i in filenames:
if not should_copy(i):
continue
copy_file(dirpath + "/" + i, dstrel + "/" + i, license=license)
def main():
if not sys.flags.optimize:
raise Exception("Not running with python optimization.")
target = sys.argv[1]
gamedir = sys.argv[2]
ap = argparse.ArgumentParser()
ap.add_argument("version")
ap.add_argument("--fast", action="store_true")
# Read license.
lf = file("LICENSE.txt")
license = "#!/usr/bin/env python\n\n"
for l in lf:
license += "# " + l
args = ap.parse_args()
lf.close()
# Revision updating is done early, so we can do it even if the rest
# of the program fails.
license = dosify(license)
# Determine the version. We grab the current revision, and if any
# file has changed, bump it by 1.
import renpy
if os.path.exists(target):
raise Exception("Target exists!")
match_version = ".".join(str(i) for i in renpy.version_tuple[:2]) #@UndefinedVariable
zip_version = ".".join(str(i) for i in renpy.version_tuple[:3]) #@UndefinedVariable
# Start off with the target.
copy_tree("dist", target,
should_copy = lambda fn : fn not in [ 'traceback.txt' ] and not fn.endswith(".log"))
s = subprocess.check_output([ "git", "describe", "--tags", "--dirty", "--match", match_version ])
parts = s.strip().split("-")
vc_version = int(parts[1])
# Copy renpy modules.
copy_tree("renpy", target + "/renpy",
should_copy = lambda fn : fn.endswith(".py"),
license=license)
if parts[-1] == "dirty":
vc_version += 1
doc_files = [
'example.html',
'tutorial.html',
'style.css',
]
with open("renpy/vc_version.py", "w") as f:
f.write("vc_version = {}".format(vc_version))
# Copy doc
copy_tree("doc", target + "/doc",
should_copy = lambda fn : fn in doc_files)
try:
reload(sys.modules['renpy.vc_version']) #@UndefinedVariable
except:
import renpy.vc_version # @UnusedImport
# Copy the game
copy_tree(gamedir, target + "/game",
should_copy = lambda fn : not fn.startswith(".") and not fn.endswith("~"))
reload(sys.modules['renpy'])
copy_tree("common", target + "/common",
should_copy = lambda fn : not fn.startswith(".") and not fn.endswith("~"))
# Check that the versions match.
full_version = ".".join(str(i) for i in renpy.version_tuple) #@UndefinedVariable
if args.version != "experimental" \
and not args.version.startswith("renpy-nightly-") \
and not full_version.startswith(args.version):
def cp(x, license=""):
copy_file(x, target + "/" + x)
raise Exception("The command-line and Ren'Py versions do not match.")
cp("CHANGELOG.txt")
cp("LICENSE.txt")
cp("README_RENPY.txt")
cp("archive_images.bat")
cp("run_game.py", license=license)
cp("archiver.py", license=license)
cp("build_exe.py", license=license)
cp("add_from.py", license=license)
cp("renpy-mode.el")
# The destination directory.
destination = os.path.join("dl", args.version)
print "Version {} ({})".format(args.version, full_version)
# Copy over the screens, to keep them up to date.
copy_tutorial_file("tutorial/game/screens.rpy", "templates/english/game/screens.rpy")
# Compile all the python files.
compileall.compile_dir("renpy/", ddir="renpy/", force=1, quiet=1)
# Generate launcher/game/script_version.rpy
with open("launcher/game/script_version.rpy", "w") as f:
f.write("init -999 python:\n")
f.write(" config.script_version = {!r}\n".format(renpy.version_tuple[:3])) # @UndefinedVariable
# Compile the various games.
if not args.fast:
for i in [ 'tutorial', 'launcher', 'templates/english', 'templates/japanese', 'the_question' ]:
print "Compiling", i
subprocess.check_call(["./renpy.sh", i, "quit" ])
if not os.path.exists(destination):
os.makedirs(destination)
if args.fast:
cmd = [
"./renpy.sh",
"launcher",
"distribute",
"launcher",
"--package",
"sdk",
"--destination",
destination,
"--no-update",
]
else:
cmd = [
"./renpy.sh",
"launcher",
"distribute",
"launcher",
"--destination",
destination,
]
print
subprocess.check_call(cmd)
# Kick off the rapt build.
if not args.fast:
out = open("/tmp/rapt_build.txt", "wb")
print("Building RAPT in the background.")
android = os.path.abspath("android")
rapt_build = subprocess.Popen([
os.path.join(android, "build_renpy.sh"),
zip_version
],
cwd = android,
stdout=out,
stderr=out)
else:
rapt_build = None
# Sign the update.
if not args.fast:
subprocess.check_call([
"scripts/sign_update.py",
"/home/tom/ab/keys/renpy_private.pem",
os.path.join(destination, "updates.json"),
])
# Write 7z.exe.
sdk = "renpy-{}-sdk".format(zip_version)
if not args.fast:
# shutil.copy("renpy-ppc.zip", os.path.join(destination, "renpy-ppc.zip"))
with open("7z.sfx", "rb") as f:
sfx = f.read()
os.chdir(destination)
if os.path.exists(sdk):
shutil.rmtree(sdk)
subprocess.check_call([ "unzip", "-q", sdk + ".zip" ])
if os.path.exists(sdk + ".7z"):
os.unlink(sdk + ".7z")
sys.stdout.write("Creating -sdk.7z")
p = subprocess.Popen([ "7z", "a", sdk +".7z", sdk], stdout=subprocess.PIPE)
for i, _l in enumerate(p.stdout):
if i % 10 != 0:
continue
sys.stdout.write(".")
sys.stdout.flush()
if p.wait() != 0:
raise Exception("7z failed")
with open(sdk + ".7z", "rb") as f:
data = f.read()
with open(sdk + ".7z.exe", "wb") as f:
f.write(sfx)
f.write(data)
os.unlink(sdk + ".7z")
shutil.rmtree(sdk)
else:
os.chdir(destination)
if os.path.exists(sdk + ".7z.exe"):
os.unlink(sdk + ".7z.exe")
print
if rapt_build:
code = rapt_build.wait()
if code:
print "RAPT build failed. The output is in /tmp/rapt_build.txt"
else:
print "RAPT build succeeded."
if __name__ == "__main__":
main()
+12
View File
@@ -0,0 +1,12 @@
all:: tutorial.html example.html
tutorial.html: tutorial.xml preprocess.py stylesheet.xslt style.css styles.xml
python preprocess.py tutorial.xml > tutorial.hi.xml
xsltproc stylesheet.xslt tutorial.hi.xml > tutorial.html
cp tutorial.html style.css ~/ab/website/renpy/devel/doc
example.html: example.xml preprocess.py stylesheet.xslt style.css styles.xml ../demo2/script.rpy
python preprocess.py example.xml > example.hi.xml
xsltproc stylesheet.xslt example.hi.xml > example.html
cp example.html style.css ~/ab/website/renpy/devel/doc
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<doc>
<title>Demo Script Example</title>
<p><a href="tutorial.html">Return to the tutorial.</a></p>
<example>
<!-- include ../demo2/script.rpy -->
</example>
<p><a href="tutorial.html">Return to the tutorial.</a></p>
</doc>
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/python
import re
import sys
import time
import inspect
sys.path.append('..')
import renpy
keywords = [
r'\bimage\b',
r'\bscene\b',
r'\bshow\b',
r'\bhide\b',
r'\binit\b',
r'\$',
r'\blabel\b',
r'\bmenu\b',
r'\bset\b',
r'\bif\b',
r'\bwhile\b',
r'\bjump\b',
r'\blabel\b',
r'\bcall\b',
r'\breturn\b',
r'\bfrom\b',
r'\belif\b',
r'\belse\b',
r'\bpass\b',
r'\bwith\b',
r'\bat\b',
r'\bpython\b',
]
kwre = '|'.join(keywords)
def example(m):
s = m.group(1)
rv = ""
pos = 0
while pos < len(s):
m = re.compile(r'(?s)"(([^"]|\\.)*)"').match(s, pos)
if m:
rv += '"<span class="string">%s</span>"' % m.group(1)
pos = m.end()
continue
m = re.compile(r"(?s)'(([^']|\\.)*)'").match(s, pos)
if m:
rv += '\'<span class="string">%s</span>\'' % m.group(1)
pos = m.end()
continue
m = re.compile(r"(?s)(#[^\n]+)").match(s, pos)
if m:
rv += '<span class="comment">%s</span>' % m.group(1)
pos = m.end()
continue
m = re.compile(kwre).match(s, pos)
if m:
rv += '<span class="keyword">%s</span>' % m.group(0)
pos = m.end()
continue
rv += s[pos]
pos += 1
return "<example>" + rv + "</example>"
def function(m):
name = m.group(1)
store = vars(renpy.store)
renpy.store.renpy = renpy.exports
func = eval(name, store)
doc = func.__doc__
if inspect.isclass(func):
func = func.__init__
if func.__doc__:
doc += "\n" + func.__doc__
a, b, c, d = inspect.getargspec(func)
args = inspect.formatargspec(a[1:], b, c, d)
else:
args = inspect.formatargspec(*inspect.getargspec(func))
docparas = []
for p in re.split(r'\n\s*\n', doc):
p = p.strip()
p = re.sub(r"\@param (\w+):", r'<param>\1</param> -', p)
p = "<p>" + p + "</p>"
docparas.append(p)
doc = '\n'.join(docparas)
return '<function name="%(name)s" sig="%(args)s">%(doc)s</function>' % locals()
def include(m):
f = file(m.group(1))
rv = f.read()
f.close()
return rv
def main():
f = file(sys.argv[1])
s = f.read()
f.close()
s = re.sub(r"<!-- func (\S+) -->", function, s)
s = re.sub(r"<!-- include (\S+) -->", include, s)
s = re.sub(r"<!-- date -->", time.strftime("%04Y-%02m-%02d %02H:%02M"), s)
s = re.sub(r"(?s)<example>(.*?)</example>", example, s)
print s
if __name__ == "__main__":
main()
+81
View File
@@ -0,0 +1,81 @@
BODY {
font-family: sans-serif;
}
H1 {
text-align: center;
margin-top: 2em;
margin-bottom: 2em;
}
H2 {
text-align: center;
margin-top: 1em;
margin-bottom: 1em;
}
PRE.example {
border: 2px black solid;
margin-left: 10%;
margin-right: 10%;
background: #f0f0f0;
padding: 1em;
padding-bottom: 0em;
}
DIV.rule {
border: 2px black solid;
margin-left: 10%;
margin-right: 10%;
margin-bottom: 1em;
background: #f0f0ff;
padding: 1em;
}
SPAN.comment {
color: #800000;
}
SPAN.string {
color: #006000;
}
SPAN.keyword {
color: #804000;
}
TD.funcname {
font-family: monospace;
font-weight: bold;
}
TD.funcsig {
font-family: monospace;
}
DIV.funcbody {
margin-left: 5%;
margin-bottom: 1em;
}
SPAN.param {
font-style: italic;
}
P.prop {
margin-left: 5%;
}
SPAN.propname {
font-family: monospace;
font-weight: bold;
}
DT {
margin-top: 1em;
}
DT.code {
font-family: monospace;
}
+165
View File
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- First, copy the element. -->
<xsl:template match="*" priority="-1">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- Now, handle some elements specially. -->
<xsl:template match="doc">
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<title><xsl:value-of select="title" /></title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="toc">
<ol>
<xsl:for-each select="../h3">
<li>
<a>
<xsl:attribute name="href">#<xsl:value-of select="." /></xsl:attribute>
<xsl:value-of select="."/>
</a>
</li>
</xsl:for-each>
</ol>
</xsl:template>
<xsl:template match="funcindex">
<ul>
<xsl:for-each select="//function">
<xsl:sort select="@name" />
<li>
<a>
<xsl:attribute name="href">#<xsl:value-of select="@name" /></xsl:attribute>
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="varindex">
<ul>
<xsl:for-each select="//var">
<xsl:sort select="@name" />
<li>
<a>
<xsl:attribute name="href">#<xsl:value-of select="@name" /></xsl:attribute>
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="styleindex">
<ul>
<xsl:for-each select="//renpy_style">
<xsl:sort select="@name" />
<li>
<a>
<xsl:attribute name="href">#<xsl:value-of select="@name" /></xsl:attribute>
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="propindex">
<ul>
<xsl:for-each select="//prop">
<xsl:sort select="@name" />
<li>
<a>
<xsl:attribute name="href">#<xsl:value-of select="@name" /></xsl:attribute>
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="h3">
<a>
<xsl:attribute name="name"><xsl:value-of select="." /></xsl:attribute>
<h3><xsl:apply-templates /></h3>
</a>
</xsl:template>
<xsl:template match="title">
<h1><xsl:apply-templates /></h1>
</xsl:template>
<xsl:template match="subtitle">
<h2><xsl:apply-templates /></h2>
</xsl:template>
<xsl:template match="def">
<b><i><xsl:apply-templates /></i></b>
</xsl:template>
<xsl:template match="example">
<pre class="example"><xsl:apply-templates /></pre>
</xsl:template>
<xsl:template match="rule">
<div class="rule"><xsl:apply-templates /></div>
</xsl:template>
<xsl:template match="function">
<a><xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute></a>
<table>
<tr>
<td valign="top" class="funcname"><xsl:value-of select="@name" /></td>
<td class="funcsig"><xsl:value-of select="@sig" />:</td>
</tr>
</table>
<div class="funcbody">
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template match="param">
<span class="param"><xsl:apply-templates /></span>
</xsl:template>
<xsl:template match="prop">
<a><xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute></a>
<p class="prop">
<span class="propname"><xsl:value-of select="@name" /></span>
--- <xsl:apply-templates />
</p>
</xsl:template>
<xsl:template match="renpy_style">
<a><xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute></a>
<dt><b><xsl:value-of select="@name" /></b>:</dt>
<dd><xsl:apply-templates /></dd>
</xsl:template>
<xsl:template match="renpy_style_inherits">
(inherits from <b><xsl:apply-templates /></b>) <br />
</xsl:template>
<xsl:template match="var">
<a><xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute></a>
<dt class="var"><b><xsl:value-of select="@name" /></b> = <xsl:value-of select="@value" /></dt>
<dd>
<xsl:apply-templates />
</dd>
</xsl:template>
</xsl:stylesheet>
+2768
View File
File diff suppressed because it is too large Load Diff
-128
View File
@@ -1,128 +0,0 @@
<html>
<head>
<title>README</title>
<style>
BODY {
background: #fff;
color: #444;
padding-left: 20%;
padding-top: 1em;
padding-bottom: 1em;
padding-right: 20%;
font-family: sans-serif;
line-height: 1.6em;
}
DT {
font-weight: bold;
margin-top: .33em;
}
H2 {
color: #000;
margin-left: -2.5em;
}
H3 {
color: #000;
margin-left: -1.5em;
}
.editsection {
display: none;
}
</style>
</head>
<body>
<div id="renpy_help"></div>
<p><a name="Basic_Help" id="Basic_Help"></a></p>
<h2><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=1" title="Edit section: Basic Help">edit</a>]</span> <span class="mw-headline">Basic Help</span></h2>
<p>To advance through the game, <tt>left-click</tt> or press the <tt>space</tt> or <tt>enter</tt> keys. When at a menu, <tt>left-click</tt> to make a choice, or use the arrow keys to select a choice and <tt>enter</tt> to activate it.</p>
<p><a name="Game_Menu" id="Game_Menu"></a></p>
<h3><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=2" title="Edit section: Game Menu">edit</a>]</span> <span class="mw-headline">Game Menu</span></h3>
<p>When playing a game, <tt>right-click</tt> or press the <tt>escape</tt> key to enter the game menu. The game menu gives the following choices:</p>
<dl>
<dt>Return</dt>
<dd>Returns to the game.</dd>
<dt>Save Game</dt>
<dd>Allows you to save a game by clicking on a save slot.</dd>
<dt>Load Game</dt>
<dd>Allows you to load a game by clicking on a save slot. Clicking on "Auto" accesses the automatic save slots.</dd>
<dt>Preferences</dt>
<dd>Changes the game preferences (options/configuration):
<dl>
<dt>Display</dt>
<dd>Switches between fullscreen and windowed mode.</dd>
<dt>Transitions</dt>
<dd>Controls the display of transitions between game screens.</dd>
<dt>Text Speed</dt>
<dd>Controls the rate at which text displays. The further to the right this slider is, the faster the text will display. All the way to the right causes text to be shown instantly.</dd>
<dt>Joystick</dt>
<dd>Lets you control the game using a joystick.</dd>
<dt>Skip</dt>
<dd>Chooses between skipping messages that have been already seen (in any play through the game), and skipping all messages.</dd>
<dt>Begin Skipping</dt>
<dd>Returns to the game, while skipping.</dd>
<dt>After Choices</dt>
<dd>Controls if skipping stops upon reaching a menu.</dd>
<dt>Auto-Forward Time</dt>
<dd>Controls automatic advance. The further to the left this slider is, the shorter the amount of time before the game advances. All the way to the right means text will never auto-forward.</dd>
<dt>Music, Sound, and Voice Volume</dt>
<dd>Controls the volume of the Music, Sound effect, and Voice channels, respectively. The further to the right these are, the louder the volume.</dd>
</dl>
</dd>
</dl>
<dl>
<dt>Main Menu</dt>
<dd>Returns to the main menu, ending the current game.</dd>
<dt>Help</dt>
<dd>Shows this help screen.</dd>
<dt>Quit</dt>
<dd>Exits the game; the game will be closed and ended.</dd>
</dl>
<p><a name="Key_and_Mouse_Bindings" id="Key_and_Mouse_Bindings"></a></p>
<h3><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=3" title="Edit section: Key and Mouse Bindings">edit</a>]</span> <span class="mw-headline">Key and Mouse Bindings</span></h3>
<dl>
<dt>Left-click, Enter</dt>
<dd>Advances through the game, activates menu choices, buttons, and sliders.</dd>
<dt>Space</dt>
<dd>Advances through the game, but does not activate choices.</dd>
<dt>Arrow Keys</dt>
<dd>Selects menu choices, buttons, and sliders.</dd>
<dt>Ctrl</dt>
<dd>Causes skipping to occur while the ctrl key is held down.</dd>
<dt>Tab</dt>
<dd>Toggles skipping, causing it to occur until tab is pressed again.</dd>
<dt>Mousewheel-Up, PageUp</dt>
<dd>Causes rollback to occur. Rollback reverses the game back in time, showing prior text and even allowing menu choices to be changed.</dd>
<dt>Mousewheel-Down, PageDown</dt>
<dd>Causes rollforward to occur, cancelling out a previous rollback.</dd>
<dt>Right-click, Escape</dt>
<dd>Enters the game menu. When in the game menu, returns to the game.</dd>
<dt>Middle-click, H</dt>
<dd>Hides the text window and other transient displays.</dd>
<dt>F</dt>
<dd>Toggles fullscreen mode</dd>
<dt>S</dt>
<dd>Takes a screenshot, saving it in a file named screenshotxxxx.png, where xxxx is a serial number.</dd>
<dt>Alt-M, Command-H</dt>
<dd>Hides (iconifies) the window.</dd>
<dt>Alt-F4, Command-Q</dt>
<dd>Quits the game.</dd>
<dt>Delete</dt>
<dd>When a save slot is selected, deletes that save slot.</dd>
</dl>
<p><a name="Legal_Notice" id="Legal_Notice"></a></p>
<h2><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=4" title="Edit section: Legal Notice">edit</a>]</span> <span class="mw-headline">Legal Notice</span></h2>
<p>This game uses source code from a number of open source projects. For a list, and a location where the source code can be downloaded from, please view the LICENSE.txt file in the renpy directory, or visit <a href="http://www.renpy.org/wiki/renpy/License" class="external free" title="http://www.renpy.org/wiki/renpy/License" rel="nofollow">http://www.renpy.org/wiki/renpy/License</a> .</p>
</body>
</html>
-4
View File
@@ -1,4 +0,0 @@
import renpy
# Do nothing when the editor is invoked.
Editor = renpy.editor.Editor
-4
View File
@@ -1,4 +0,0 @@
import renpy
# Pass the file off to the system editor (as determined by file associations).
Editor = renpy.editor.SystemEditor
-144
View File
@@ -1,144 +0,0 @@
import binascii
def a2b(a):
return binascii.a2b_hex(''.join(a.split()))
resources = {
260 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 c8 00 c0 80
02 00 00 00 00 00 b8 00 29 00 00 00 00 00 00 00
08 00 90 01 00 01 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 01 00 01 50 7f 00 14 00
32 00 0e 00 01 00 00 00 ff ff 80 00 4f 00 4b 00
00 00 00 00 00 00 00 00 00 00 00 00 04 08 00 50
07 00 07 00 aa 00 0c 00 ea 03 00 00 ff ff 81 00
00 00 00 00
'''),
261 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 c8 00 c0 80
04 00 00 00 00 00 b8 00 3a 00 00 00 00 00 00 00
08 00 90 01 00 01 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 80 00 81 50 07 00 14 00
aa 00 0c 00 ec 03 00 00 ff ff 81 00 00 00 00 00
00 00 00 00 00 00 00 00 01 00 01 50 7f 00 25 00
32 00 0e 00 01 00 00 00 ff ff 80 00 4f 00 4b 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 50
4a 00 25 00 32 00 0e 00 02 00 00 00 ff ff 80 00
43 00 61 00 6e 00 63 00 65 00 6c 00 00 00 00 00
00 00 00 00 00 00 00 00 04 08 00 50 07 00 07 00
aa 00 0c 00 eb 03 00 00 ff ff 81 00 00 00 00 00
'''),
262 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 c8 00 c0 80
04 00 00 00 00 00 b8 00 29 00 00 00 00 00 00 00
08 00 90 01 00 01 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 00 00 01 50 7f 00 14 00
32 00 0e 00 06 00 00 00 ff ff 80 00 59 00 65 00
73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
04 08 00 50 07 00 07 00 aa 00 0c 00 ed 03 00 00
ff ff 81 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 50 07 00 14 00 32 00 0e 00 07 00 00 00
ff ff 80 00 4e 00 6f 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 50 4b 00 14 00 32 00 0e 00
02 00 00 00 ff ff 80 00 43 00 61 00 6e 00 63 00
65 00 6c 00 00 00 00 00
'''),
263 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 80 00 ca 80
03 00 00 00 00 00 e2 00 29 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 81 50 07 00 14 00
97 00 0e 00 eb 03 00 00 6d 00 73 00 63 00 74 00
6c 00 73 00 5f 00 70 00 72 00 6f 00 67 00 72 00
65 00 73 00 73 00 33 00 32 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 04 08 00 50 07 00 07 00
d4 00 0c 00 ea 03 00 00 ff ff 81 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 50 a9 00 14 00
32 00 0e 00 02 00 00 00 ff ff 80 00 43 00 61 00
6e 00 63 00 65 00 6c 00 00 00 00 00
'''),
264 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 c8 00 c0 80
04 00 00 00 00 00 b8 00 3a 00 00 00 00 00 00 00
08 00 90 01 00 01 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 a0 00 81 50 07 00 14 00
aa 00 0c 00 ec 03 00 00 ff ff 81 00 00 00 00 00
00 00 00 00 00 00 00 00 01 00 01 50 7f 00 25 00
32 00 0e 00 01 00 00 00 ff ff 80 00 4f 00 4b 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 50
4a 00 25 00 32 00 0e 00 02 00 00 00 ff ff 80 00
43 00 61 00 6e 00 63 00 65 00 6c 00 00 00 00 00
00 00 00 00 00 00 00 00 04 08 00 50 07 00 07 00
aa 00 0c 00 eb 03 00 00 ff ff 81 00 00 00 00 00
'''),
265 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 c8 00 c8 80
12 00 00 00 00 00 d9 00 fc 00 00 00 00 00 00 00
08 00 90 01 00 01 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 01 00 01 50 6c 00 ea 00
30 00 0e 00 01 00 00 00 ff ff 80 00 4f 00 4b 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 50
a2 00 ea 00 30 00 0e 00 02 00 00 00 ff ff 80 00
43 00 61 00 6e 00 63 00 65 00 6c 00 00 00 00 00
00 00 00 00 00 00 00 00 07 00 00 50 06 00 06 00
cc 00 4e 00 ff ff ff ff ff ff 80 00 00 00 00 00
00 00 00 00 00 00 00 00 03 00 21 50 48 00 12 00
84 00 64 00 03 00 00 00 ff ff 85 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 02 50 0c 00 24 00
c0 00 08 00 04 00 00 00 ff ff 82 00 00 00 00 00
00 00 00 00 00 00 00 00 80 00 81 50 0c 00 30 00
c0 00 0e 00 05 00 00 00 ff ff 81 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 50 9c 00 42 00
30 00 0e 00 06 00 00 00 ff ff 80 00 41 00 64 00
64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
07 00 00 50 06 00 54 00 cb 00 3c 00 ff ff ff ff
ff ff 80 00 00 00 00 00 00 00 00 00 00 00 00 00
03 00 21 50 48 00 61 00 84 00 64 00 07 00 00 00
ff ff 85 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 02 50 0c 00 72 00 c0 00 08 00 08 00 00 00
ff ff 82 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 50 9c 00 7e 00 30 00 0e 00 09 00 00 00
ff ff 80 00 41 00 64 00 64 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 50 06 00 96 00
42 00 0e 00 0a 00 00 00 ff ff 80 00 41 00 64 00
64 00 20 00 66 00 69 00 6c 00 65 00 2e 00 2e 00
2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 50 4e 00 96 00 42 00 0e 00 0b 00 00 00
ff ff 80 00 41 00 64 00 64 00 20 00 6e 00 65 00
77 00 20 00 66 00 69 00 6c 00 65 00 2e 00 2e 00
2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 50 06 00 a8 00 42 00 0e 00 0c 00 00 00
ff ff 80 00 41 00 64 00 64 00 20 00 66 00 6f 00
6c 00 64 00 65 00 72 00 2e 00 2e 00 2e 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 50
06 00 c6 00 cc 00 1e 00 ff ff ff ff ff ff 80 00
43 00 6f 00 6d 00 6d 00 61 00 6e 00 64 00 20 00
6c 00 69 00 6e 00 65 00 3a 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 80 00 81 50 0c 00 d2 00
c0 00 0e 00 0e 00 00 00 ff ff 81 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 02 50 0c 00 14 00
3c 00 08 00 1e 00 00 00 ff ff 82 00 4f 00 70 00
74 00 69 00 6f 00 6e 00 3a 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 02 50 0c 00 63 00
3c 00 08 00 46 00 00 00 ff ff 82 00 43 00 6f 00
6d 00 6d 00 61 00 6e 00 64 00 3a 00 00 00 00 00
'''),
270 : a2b('''
01 00 ff ff 00 00 00 00 00 00 00 00 48 04 00 44
02 00 00 00 00 00 23 01 1a 00 00 00 00 00 00 00
08 00 00 00 00 00 4d 00 53 00 20 00 53 00 68 00
65 00 6c 00 6c 00 20 00 44 00 6c 00 67 00 00 00
00 00 00 00 00 00 00 00 01 00 02 50 00 00 07 00
23 01 08 00 ff ff ff ff ff ff 82 00 53 00 74 00
61 00 74 00 69 00 63 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 02 40 00 00 12 00 23 01 08 00
5f 04 00 00 ff ff 82 00 73 00 74 00 63 00 33 00
32 00 00 00 00 00
'''),
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
-27
View File
@@ -1,27 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Checks for various abilities that might be taken away from us by
# redistributors.
init 1 python in ability:
from store import config
import store
import store.updater as updater
import os
EXECUTABLES = [ "renpy.exe", "renpy.app", "renpy.sh" ]
# can_distribute - True if we can distribute
for i in EXECUTABLES:
if not os.path.exists(os.path.join(config.renpy_base, i)):
can_distribute = False
else:
can_distribute = True
# can_update - True if we can update.
can_update = updater.can_update() or (store.UPDATE_SIMULATE is not None)
-31
View File
@@ -1,31 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
screen about:
$ version = renpy.version()
frame:
style_group "l"
style "l_root"
window:
xfill True
has vbox xfill True
add "logo.png" xalign 0.5 yoffset -5
null height 15
text _("[version!q]") xalign 0.5 bold True
null height 20
textbutton _("View license") action interface.OpenLicense() xalign 0.5
textbutton _("Back") action Jump("front_page") style "l_left_button"
label about:
call screen about
-36
View File
@@ -1,36 +0,0 @@
label add_file:
python hide:
import os
import codecs
filename = interface.input(_("FILENAME"), _("Enter the name of the script file to create."), filename="withslash", cancel=Jump("navigation"))
if "." in filename and not filename.endswith(".rpy"):
interface.error(_("The filename must have the .rpy extension."), label="navigation")
elif "." not in filename:
filename += ".rpy"
path = os.path.join(project.current.gamedir, filename)
dir = os.path.dirname(path)
if os.path.exists(path):
interface.error(_("The file already exists."), label="navigation")
contents = u"\uFEFF"
contents += _("# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n")
contents += "\n"
try:
os.makedirs(dir)
except:
pass
contents = u"\uFEFF"
contents += _("# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n")
with open(path, "wb") as f:
f.write(contents.encode("utf-8"))
jump navigation_refresh
-502
View File
@@ -1,502 +0,0 @@
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
ANDROID_NO_JDK = 0
ANDROID_NO_RAPT = 1
ANDROID_NO_SDK = 2
ANDROID_NO_KEY = 3
ANDROID_NO_CONFIG = 4
ANDROID_OK = 5
NO_JDK_TEXT = _("A 32-bit Java Development Kit is required to build Android packages on Windows. The JDK is different from the JRE, so it's possible you have Java without having the JDK.\n\nPlease {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}download and install the JDK{/a}, then restart the Ren'Py launcher.")
NO_RAPT_TEXT = _("To build Android packages, please download RAPT (from {a=http://www.renpy.org/dl/android}here{/a}), unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher.")
NO_SDK_TEXT = _("RAPT has been installed, but you'll need to install the Android SDK before you can build Android packages. Choose Install SDK to do this.")
NO_KEY_TEXT = _("RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore.")
NO_CONFIG_TEXT = _("The current project has not been configured. Use \"Configure\" to configure it before building.")
OK_TEXT = _("Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device.")
PHONE_TEXT = _("Attempts to emulate an Android phone.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button.")
TABLET_TEXT = _("Attempts to emulate an Android tablet.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button.")
OUYA_TEXT = _("Attempts to emulate an OUYA console.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button.")
INSTALL_SDK_TEXT = _("Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package.")
CONFIGURE_TEXT = _("Configures the package name, version, and other information about this project.")
PLAY_KEYS_TEXT = _("Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details.")
BUILD_TEXT = _("Builds the Android package.")
BUILD_AND_INSTALL_TEXT = _("Builds the Android package, and installs it on an Android device connected to your computer.")
import subprocess
import re
import os
import json
def find_rapt():
global RAPT_PATH
candidates = [ ]
for fn in os.listdir(config.renpy_base):
if not fn.startswith("rapt-"):
continue
if not os.path.isdir(os.path.join(config.renpy_base, fn)):
continue
try:
version = fn[5:]
version = tuple(int(i) for i in version.split('.'))
except ValueError:
continue
candidates.append((version, fn))
if not candidates:
RAPT_PATH = None
else:
RAPT_PATH = os.path.join(config.renpy_base, candidates[-1][1])
import sys
sys.path.insert(0, os.path.join(RAPT_PATH, "buildlib"))
find_rapt()
import threading
if RAPT_PATH:
import rapt
import rapt.build
import rapt.configure
import rapt.install_sdk
import rapt.plat
else:
rapt = None
def AndroidState():
"""
Determines the state of the android install, and returns it.
"""
if renpy.windows and not "JAVA_HOME" in os.environ:
return ANDROID_NO_JDK
if RAPT_PATH is None:
return ANDROID_NO_RAPT
if not os.path.exists(os.path.join(RAPT_PATH, "android-sdk/extras/google/play_licensing")):
return ANDROID_NO_SDK
if not os.path.exists(os.path.join(RAPT_PATH, "android.keystore")):
return ANDROID_NO_KEY
if not os.path.exists(os.path.join(project.current.path, ".android.json")):
return ANDROID_NO_CONFIG
return ANDROID_OK
def AndroidStateText(state):
"""
Returns text corresponding to the state.
"""
if state == ANDROID_NO_JDK:
return NO_JDK_TEXT
if state == ANDROID_NO_RAPT:
return NO_RAPT_TEXT
if state == ANDROID_NO_SDK:
return NO_SDK_TEXT
if state == ANDROID_NO_KEY:
return NO_KEY_TEXT
if state == ANDROID_NO_CONFIG:
return NO_CONFIG_TEXT
if state == ANDROID_OK:
return OK_TEXT
def AndroidIfState(state, needed, action):
"""
If `state` is `needed` or better, `action` is returned. Otherwise,
returns None, disabling the button.
"""
if state >= needed:
return action
else:
return None
class AndroidInterface(object):
def __init__(self):
self.process = None
self.filename = project.current.temp_filename("android.txt")
self.info_msg = ""
with open(self.filename, "w"):
pass
def info(self, prompt):
self.info_msg = prompt
interface.processing(prompt, pause=False)
def yesno(self, prompt, submessage=None):
return interface.yesno(prompt, submessage=submessage)
def yesno_choice(self, prompt, default=None):
choices = [ (True, "Yes"), (False, "No") ]
return interface.choice(prompt, choices, default)
def terms(self, url, prompt):
submessage = _("{a=%s}%s{/a}") % (url, url)
return interface.yesno(prompt, submessage=submessage)
def input(self, prompt, empty=None):
if empty is None:
empty = ''
while True:
rv = interface.input(_("QUESTION"), prompt, default=empty, cancel=Jump("android"))
rv = rv.strip()
if rv:
return rv
def choice(self, prompt, choices, default):
return interface.choice(prompt, choices, default, cancel=Jump("android"))
def fail(self, prompt):
prompt = re.sub(r'(http://\S+)', r'{a=\1}\1{/a}', prompt)
# Open android.txt in the editor.
editor.EditAbsolute(self.filename)()
interface.error(prompt, label="android")
def success(self, prompt):
interface.info(prompt, pause=False)
def final_success(self, prompt):
interface.info(prompt, label="android")
def call(self, cmd, cancel=False, use_path=False):
if not use_path:
cmd = [ rapt.plat.path(cmd[0]) ] + list(cmd[1:])
self.cmd = cmd
f = open(self.filename, "a")
f.write("\n\n\n")
if cancel:
cancel_action = self.cancel
else:
cancel_action = None
startupinfo = None
if renpy.windows:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
try:
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action)
self.process = subprocess.Popen(cmd, cwd=RAPT_PATH, stdout=f, stderr=f, startupinfo=startupinfo)
renpy.call_screen("android_process", interface=self)
finally:
f.close()
interface.hide_screen()
self.process = None
def check_process(self):
rv = self.process.poll()
if rv is not None:
if rv:
raise subprocess.CalledProcessError(rv, self.cmd)
else:
return True
def download(self, url, dest):
try:
d = Downloader(url, dest)
cancel_action = [ d.cancel, Jump("android") ]
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action, bar_value=DownloaderValue(d))
ui.timer(.1, action=d.check, repeat=True)
ui.interact()
finally:
interface.hide_screen()
def background(self, f):
try:
t = threading.Thread(target=f)
t.start()
interface.processing(self.info_msg, show_screen=True)
while t.is_alive():
renpy.pause(0)
t.join(0.25)
finally:
interface.hide_screen()
def cancel(self):
if self.process:
self.process.terminate()
renpy.jump("android")
class AndroidBuild(Action):
"""
Activates an Android build process.
"""
def __init__(self, label):
self.label = label
def __call__(self):
renpy.jump(self.label)
class LaunchEmulator(Action):
def __init__(self, emulator, variants):
self.emulator = emulator
self.variants = variants
def __call__(self):
env = {
"RENPY_EMULATOR" : self.emulator,
"RENPY_VARIANT" : self.variants,
}
p = project.current
p.launch(env=env)
def update_android_json():
"""
Updates .android.json to include the google play information.
"""
project.current.update_dump(True)
build = project.current.dump["build"]
filename = os.path.join(project.current.path, ".android.json")
with open(filename, "r") as f:
android_json = json.load(f)
if "google_play_key" in build:
android_json["google_play_key"] = build["google_play_key"]
else:
android_json.pop("google_play_key", None)
if "google_play_salt" in build:
if len(build["google_play_salt"]) != 20:
raise Exception("build.google_play_salt must be exactly 20 bytes long.")
android_json["google_play_salt"] = ", ".join(str(i) for i in build["google_play_salt"])
else:
android_json.pop("google_play_salt", None)
with open(filename, "w") as f:
json.dump(android_json, f)
def android_build(command):
"""
This actually builds the package.
"""
update_android_json()
dist = project.current.temp_filename("android.dist")
if os.path.exists(dist):
shutil.rmtree(dist)
distribute.Distributor(project.current,
reporter=distribute.GuiReporter(),
packages=[ 'android' ],
build_update=False,
noarchive=True,
packagedest=dist,
report_success=False,
)
with interface.nolinks():
rapt.build.build(AndroidInterface(), dist, command)
# The android support can stick unicode into os.environ. Fix that.
init 100 python:
for k, v in list(os.environ.items()):
if isinstance(v, str):
os.environ[k] = renpy.fsencode(v)
screen android_process(interface):
zorder 100
default ft = FileTail(interface.filename)
text "[ft.text!q]":
size 14
color TEXT
font "Roboto-Light.ttf"
xpos 75
ypos 350
timer .1 action interface.check_process repeat True
timer .2 action ft.update repeat True
screen android:
default tt = Tooltip(None)
$ state = AndroidState()
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Android: [project.current.name!q]")
add HALF_SPACER
hbox:
# Left side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Emulation:")
add HALF_SPACER
frame style "l_indent":
has vbox
textbutton _("Phone"):
action LaunchEmulator("touch", "small phone touch android")
hovered tt.Action(PHONE_TEXT)
textbutton _("Tablet"):
action LaunchEmulator("touch", "medium tablet touch android")
hovered tt.Action(TABLET_TEXT)
textbutton _("Television / OUYA"):
action LaunchEmulator("tv", "small tv ouya android")
hovered tt.Action(OUYA_TEXT)
add SPACER
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Build:")
add HALF_SPACER
frame style "l_indent":
has vbox
textbutton _("Install SDK & Create Keys"):
action AndroidIfState(state, ANDROID_NO_SDK, Jump("android_installsdk"))
hovered tt.Action(INSTALL_SDK_TEXT)
textbutton _("Configure"):
action AndroidIfState(state, ANDROID_NO_CONFIG, Jump("android_configure"))
hovered tt.Action(CONFIGURE_TEXT)
textbutton _("Build Package"):
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build"))
hovered tt.Action(BUILD_TEXT)
textbutton _("Build & Install"):
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_and_install"))
hovered tt.Action(BUILD_AND_INSTALL_TEXT)
# Right side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
has vbox
add SPACER
if tt.value:
text tt.value
else:
text AndroidStateText(state)
textbutton _("Back") action Jump("front_page") style "l_left_button"
label android:
call screen android
label android_installsdk:
python:
with interface.nolinks():
rapt.install_sdk.install_sdk(AndroidInterface())
jump android
label android_configure:
python:
rapt.configure.configure(AndroidInterface(), project.current.path)
jump android
label android_build:
$ android_build([ 'release' ])
jump android
label android_build_and_install:
$ android_build([ 'release', 'install' ])
jump android
-67
View File
@@ -1,67 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Ren'Py archiver. This builds a Ren'Py archive file, and the
# associated index file. These files are really easy to
# reverse-engineer, but are probably better than nothing.
init python in archiver:
import sys
import random
import glob
from cPickle import dumps, HIGHEST_PROTOCOL
class Archive(object):
"""
Adds files from disk to a rpa archive.
"""
def __init__(self, filename):
# The archive file.
self.f = open(filename, "wb")
# The index to the file.
self.index = _dict()
# A fixed key minimizes difference between archive versions.
self.key = 0x42424242
padding = "RPA-3.0 XXXXXXXXXXXXXXXX XXXXXXXX\n"
self.f.write(padding)
def add(self, name, path):
"""
Adds a file to the archive.
"""
self.index[name] = _list()
with open(path, "rb") as df:
data = df.read()
dlen = len(data)
# Pad.
padding = "Made with Ren'Py."
self.f.write(padding)
offset = self.f.tell()
self.f.write(data)
self.index[name].append((offset ^ self.key, dlen ^ self.key, ""))
def close(self):
indexoff = self.f.tell()
self.f.write(dumps(self.index, HIGHEST_PROTOCOL).encode("zlib"))
self.f.seek(0)
self.f.write("RPA-3.0 %016x %08x\n" % (indexoff, self.key))
self.f.close()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

-328
View File
@@ -1,328 +0,0 @@
# http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html
# Contains a reasonable description of the format.
import struct
import sys
import array
import pefile # @UnresolvedImport
# This class performs various operations on memory-loaded binary files,
# including modifications.
class BinFile(object):
def set_u32(self, addr, value):
self.a[addr+0] = (value >> 0) & 0xff
self.a[addr+1] = (value >> 8) & 0xff
self.a[addr+2] = (value >> 16) & 0xff
self.a[addr+3] = (value >> 24) & 0xff
def u32(self):
addr = self.addr
rv = self.a[addr]
rv |= self.a[addr+1] << 8
rv |= self.a[addr+2] << 16
rv |= self.a[addr+3] << 24
self.addr += 4
return rv
def u16(self):
addr = self.addr
rv = self.a[addr]
rv |= self.a[addr+1] << 8
self.addr += 2
return rv
def u8(self):
rv = self.a[self.addr]
self.addr += 1
return rv
def name(self):
c = self.u16()
rv = u""
for _i in range(c):
rv += unichr(self.u16())
return rv
def seek(self, addr):
self.addr = addr
def tostring(self):
return self.a.tostring()
def substring(self, start, len): #@ReservedAssignment
return self.a[start:start+len].tostring()
def __init__(self, data):
self.a = array.array('B')
self.a.fromstring(data)
##############################################################################
# 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(bf, offset):
bf.seek(offset)
data_offset = bf.u32()
data_len = bf.u32()
code_page = bf.u32()
bf.u32()
l = [ ]
bf.seek(data_offset - resource_virtual)
for _i in range(data_len):
l.append(chr(bf.u8()))
return (code_page, "".join(l))
# This parses a resource directory.
def parse_directory(bf, offset):
bf.seek(offset)
char = bf.u32() #@UnusedVariable
timedate = bf.u32() #@UnusedVariable
major = bf.u16() #@UnusedVariable
minor = bf.u16() #@UnusedVariable
n_named = bf.u16()
n_id = bf.u16()
entries = [ ]
for _i in range(n_named + n_id):
entries.append((bf.u32(), bf.u32()))
rv = { }
for name, value in entries:
if name & 0x80000000:
bf.seek((name & 0x7fffffff))
name = bf.name()
if value & 0x80000000:
value = parse_directory(bf, value & 0x7fffffff)
else:
value = parse_data(bf, value)
rv[name] = value
return rv
##############################################################################
# This utility function displays the tree of resources that have been loaded.
def show_resources(d, prefix):
if not isinstance(d, dict):
print prefix, "Codepage", d[0], "length", len(d[1])
return
for k in d:
print prefix, k
show_resources(d[k], prefix + " ")
##############################################################################
# These functions repack the resources into a new resource segment. Here,
# the offset is relative to the start of the resource segment.
class Packer(object):
def pack(self, d):
self.data = ""
self.data_offset = 0
self.entries = ""
self.entries_offset = 0
head = self.pack_dict(d, 0)
self.data = ""
self.data_offset = len(head) + len(self.entries)
self.entries = ""
self.entries_offset = len(head)
return self.pack_dict(d, 0) + self.entries + self.data
def pack_name(self, s):
rv = self.data_offset + len(self.data)
l = len(s)
s = s.encode("utf-16le")
self.data += struct.pack("<H", l) + s + "\0\0"
return rv
def pack_tuple(self, t):
codepage, data = t
rv = len(self.entries) + self.entries_offset
if len(self.data) % 2:
self.data += "P"
daddr = len(self.data) + self.data_offset
self.entries += struct.pack("<IIII", daddr + resource_virtual, len(data), codepage, 0)
self.data += data
# if len(self.data) % 1 == 1:
# self.data += 'P'
return rv
def pack_dict(self, d, offset):
name_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, unicode))
id_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, int))
rv = struct.pack("<IIHHHH", 0, 0, 4, 0, len(name_entries), len(id_entries))
offset += len(rv) + (len(name_entries) + len(id_entries)) * 8
rest = ""
for (name, value) in name_entries + id_entries:
if isinstance(name, unicode):
name = 0x80000000 | self.pack_name(name)
if isinstance(value, dict):
addr = offset | 0x80000000
packed = self.pack_dict(value, offset)
offset += len(packed)
rest += packed
else:
addr = self.pack_tuple(value)
rv += struct.pack("<II", name, addr)
return rv + rest
##############################################################################
# This loads in an icon file, and returns a dictionary that is suitable for
# use in the resources of an exe file.
def load_icon(fn):
f = BinFile(file(fn, "rb").read())
f.seek(0)
f.u16()
f.u16()
count = f.u16()
rv = { }
rv[3] = { }
group = struct.pack("HHH", 0, 1, count)
for i in range(count):
width = f.u8()
height = f.u8()
colors = f.u8()
reserved = f.u8()
planes = f.u16()
bpp = f.u16()
size = f.u32()
offset = f.u32()
addr = f.addr
f.seek(offset + 16)
if not f.u32():
f.set_u32(offset + 20, 0)
rv[3][i + 1] = { 0 : (1252, f.substring(offset, size)) }
group += struct.pack("BBBBHHIH", width, height, colors, reserved,
planes, bpp, size, i + 1)
f.seek(addr)
rv[14] = { 1 : { 0 : (1252, group) } }
return rv
##############################################################################
# This is the main function that should be called externally, that copies over
# the icons.
def change_icons(oldexe, icofn):
global resource_virtual
pe = pefile.PE(oldexe)
for s in pe.sections:
if s.Name == ".rsrc\0\0\0":
rsrc_section = s
break
else:
raise Exception("Couldn't find resource section.")
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, "")
rsrc = Packer().pack(resources)
alignment = pe.OPTIONAL_HEADER.SectionAlignment
# print "Alignment is", alignment
if len(rsrc) % alignment:
pad = alignment - (len(rsrc) % alignment)
padding = "RENPYVNE" * (pad / 8 + 1)
padding = padding[:pad]
rsrc += padding
newsize = len(rsrc)
rsrc_section.Misc_VirtualSize += newsize - virsize
rsrc_section.Misc_PhysicalAddress += newsize - virsize
rsrc_section.Misc += newsize - virsize
rsrc_section.SizeOfRawData += newsize - physize
pe.OPTIONAL_HEADER.SizeOfInitializedData += newsize - physize
# Resource size.
pe.OPTIONAL_HEADER.DATA_DIRECTORY[2].Size += newsize - virsize
# Compute the total size of the image.
total_size = 0
for i in pe.sections:
sec_size = i.Misc_VirtualSize
sec_size = sec_size - (sec_size % alignment) + alignment
total_size += sec_size
pe.OPTIONAL_HEADER.SizeOfImage = total_size
return pe.write()[:base] + rsrc
if __name__ == "__main__":
f = file(sys.argv[3], "wb")
f.write(change_icons(sys.argv[1], sys.argv[2]))
f.close()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

-470
View File
@@ -1,470 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
import random
import codecs
import re
import sys
def theme_names():
"""
Gets a list of all of the theme names we know about.
"""
names = list(theme_data.THEME.keys())
names.sort(key=lambda a : a.lower())
return names
def scheme_names(theme):
"""
Gets a list of the color scheme names corresponding to the given
theme.
"""
names = list(theme_data.THEME[theme].keys())
names.sort(key=lambda a : a.lower())
return names
def theme_yinitial():
names = theme_names()
if len(names) < 2:
return 0
return 1.0 * names.index(current_theme) / (len(names) - 1)
def scheme_yinitial():
names = scheme_names(current_theme)
if len(names) < 2:
return 0
return 1.0 * names.index(current_scheme) / (len(names) - 1)
def pick_theme(theme, scheme):
"""
Returns a theme and scheme that are similar to `theme` and `scheme`.
If the theme is known, picks it, otherwise picks a random theme. If
the scheme is known for that theme, picks it, otherwise picks a
random scheme that is known for the current theme.
"""
if theme not in theme_data.THEME:
theme = random.choice(list(theme_data.THEME))
schemes = theme_data.THEME[theme]
if scheme not in schemes:
if theme in schemes:
scheme = theme
else:
scheme = random.choice(list(schemes))
return theme, scheme
def implement_theme(theme, scheme):
global showing_theme, showing_scheme
if theme == showing_theme and scheme == showing_scheme:
return
renpy.style.restore(style_backup)
exec theme_data.THEME[theme][scheme] in globals()
renpy.style.rebuild()
showing_theme = theme
showing_scheme = scheme
renpy.restart_interaction()
showing_theme = None
showing_scheme = None
class SetTheme(Action):
def __init__(self, theme):
self.theme = theme
def __call__(self):
global current_theme
global current_scheme
current_theme, current_scheme = pick_theme(self.theme, current_scheme)
implement_theme(current_theme, current_scheme)
renpy.restart_interaction()
def get_selected(self):
return current_theme == self.theme
class SetScheme(Action):
def __init__(self, scheme):
self.scheme = scheme
def __call__(self):
global current_theme
global current_scheme
current_theme, current_scheme = pick_theme(current_theme, self.scheme)
implement_theme(current_theme, current_scheme)
renpy.restart_interaction()
def get_selected(self):
return current_scheme == self.scheme
class PreviewTheme(Action):
def __init__(self, theme, scheme):
self.theme = theme
self.scheme = scheme
def __call__(self):
theme, scheme = pick_theme(self.theme, self.scheme)
implement_theme(theme, scheme)
def unhovered(self):
if (showing_theme == self.theme and showing_scheme == self.scheme):
implement_theme(current_theme, current_scheme)
def value_changed(value):
return None
##########################################################################
# Code to update options.rpy
def list_logical_lines(filename):
"""
This reads in filename, and turns it into a list of logical
lines.
"""
f = codecs.open(filename, "rb", "utf-8")
data = f.read()
f.close()
# The result.
rv = [ ]
# The current position we're looking at in the buffer.
pos = 0
# Looping over the lines in the file.
while pos < len(data):
# The line that we're building up.
line = ""
# The number of open parenthesis there are right now.
parendepth = 0
# Looping over the characters in a single logical line.
while pos < len(data):
c = data[pos]
if c == '\n' and not parendepth:
rv.append(line)
pos += 1
# This helps out error checking.
line = ""
break
# Backslash/newline.
if c == "\\" and data[pos+1] == "\n":
pos += 2
line += "\\\n"
continue
# Parenthesis.
if c in ('(', '[', '{'):
parendepth += 1
if c in ('}', ']', ')') and parendepth:
parendepth -= 1
# Comments.
if c == '#':
while data[pos] != '\n':
line += data[pos]
pos += 1
continue
# Strings.
if c in ('"', "'", "`"):
delim = c
line += c
pos += 1
escape = False
while pos < len(data):
c = data[pos]
if escape:
escape = False
pos += 1
line += c
continue
if c == delim:
pos += 1
line += c
break
if c == '\\':
escape = True
line += c
pos += 1
continue
continue
line += c
pos += 1
if line:
rv.append(line)
return rv
def switch_theme():
"""
Switches the theme of the current project to the current theme
and color scheme. (As set in current_theme and current_scheme.)
"""
theme_code = theme_data.THEME[current_theme][current_scheme]
# Did we change the file at all?
changed = False
filename = os.path.join(project.current.path, "game/options.rpy")
with codecs.open(filename + ".new", "wb", "utf-8") as out:
for l in list_logical_lines(filename):
m = re.match(r' theme.(\w+)\(', l)
if (not changed) and m and (m.group(1) in theme_data.THEME_FUNCTIONS):
l = " " + theme_code
changed = True
out.write(l + "\n")
if changed:
try:
os.unlink(filename + ".bak")
except:
pass
os.rename(filename, filename + ".bak")
os.rename(filename + ".new", filename)
else:
os.unlink(filename + ".new")
interface.error(_("Could not change the theme. Perhaps options.rpy was changed too much."))
# Now give the theme's screen-ops function a chance to make any
# necessary changes to the screens.rpy file
filename = os.path.join(project.current.path, "game/screens.rpy")
changed = False
try:
with codecs.open(filename + ".new", "wb", "utf-8") as out:
lines = list_logical_lines(filename)
lines = theme_data.THEME_SCREEN_OPERATIONS[current_theme](lines)
if lines != None:
for l in lines:
out.write(l + "\n")
changed = True
if changed:
try:
os.unlink(filename + ".bak")
except:
pass
os.rename(filename, filename + ".bak")
os.rename(filename + ".new", filename)
except Exception as inst:
try:
# just in case
os.unlink(filename + ".new")
except:
pass
pass
def make_style_backup():
"""
Call this to back up the styles. This should be called in a
translate python block in each translation.
"""
global style_backup
style_backup = renpy.style.backup()
translate None python:
make_style_backup()
screen theme_demo:
window:
style "gm_root"
xpadding 5
ypadding 5
grid 1 1:
xfill True
style_group "prefs"
vbox:
frame:
style_group "pref"
has vbox
label _("Display")
textbutton _("Window") action SelectedIf(True)
textbutton _("Fullscreen") action ui.returns(None)
textbutton _("Planetarium") action None
frame:
style_group "pref"
has vbox
label _("Sound Volume")
bar style "slider" value .75 range 1.0 changed value_changed
textbutton "Test":
action ui.returns(None)
style "soundtest_button"
init -2 python:
style.pref_frame.xfill = True
style.pref_frame.xmargin = 5
style.pref_frame.top_margin = 5
style.pref_vbox.xfill = True
style.pref_button.size_group = "pref"
style.pref_button.xalign = 1.0
style.pref_slider.xmaximum = 192
style.pref_slider.xalign = 1.0
style.soundtest_button.xalign = 1.0
screen choose_theme:
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Choose Theme")
hbox:
yfill True
# Theme selector.
frame:
style "l_indent"
bottom_margin HALF_SPACER_HEIGHT
xmaximum 225
has vbox
label _("Theme") style "l_label_small"
viewport:
scrollbars "vertical"
yinitial theme_yinitial()
mousewheel True
has vbox
for i in theme_names():
textbutton "[i]":
action SetTheme(i)
hovered PreviewTheme(i, current_scheme)
style "l_list2"
# Color scheme selector.
frame:
style "l_indent"
bottom_margin HALF_SPACER_HEIGHT
xmaximum 225
has vbox
label _("Color Scheme") style "l_label_small"
viewport:
scrollbars "vertical"
mousewheel True
yinitial scheme_yinitial()
has vbox
for i in scheme_names(current_theme):
textbutton "[i]":
action SetScheme(i)
hovered PreviewTheme(current_theme, i)
style "l_list2"
# Preview
frame:
style "l_default"
background Frame(PATTERN, 0, 0, tile=True)
xpadding 5
ypadding 5
xfill True
yfill True
xmargin 20
bottom_margin 6
use theme_demo
textbutton _("Back") action Jump("front_page") style "l_left_button"
textbutton _("Continue") action Return(True) style "l_right_button"
label choose_theme_callable:
python:
current_theme, current_scheme = pick_theme(None, None)
implement_theme(current_theme, current_scheme)
call screen choose_theme
python hide:
with interface.error_handling("changing the theme"):
switch_theme()
return
label choose_theme:
call choose_theme_callable
jump front_page
-985
View File
@@ -1,985 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains code that manages the distribution of Ren'Py games
# and Ren'Py proper.
#
# In this module, all files and paths are stored in unicode. Full paths
# might include windows path separators (\), but archive paths and names we
# deal with/match against use the unix separator (/).
init python in distribute:
from store import config, persistent
import store.project as project
import store.interface as interface
import store.archiver as archiver
import store.updater as updater
import store as store
from change_icon import change_icons
import sys
import os
import json
import subprocess
import hashlib
import struct
import collections
import os
import io
import re
import plistlib
import time
match_cache = { }
def compile_match(pattern):
"""
Compiles a pattern for use with match.
"""
regexp = ""
while pattern:
if pattern.startswith("**"):
regexp += r'.*'
pattern = pattern[2:]
elif pattern[0] == "*":
regexp += r'[^/]*/?'
pattern = pattern[1:]
elif pattern[0] == '[':
regexp += r'['
pattern = pattern[1:]
while pattern and pattern[0] != ']':
regexp += pattern[0]
pattern = pattern[1:]
pattern = pattern[1:]
regexp += ']'
else:
regexp += re.escape(pattern[0])
pattern = pattern[1:]
regexp += "$"
return re.compile(regexp, re.I)
def match(s, pattern):
"""
Matches a glob-style pattern against s. Returns True if it matches,
and False otherwise.
** matches every character.
* matches every character but /.
[abc] matches a, b, or c.
Things are matched case-insensitively.
"""
regexp = match_cache.get(pattern, None)
if regexp is None:
regexp = compile_match(pattern)
match_cache[pattern] = regexp
if regexp.match(s):
return True
if regexp.match("/" + s):
return True
return False
class File(object):
"""
Represents a file that we can distribute.
self.name
The name of the file as it will be stored in the archives.
self.path
The path to the file on disk. None if it won't be stored
on disk.
self.directory
True if this is a directory.
self.executable
True if this is an executable that should be distributed
with the xbit set.
"""
def __init__(self, name, path, directory, executable):
self.name = name
self.path = path
self.directory = directory
self.executable = executable
def __repr__(self):
if self.directory:
extra = "dir"
elif self.executable:
extra = "x-bit"
else:
extra = ""
return "<File {!r} {!r} {}>".format(self.name, self.path, extra)
def copy(self):
return File(self.name, self.path, self.directory, self.executable)
class FileList(list):
"""
This represents a list of files that we know about.
"""
def sort(self):
list.sort(self, key=lambda a : a.name)
def copy(self):
"""
Makes a deep copy of this file list.
"""
rv = FileList()
for i in self:
rv.append(i.copy())
return rv
def filter_empty(self):
"""
Makes a deep copy of this file list with empty directories
omitted.
"""
rv = FileList()
needed_dirs = set()
for i in reversed(self):
if (not i.directory) or (i.name in needed_dirs):
rv.insert(0, i.copy())
directory, _sep, _filename = i.name.rpartition("/")
needed_dirs.add(directory)
return rv
@staticmethod
def merge(l):
"""
Merges a list of file lists into a single file list with no
duplicate entries.
"""
rv = FileList()
seen = set()
for fl in l:
for f in fl:
if f.name in seen:
continue
rv.append(f)
seen.add(f.name)
return rv
def prepend_directory(self, directory):
"""
Modifies this file list such that every file in it has `directory`
prepended.
"""
for i in self:
i.name = directory + "/" + i.name
self.insert(0, File(directory, None, True, False))
def mac_transform(self, app, documentation):
"""
Creates a new file list that has the mac transform applied to it.
The mac transform places all files that aren't already in <app> in
<app>/Contents/Resources/autorun. If it matches one of the documentation
patterns, then it appears both inside and outside of the app.
"""
rv = FileList()
for f in self:
# Already in the app.
if f.name == app or f.name.startswith(app + "/"):
rv.append(f)
continue
# If it's documentation, keep the file. (But also make
# a copy.)
for pattern in documentation:
if match(f.name, pattern):
rv.append(f)
if match("/" + f.name, pattern):
rv.append(f)
# Make a copy.
f = f.copy()
f.name = app + "/Contents/Resources/autorun/" + f.name
rv.append(f)
rv.append(File(app + "/Contents/Resources/autorun", None, True, False))
rv.sort()
return rv
class Distributor(object):
"""
This manages the process of building distributions.
"""
def __init__(self, project, destination=None, reporter=None, packages=None, build_update=True, open_directory=False, noarchive=False, packagedest=None, report_success=True):
"""
Distributes `project`.
`destination`
The destination in which the distribution will be placed. If None,
uses a default location.
`reporter`
An object that's used to report status and progress to the user.
`packages`
If not None, a list of packages to distributed. If None, all
packages are distributed.
`build_update`
Will updates be built?
`open_directory`
If true, the directory containing the built files will be opened
if the build succeeds.
`noarchive`
If true, files will not be placed into archives.
`packagedest`
If given, gives the full path to the single package (without any
extensions).
`report_success`
If true, we report that the build succeeded.
"""
if packagedest is not None:
if packages is None or len(packages) != 1:
raise Exception("Packagedest requires a single package be given.")
# Safety - prevents us from releasing a launcher that won't update.
if store.UPDATE_SIMULATE:
raise Exception("Cannot build distributions when UPDATE_SIMULATE is True.")
# The project we want to distribute.
self.project = project
# Logfile.
self.log = open(self.temp_filename("distribute.txt"), "w")
# Start by scanning the project, to get the data and build
# dictionaries.
data = project.data
project.update_dump(force=True, gui=False)
if project.dump.get("error", False):
raise Exception("Could not get build data from the project. Please ensure the project runs.")
self.build = build = project.dump['build']
# Map from file list name to file list.
self.file_lists = collections.defaultdict(FileList)
self.base_name = build['directory_name']
self.executable_name = build['executable_name']
self.pretty_version = build['version']
# The destination directory.
if destination is None:
destination = build["destination"]
parent = os.path.dirname(project.path)
self.destination = os.path.join(parent, destination)
else:
self.destination = destination
if not packagedest:
try:
os.makedirs(self.destination)
except:
pass
self.packagedest = packagedest
# Status reporter.
self.reporter = reporter
self.include_update = build['include_update']
self.build_update = self.include_update and build_update
# The various executables, which change names based on self.executable_name.
self.app = self.executable_name + ".app"
self.exe = self.executable_name + ".exe"
self.sh = self.executable_name + ".sh"
self.py = self.executable_name + ".py"
self.documentation_patterns = build['documentation_patterns']
build_packages = [ ]
for i in build['packages']:
name = i['name']
if packages is None:
if not i['hidden']:
build_packages.append(i)
elif name in packages:
build_packages.append(i)
if not build_packages:
self.reporter.info(_("No packages are selected, so there's nothing to do."), pause=True)
self.log.close()
return
# add the game.
self.reporter.info(_("Scanning project files..."))
self.scan_and_classify(project.path, build["base_patterns"])
if noarchive:
self.ignore_archives(build['archives'])
else:
self.archive_files(build["archives"])
# Add Ren'Py.
self.reporter.info(_("Scanning Ren'Py files..."))
self.scan_and_classify(config.renpy_base, build["renpy_patterns"])
# Add Python (with the same name as our executables)
self.add_python()
# Build the mac app.
self.add_mac_files()
# Add generated/special files.
if not build['renpy']:
self.add_renpy_files()
self.add_windows_files()
# Assign the x-bit as necessary.
self.mark_executable()
# Rename the executable-like files.
if not build['renpy']:
self.rename()
# The time of the update version.
self.update_version = int(time.time())
for p in build_packages:
for f in p["formats"]:
self.make_package(
p["name"],
f,
p["file_lists"],
dlc=p["dlc"])
if self.build_update and p["update"]:
self.make_package(
p["name"],
"update",
p["file_lists"],
dlc=False)
if self.build_update:
self.finish_updates(build_packages)
# Finish up.
self.log.close()
if report_success:
self.reporter.info(_("All packages have been built.\n\nDue to the presence of permission information, unpacking and repacking the Linux and Macintosh distributions on Windows is not supported."))
if open_directory:
store.OpenDirectory(self.destination)()
def scan_and_classify(self, directory, patterns):
"""
Walks through the `directory`, finds files and directories that
match the pattern, and assigns them to the appropriate file list.
`patterns`
A list of pattern, file_list tuples. The pattern is a string
that is matched using match. File_list is either
a space-separated list of file lists to add the file to,
or None to ignore it.
Directories are matched with a trailing /, but added to the
file list with the trailing / removed.
"""
def walk(name, path):
is_dir = os.path.isdir(path)
if is_dir:
match_name = name + "/"
else:
match_name = name
for pattern, file_list in patterns:
if match(match_name, pattern):
break
else:
print >> self.log, match_name.encode("utf-8"), "doesn't match anything."
pattern = None
file_list = None
print >> self.log, match_name.encode("utf-8"), "matches", pattern, "(" + str(file_list) + ")."
if file_list is None:
return
for fl in file_list:
f = File(name, path, is_dir, False)
self.file_lists[fl].append(f)
if is_dir:
for fn in os.listdir(path):
walk(
name + "/" + fn,
os.path.join(path, fn),
)
for fn in os.listdir(directory):
walk(fn, os.path.join(directory, fn))
def temp_filename(self, name):
self.project.make_tmp()
return os.path.join(self.project.tmp, name)
def add_file(self, file_list, name, path, executable=False):
"""
Adds a file to the file lists.
`file_list`
A space-separated list of file list names.
`name`
The name of the file to be added.
`path`
The path to that file on disk.
"""
if not os.path.exists(path):
raise Exception("{} does not exist.".format(path))
if isinstance(file_list, basestring):
file_list = file_list.split()
f = File(name, path, False, executable)
for fl in file_list:
self.file_lists[fl].append(f)
def ignore_archives(self, archives):
"""
Ignore archiving commands by adding the files that would be in
archives into packages instead.
"""
for arcname, file_lists in archives:
if not self.file_lists[arcname]:
continue
for f in self.file_lists[arcname]:
for fl in file_lists:
self.file_lists[fl].append(f)
def archive_files(self, archives):
"""
Add files to archives.
"""
for arcname, file_list in archives:
if not self.file_lists[arcname]:
continue
arcfn = arcname + ".rpa"
arcpath = self.temp_filename(arcfn)
af = archiver.Archive(arcpath)
fll = len(self.file_lists[arcname])
for i, entry in enumerate(self.file_lists[arcname]):
if entry.directory:
continue
self.reporter.progress(_("Archiving files..."), i, fll)
name = "/".join(entry.name.split("/")[1:])
af.add(name, entry.path)
self.reporter.progress_done()
af.close()
self.add_file(file_list, "game/" + arcfn, arcpath)
def add_renpy_files(self):
"""
Add Ren'Py-generic files to the project.
"""
SCRIPT_VERSION_RPY = os.path.join(config.gamedir, "script_version.rpy")
SCRIPT_VERSION_RPYC = os.path.join(config.gamedir, "script_version.rpy")
LICENSE_TXT = os.path.join(config.renpy_base, "LICENSE.txt")
if os.path.exists(SCRIPT_VERSION_RPY):
if not os.path.exists(os.path.join(self.project.path, "game", "script_version.rpy")):
self.add_file("all", "game/script_version.rpy", SCRIPT_VERSION_RPY)
if os.path.exists(SCRIPT_VERSION_RPYC):
if not os.path.exists(os.path.join(self.project.path, "game", "script_version.rpyc")):
self.add_file("all", "game/script_version.rpyc", SCRIPT_VERSION_RPYC)
if os.path.exists(LICENSE_TXT):
self.add_file("renpy", "renpy/LICENSE.txt", LICENSE_TXT)
def write_plist(self):
display_name = self.build['display_name']
executable_name = self.executable_name
version = self.build['version']
plist = dict(
CFBundleDevelopmentRegion="English",
CFBundleDisplayName=display_name,
CFBundleExecutable=executable_name,
CFBundleIconFile="icon",
CFBundleInfoDictionaryVersion="6.0",
CFBundleName=display_name,
CFBundlePackageType="APPL",
CFBundleShortVersionString=version,
CFBundleVersion="1.0.{0}".format(int(time.time())),
CFBundleDocumentTypes = [
{
"CFBundleTypeOSTypes" : [ "****", "fold", "disk" ],
"CFBundleTypeRole" : "Viewer",
},
],
UTExportedTypeDeclarations = [
{
"UTTypeConformsTo" : [ "public.python-script" ],
"UTTypeDescription" : "Ren'Py Script",
"UTTypeIdentifier" : "org.renpy.rpy",
"UTTypeTagSpecification" : { "public.filename-extension" : [ "rpy" ] }
},
],
)
rv = self.temp_filename("Info.plist")
plistlib.writePlist(plist, rv)
return rv
def add_python(self):
if self.build['renpy']:
windows = 'binary'
linux = 'binary'
mac = 'binary'
else:
windows = 'windows'
linux = 'linux'
mac = 'mac'
self.add_file(
linux,
"lib/linux-i686/" + self.executable_name,
os.path.join(config.renpy_base, "lib/linux-i686/pythonw"),
True)
self.add_file(
linux,
"lib/linux-x86_64/" + self.executable_name,
os.path.join(config.renpy_base, "lib/linux-x86_64/pythonw"),
True)
self.add_file(
mac,
"lib/darwin-x86_64/" + self.executable_name,
os.path.join(config.renpy_base, "lib/darwin-x86_64/pythonw"),
True)
self.add_file(
windows,
"lib/windows-i686/" + self.executable_name + ".exe",
os.path.join(config.renpy_base, "lib/windows-i686/pythonw.exe"))
def add_mac_files(self):
"""
Add mac-specific files to the distro.
"""
if self.build['renpy']:
filelist = "binary"
else:
filelist = "mac"
contents = self.app + "/Contents"
plist_fn = self.write_plist()
self.add_file(filelist, contents + "/Info.plist", plist_fn)
self.add_file(filelist, contents + "/MacOS/" + self.executable_name, os.path.join(config.renpy_base, "renpy.sh"))
custom_fn = os.path.join(self.project.path, "icon.icns")
default_fn = os.path.join(config.renpy_base, "launcher/icon.icns")
if os.path.exists(custom_fn):
icon_fn = custom_fn
else:
icon_fn = default_fn
self.add_file(filelist, contents + "/Resources/icon.icns", icon_fn)
def add_windows_files(self):
"""
Adds windows-specific files.
"""
icon_fn = os.path.join(self.project.path, "icon.ico")
old_exe_fn = os.path.join(config.renpy_base, "renpy.exe")
if os.path.exists(icon_fn):
exe_fn = self.temp_filename("renpy.exe")
with open(exe_fn, "wb") as f:
f.write(change_icons(old_exe_fn, icon_fn))
else:
exe_fn = old_exe_fn
self.add_file("windows", "renpy.exe", exe_fn)
def mark_executable(self):
"""
Marks files as executable.
"""
for l in self.file_lists.values():
for f in l:
for pat in self.build['xbit_patterns']:
if match(f.name, pat):
f.executable = True
if match("/" + f.name, pat):
f.executable = True
def rename(self):
"""
Rename files in all lists to match the executable names.
"""
def rename_one(fn):
parts = fn.split('/')
p = parts[0]
if p == "renpy.exe":
p = self.exe
elif p == "renpy.sh":
p = self.sh
elif p == "renpy.py":
p = self.py
parts[0] = p
return "/".join(parts)
for l in self.file_lists.values():
for f in l:
f.name = rename_one(f.name)
def make_package(self, variant, format, file_lists, dlc=False):
"""
Creates a package file in the projects directory.
`variant`
The name of the variant to package. This is appended to the base name to become
part of the file and directory names.
`format`
The format things will be packaged in. This should be one of "zip", "tar.bz2", or
"update".
`file_lists`
A string containing a space-separated list of file_lists to include in this
package.
`dlc`
True if we want to build a non-update file in DLC mode.
"""
filename = self.base_name + "-" + variant
path = os.path.join(self.destination, filename)
if self.packagedest:
path = self.packagedest
fl = FileList.merge([ self.file_lists[i] for i in file_lists ])
fl = fl.copy()
fl.sort()
if self.build.get("exclude_empty_directories", True):
fl = fl.filter_empty()
# Write the update information.
update_files = [ ]
update_xbit = [ ]
update_directories = [ ]
for i in fl:
if not i.directory:
update_files.append(i.name)
else:
update_directories.append(i.name)
if i.executable:
update_xbit.append(i.name)
update = { variant : { "version" : self.update_version, "pretty_version" : self.pretty_version, "files" : update_files, "directories" : update_directories, "xbit" : update_xbit } }
if self.include_update and not dlc:
update_fn = os.path.join(self.destination, filename + ".update.json")
with open(update_fn, "wb") as f:
json.dump(update, f)
fl.append(File("update", None, True, False))
fl.append(File("update/current.json", update_fn, False, False))
# The mac transform.
if format == "app-zip":
fl = fl.mac_transform(self.app, self.documentation_patterns)
# If we're not an update file, prepend the directory.
if (not dlc) and format != "update" and format != "directory":
fl.prepend_directory(filename)
if format == "tar.bz2":
path += ".tar.bz2"
pkg = TarPackage(path, "w:bz2")
elif format == "update":
path += ".update"
pkg = TarPackage(path, "w", notime=True)
elif format == "zip" or format == "app-zip":
path += ".zip"
pkg = ZipPackage(path)
elif format == "directory":
pkg = DirectoryPackage(path)
for i, f in enumerate(fl):
self.reporter.progress(_("Writing the [variant] [format] package."), i, len(fl), variant=variant, format=format)
if f.directory:
pkg.add_directory(f.name, f.path)
else:
pkg.add_file(f.name, f.path, f.executable)
self.reporter.progress_done()
pkg.close()
if format == "update":
# Build the zsync file.
self.reporter.info(_("Making the [variant] update zsync file."), variant=variant)
cmd = [
updater.zsync_path("zsyncmake"),
"-z",
# -u url to gzipped data - not a local filename!
"-u", filename + ".update.gz",
"-o", os.path.join(self.destination, filename + ".zsync"),
os.path.abspath(path),
]
subprocess.check_call([ renpy.fsencode(i) for i in cmd ])
# Build the sums file. This is a file with an adler32 hash of each 64k block
# of the zsync file. It's used to help us determine how much of the file is
# downloaded.
with open(path, "rb") as src:
with open(renpy.fsencode(os.path.join(self.destination, filename + ".sums")), "wb") as sums:
while True:
data = src.read(65536)
if not data:
break
sums.write(struct.pack("I", zlib.adler32(data) & 0xffffffff))
if self.include_update and not self.build_update and not dlc:
os.unlink(update_fn)
def finish_updates(self, packages):
"""
Indexes the updates, then removes the .update files.
"""
if not self.build_update:
return
index = { }
def add_variant(variant):
fn = renpy.fsencode(os.path.join(self.destination, self.base_name + "-" + variant + ".update"))
with open(fn, "rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
index[variant] = {
"version" : self.update_version,
"pretty_version" : self.pretty_version,
"digest" : digest,
"zsync_url" : self.base_name + "-" + variant + ".zsync",
"sums_url" : self.base_name + "-" + variant + ".sums",
"json_url" : self.base_name + "-" + variant + ".update.json",
}
os.unlink(fn)
for p in packages:
if p["update"]:
add_variant(p["name"])
fn = renpy.fsencode(os.path.join(self.destination, "updates.json"))
with open(fn, "wb") as f:
json.dump(index, f)
def dump(self):
for k, v in sorted(self.file_lists.items()):
print
print k + ":"
v.sort()
for i in v:
print " ", i.name, "xbit" if i.executable else ""
class GuiReporter(object):
"""
Displays progress using the gui.
"""
def __init__(self):
# The time at which we should next report progress.
self.next_progress = 0
def info(self, what, pause=False, **kwargs):
if pause:
interface.info(what, **kwargs)
else:
interface.processing(what, **kwargs)
def progress(self, what, complete, total, **kwargs):
if (complete > 0) and (time.time() < self.next_progress):
return
interface.processing(what, _("Processed {b}[complete]{/b} of {b}[total]{/b} files."), complete=complete, total=total, **kwargs)
self.next_progress = time.time() + .05
def progress_done(self):
return
class TextReporter(object):
"""
Displays progress on the command line.
"""
def info(self, what, pause=False, **kwargs):
what = what.replace("[", "{")
what = what.replace("]", "}")
what = what.format(**kwargs)
print what
def progress(self, what, done, total, **kwargs):
what = what.replace("[", "{")
what = what.replace("]", "}")
what = what.format(**kwargs)
sys.stdout.write("\r{} - {} of {}".format(what, done + 1, total))
sys.stdout.flush()
def progress_done(self):
sys.stdout.write("\n")
def distribute_command():
ap = renpy.arguments.ArgumentParser()
ap.add_argument("--destination", "--dest", default=None, action="store", help="The directory where the packaged files should be placed.")
ap.add_argument("--packagedest", default=None, action="store", help="If given, gives the full path to the package file, without extensions." )
ap.add_argument("--no-update", default=True, action="store_false", dest="build_update", help="Prevents updates from being built.")
ap.add_argument("--package", action="append", help="If given, a package to build. Defaults to building all packages.")
ap.add_argument("--no-archive", action="store_true", help="If given, files will not be added to archives.")
ap.add_argument("project", help="The path to the project directory.")
args = ap.parse_args()
p = project.Project(args.project)
if args.package:
packages = args.package
else:
packages = None
Distributor(p, destination=args.destination, reporter=TextReporter(), packages=packages, build_update=args.build_update, noarchive=args.no_archive, packagedest=args.packagedest)
return False
renpy.arguments.register_command("distribute", distribute_command)
label distribute:
python hide:
data = project.current.data
d = distribute.Distributor(project.current,
reporter=distribute.GuiReporter(),
packages=data['packages'],
build_update=data['build_update'],
open_directory=True,
)
jump front_page
-242
View File
@@ -1,242 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
class PackageToggle(Action):
def __init__(self, name):
self.name = name
def get_selected(self):
return self.name in project.current.data['packages']
def __call__(self):
packages = project.current.data['packages']
if self.name in packages:
packages.remove(self.name)
else:
packages.append(self.name)
project.current.save_data()
renpy.restart_interaction()
class DataToggle(Action):
def __init__(self, field):
self.field = field
def get_selected(self):
return project.current.data[self.field]
def __call__(self):
project.current.data[self.field] = not project.current.data[self.field]
project.current.save_data()
renpy.restart_interaction()
DEFAULT_BUILD_INFO = """
## This section contains information about how to build your project into
## distribution files.
init python:
## The name that's used for directories and archive files. For example, if
## this is 'mygame-1.0', the windows distribution will be in the
## directory 'mygame-1.0-win', in the 'mygame-1.0-win.zip' file.
build.directory_name = "PROJECTNAME-1.0"
## The name that's uses for executables - the program that users will run
## to start the game. For example, if this is 'mygame', then on Windows,
## users can click 'mygame.exe' to start the game.
build.executable_name = "PROJECTNAME"
## If True, Ren'Py will include update information into packages. This
## allows the updater to run.
build.include_update = False
## File patterns:
##
## The following functions take file patterns. File patterns are case-
## insensitive, and matched against the path relative to the base
## directory, with and without a leading /. If multiple patterns match,
## the first is used.
##
##
## In a pattern:
##
## /
## Is the directory separator.
## *
## Matches all characters, except the directory separator.
## **
## Matches all characters, including the directory separator.
##
## For example:
##
## *.txt
## Matches txt files in the base directory.
## game/**.ogg
## Matches ogg files in the game directory or any of its subdirectories.
## **.psd
## Matches psd files anywhere in the project.
## Classify files as None to exclude them from the built distributions.
build.classify('**~', None)
build.classify('**.bak', None)
build.classify('**/.**', None)
build.classify('**/#**', None)
build.classify('**/thumbs.db', None)
## To archive files, classify them as 'archive'.
# build.classify('game/**.png', 'archive')
# build.classify('game/**.jpg', 'archive')
## Files matching documentation patterns are duplicated in a mac app
## build, so they appear in both the app and the zip file.
build.documentation('*.html')
build.documentation('*.txt')
"""
# A screen that displays a file or directory name, and
# lets the user change it,
#
# title
# The title of the link.
# value
# The value of the field.
screen distribute_name:
add SEPARATOR2
frame:
style "l_indent"
has vbox
text title
add HALF_SPACER
frame:
style "l_indent"
text "[value!q]"
add SPACER
screen build_distributions:
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Build Distributions: [project.current.name!q]")
add HALF_SPACER
hbox:
# Left side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
use distribute_name(
title=_("Directory Name:"),
value=project.current.dump["build"]["directory_name"])
use distribute_name(
title=_("Executable Name:"),
value=project.current.dump["build"]["executable_name"])
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Actions:")
add HALF_SPACER
frame style "l_indent":
has vbox
textbutton _("Edit options.rpy") action editor.Edit("game/options.rpy", check=True)
textbutton _("Refresh") action Jump("build_distributions")
# Right side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Build Packages:")
add HALF_SPACER
$ packages = project.current.dump["build"]["packages"]
for pkg in packages:
if not pkg["hidden"]:
$ description = pkg["description"]
textbutton "[description!q]" action PackageToggle(pkg["name"]) style "l_checkbox"
add SPACER
if project.current.dump["build"]["include_update"]:
textbutton _("Build Updates") action DataToggle("build_update") style "l_checkbox"
textbutton _("Back") action Jump("front_page") style "l_left_button"
textbutton _("Build") action Jump("distribute") style "l_right_button"
label build_update_dump:
python:
project.current.update_dump(True)
if project.current.dump.get("error", False):
interface.error(_("Errors were detected when running the project. Please ensure the project runs without errors before building distributions."))
return
label build_distributions:
call build_update_dump
if not project.current.dump["build"]["directory_name"]:
jump build_missing
call screen build_distributions
label build_missing:
python hide:
interface.yesno(_("Your project does not contain build information. Would you like to add build information to the end of options.rpy?"), yes=Return(True), no=Jump("front_page"))
build_info = DEFAULT_BUILD_INFO.replace("PROJECTNAME", project.current.name)
with open(os.path.join(project.current.path, "game", "options.rpy"), "a") as f:
f.write(build_info)
jump build_distributions
-129
View File
@@ -1,129 +0,0 @@
init python:
import urllib2
import os
import threading
import time
class Downloader(object):
def __init__(self, url, dest):
"""
Downloads `url` to `dest`, providing progress reports
as necessary.
"""
self.url = url
# The destination file, and the destination temp file.
self.dest = dest
self.tmp = dest + ".tmp"
# Open the tmpfile.
self.safe_unlink(self.tmp)
self.tmpfile = open(self.tmp, "wb")
# Set by the thread to indicate progress (ranges from 0.0 to 1.0).
self.progress = 0.0
# This is set to true by cancel() to indicate the download should be cancelled.
self.cancelled = False
# Set on succes or failure.
self.success = False
self.failure = None
try:
# Open the URL.
self.urlfile = urllib2.urlopen(url)
t = threading.Thread(target=self.thread)
t.daemon = True
t.start()
except Exception as e:
self.failure = str(e)
def thread(self):
try:
count = 0
if "content-length" in self.urlfile.headers:
length = int(self.urlfile.headers["content-length"])
else:
length = 0
while not self.cancelled:
data = self.urlfile.read(65536)
if not data:
break
count += len(data)
self.tmpfile.write(data)
if length > 0:
self.progress = 1.0 * count / length
self.tmpfile.close()
if self.cancelled:
return
if length and count != length:
self.failure = "Download length does not match content length."
return
self.safe_unlink(self.dest)
os.rename(self.tmp, self.dest)
self.success = True
except Exception as e:
self.failure = str(e)
def safe_unlink(self, fn):
if os.path.exists(fn):
os.unlink(fn)
def cancel(self):
"""
Cancels the download.
"""
self.cancelled = True
def check(self):
"""
Returns True if the download is finished, False if it was cancelled,
None if it's ongoing, and raises an Exception if the download has failed.
"""
if self.success:
return True
if self.cancelled:
return False
if self.failure:
raise Exception("Downloading {} to {} failed: {}".format(self.url, self.dest, self.failure))
return None
class DownloaderValue(BarValue):
"""
A BarValue that reports the progress of a background download.
"""
def __init__(self, d):
self.downloader = d
def get_adjustment(self):
self.adjustment = ui.adjustment(value=0.0, range=1.0, adjustable=False)
return self.adjustment
def periodic(self, st):
self.adjustment.change(self.downloader.progress)
return .25
-464
View File
@@ -1,464 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Editor Support.
#
# This contains code for scanning for editors, and for allowing the user to
# select an editor.
init python in editor:
from store import Action, renpy, config, persistent
import store.project as project
import store.updater as updater
import store.interface as interface
import store
import glob
import re
import traceback
import os
import os.path
# Should we set up the editor?
set_editor = "RENPY_EDIT_PY" not in os.environ
# A map from editor name to EditorInfo object.
editors = { }
class EditorInfo(object):
def __init__(self, filename):
# The path to the editor info file.
self.filename = filename
# The name of the editor.
self.name = os.path.basename(filename)[:-len(".edit.py")]
# The time the editor file was last modified. We use this
# to decide if we should update the editors mat when we
# have multiple versions of an editor in contention.
self.mtime = os.path.getmtime(filename)
def scan_editor(filename):
"""
Inserts an editor into editors if there isn't a newer
editor there already.
"""
ei = EditorInfo(filename)
if ei.name in editors:
if editors[ei.name].mtime >= ei.mtime:
return
editors[ei.name] = ei
def scan_all():
"""
Finds all *.edit.py files, and uses them to populate the list
of editors.
"""
editors.clear()
for d in [ config.renpy_base, persistent.projects_directory ]:
if d is None:
continue
for filename in glob.glob(d + "/*/*.edit.py"):
scan_editor(filename)
########################################################################
# A list of fancy_editor_info objects.
fancy_editors = [ ]
# The error message to display if an editor failed to start.
error_message = None
class FancyEditorInfo(object):
"""
Represents an editor in the selection screen. A FEI knows if the
editor is installed or not.
"""
def __init__(self, priority, name, description=None, dlc=None, dldescription=None, error_message=None):
# The priority of the editor. Lower priorities will come later
# in the list.
self.priority = priority
# The name of the editor.
self.name = name
# Is the editor installed?
self.installed = name in editors
# The dlc needed to install the editor.
self.dlc = dlc
# A description of the editor.
self.description = description
# A description of the download.
self.dldescription = dldescription
# An error message to display if the editor failed to start.
self.error_message = error_message
def fancy_scan_editors():
"""
Creates the list of FancyEditorInfo objects.
"""
global fancy_editors
scan_all()
fei = fancy_editors = [ ]
# Editra.
ED = _("{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input.")
EDL = _("{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython.")
if renpy.windows:
dlc = "editra-windows"
installed = os.path.exists(os.path.join(config.basedir, "editra/Editra-win32"))
description = ED
error_message = None
elif renpy.macintosh:
dlc = "editra-mac"
installed = os.path.exists(os.path.join(config.basedir, "editra/Editra-mac.app"))
description = ED
error_message = None
else:
dlc = "editra-linux"
installed = os.path.exists(os.path.join(config.basedir, "editra/Editra"))
description = EDL
error_message = _("This may have occured because wxPython is not installed on this system.")
e = FancyEditorInfo(
1,
"Editra",
description,
dlc,
_("Up to 22 MB download required."),
error_message)
e.installed = e.installed or installed
fei.append(e)
# jEdit
fei.append(FancyEditorInfo(
2,
"jEdit",
_("A mature editor that requires Java."),
"jedit",
_("1.8 MB download required."),
_("This may have occured because Java is not installed on this system."),
))
fei.append(FancyEditorInfo(
3,
"System Editor",
_("Invokes the editor your operating system has associated with .rpy files."),
None))
for k in editors:
if k in [ "Editra", "jEdit", "System Editor", "None" ]:
continue
fei.append(FancyEditorInfo(
4,
k,
None,
None))
fei.append(FancyEditorInfo(
5,
"None",
_("Prevents Ren'Py from opening a text editor."),
None))
fei.sort(key=lambda e : (e.priority, e.name.lower()))
# If we're in a linux distro or something, assume all editors work.
if not updater.can_update():
for i in fei:
i.installed = True
def fancy_activate_editor(default=False):
"""
Activates the editor in persistent.editor, if it's installed.
`default`
"""
global error_message
fancy_scan_editors()
if default and not set_editor:
renpy.editor.init()
return
for i in fancy_editors:
if i.name == persistent.editor:
if i.installed and i.name in editors:
ei = editors[i.name]
os.environ["RENPY_EDIT_PY"] = renpy.fsencode(os.path.abspath(ei.filename))
error_message = i.error_message
break
else:
persistent.editor = None
os.environ.pop("RENPY_EDIT_PY", None)
renpy.editor.init()
def fancy_select_editor(name):
"""
Selects the editor with the given name, installing it if it
doesn't already exist.
"""
for fe in fancy_editors:
if fe.name == name:
break
else:
return
if not fe.installed:
# We don't check the status of this because fancy_activate_editor
# will fail if the editor is not installed.
store.add_dlc(fe.dlc)
persistent.editor = fe.name
fancy_activate_editor()
return persistent.editor is not None
# Call fancy_activate_editor on startup.
fancy_activate_editor(True)
class SelectEditor(Action):
def __init__(self, name):
self.name = name
def get_selected(self):
return persistent.editor == self.name
def __call__(self):
return fancy_select_editor(self.name)
def check_editor():
"""
Checks to see if an editor is set. If one isn't asks the user to
select one.
Returns True if the editor is set and editing can proceed, and
False otherwise.
"""
if not set_editor:
return True
if persistent.editor:
return True
return renpy.invoke_in_new_context(renpy.call_screen, "editor")
##########################################################################
# Editing actions.
class Edit(Action):
def __init__(self, filename, line=None, check=False):
"""
An action that opens the given line of the given file in a
text editor.
`filename`
The filename to open.
`line`
The line in the file to jump to.
`check`
If true, we will check to see if the file exists, and gray
out the box if it does not.
"""
self.filename = filename
self.line = line
self.check = check
def get_sensitive(self):
if not self.check:
return True
fn = project.current.unelide_filename(self.filename)
return os.path.exists(fn)
def __call__(self):
if not self.get_sensitive():
return
if not check_editor():
return
fn = project.current.unelide_filename(self.filename)
try:
e = renpy.editor.editor
e.begin()
e.open(fn, line=self.line)
e.end()
except Exception, e:
exception = traceback.format_exception_only(type(e), e)[-1][:-1]
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
class EditAbsolute(Action):
def __init__(self, filename, line=None, check=False):
"""
An action that lets us edit an absolutely-specified filename.
`filename`
The filename to open.
`line`
The line in the file to jump to.
`check`
If true, we will check to see if the file exists, and gray
out the box if it does not.
"""
self.filename = filename
self.line = line
self.check = check
def get_sensitive(self):
if not self.check:
return True
return os.path.exists(self.filename)
def __call__(self):
if not self.get_sensitive():
return
if not check_editor():
return
try:
e = renpy.editor.editor
e.begin()
e.open(self.filename, line=self.line)
e.end()
except Exception, e:
exception = traceback.format_exception_only(type(e), e)[-1][:-1]
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
class EditAll(Action):
"""
Opens all scripts that are part of the current project in a web browser.
"""
def __init__(self):
return
def __call__(self):
if not check_editor():
return
scripts = project.current.script_files()
scripts = [ i for i in scripts if not i.startswith("game/tl/") ]
scripts.sort(key=lambda fn : fn.lower())
for fn in [ "game/screens.rpy", "game/options.rpy", "game/script.rpy" ]:
if fn in scripts:
scripts.remove(fn)
scripts.insert(0, fn)
try:
e = renpy.editor.editor
e.begin()
for fn in scripts:
fn = project.current.unelide_filename(fn)
e.open(fn)
e.end()
except Exception, e:
exception = traceback.format_exception_only(type(e), e)[-1][:-1]
renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
screen editor:
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Select Editor")
add HALF_SPACER
hbox:
frame:
style "l_indent"
xfill True
viewport:
scrollbars "vertical"
mousewheel True
has vbox
text _("A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed.") style "l_small_text"
for fe in editor.fancy_editors:
add SPACER
textbutton fe.name action editor.SelectEditor(fe.name)
add HALF_SPACER
frame:
style "l_indent"
has vbox
if fe.description:
text fe.description style "l_small_text"
if not fe.installed:
add HALF_SPACER
text fe.dldescription style "l_small_text"
textbutton _("Cancel") action Return(False) style "l_left_button"
label editor_preference:
call screen editor
jump preferences
-252
View File
@@ -1,252 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
define PROJECT_ADJUSTMENT = ui.adjustment()
init python:
import os
import subprocess
class OpenDirectory(Action):
"""
Opens `directory` in a file browser. `directory` is relative to
the project root.
"""
def __init__(self, directory, absolute=False):
if absolute:
self.directory = directory
else:
self.directory = os.path.join(project.current.path, directory)
def get_sensitive(self):
return os.path.exists(self.directory)
def __call__(self):
directory = renpy.fsencode(self.directory)
if renpy.windows:
os.startfile(directory)
elif renpy.macintosh:
subprocess.Popen([ "open", directory ])
else:
subprocess.Popen([ "xdg-open", directory ])
# Used for testing.
def Relaunch():
renpy.quit(relaunch=True)
screen front_page:
frame:
style_group "l"
style "l_root"
has hbox
# Projects list section - on left.
frame:
style "l_projects"
xmaximum 300
right_margin 2
top_padding 20
bottom_padding 26
side "t c b":
window style "l_label":
has hbox:
xfill True
text "PROJECTS:" style "l_label_text" size 36 yoffset 10
textbutton _("refresh"):
xalign 1.0
yalign 1.0
yoffset 5
style "l_small_button"
action project.Rescan()
right_margin HALF_INDENT
side "c r":
viewport:
yadjustment PROJECT_ADJUSTMENT
mousewheel True
use front_page_project_list
vbar:
style "l_vscrollbar"
adjustment PROJECT_ADJUSTMENT
vbox:
add HALF_SPACER
add SEPARATOR
add HALF_SPACER
hbox:
xfill True
textbutton _("+ Create New Project"):
left_margin (HALF_INDENT)
action Jump("new_project")
# Project section - on right.
if project.current is not None:
use front_page_project
if project.current is not None:
textbutton _("Launch Project") action project.Launch() style "l_right_button"
# This is used by front_page to display the list of known projects on the screen.
screen front_page_project_list:
$ projects = project.manager.projects
$ templates = project.manager.templates
vbox:
if templates and persistent.show_templates:
for p in templates:
textbutton _("[p.name!q] (template)"):
action project.Select(p)
style "l_list"
null height 12
if projects:
for p in projects:
textbutton "[p.name!q]":
action project.Select(p)
style "l_list"
null height 12
textbutton _("Tutorial") action project.Select("tutorial") style "l_list"
textbutton _("The Question") action project.Select("the_question") style "l_list"
# This is used for the right side of the screen, which is where the project-specific
# buttons are.
screen front_page_project:
$ p = project.current
window:
has vbox
frame style "l_label":
has hbox xfill True
text "[p.name!q]" style "l_label_text"
label _("Active Project") style "l_alternate"
grid 2 1:
xfill True
spacing HALF_INDENT
vbox:
label _("Open Directory") style "l_label_small"
frame style "l_indent":
has vbox
textbutton _("game") action OpenDirectory("game")
textbutton _("base") action OpenDirectory(".")
# textbutton _("images") action OpenDirectory("game/images") style "l_list"
# textbutton _("save") action None style "l_list"
vbox:
label _("Edit File") style "l_label_small"
frame style "l_indent":
has vbox
textbutton "script.rpy" action editor.Edit("game/script.rpy", check=True)
textbutton "options.rpy" action editor.Edit("game/options.rpy", check=True)
textbutton "screens.rpy" action editor.Edit("game/screens.rpy", check=True)
textbutton _("All script files") action editor.EditAll()
add SPACER
add SEPARATOR
add SPACER
frame style "l_indent":
has vbox
textbutton _("Navigate Script") text_size 30 action Jump("navigation")
add SPACER
grid 2 1:
xfill True
spacing HALF_INDENT
frame style "l_indent":
has vbox
textbutton _("Check Script (Lint)") action Jump("lint")
textbutton _("Change Theme") action Jump("choose_theme")
textbutton _("Delete Persistent") action Jump("rmpersistent")
# textbutton "Relaunch" action Relaunch
frame style "l_indent":
has vbox
if ability.can_distribute:
textbutton _("Build Distributions") action Jump("build_distributions")
textbutton _("Android") action Jump("android")
textbutton _("Generate Translations") action Jump("translate")
textbutton _("Extract Dialogue") action Jump("extract_dialogue")
label main_menu:
return
label start:
show screen bottom_info
label front_page:
call screen front_page
jump front_page
label lint:
python hide:
interface.processing(_("Checking script for potential problems..."))
lint_fn = project.current.temp_filename("lint.txt")
project.current.launch([ 'lint', lint_fn ], wait=True)
e = renpy.editor.editor
e.begin(True)
e.open(lint_fn)
e.end()
jump front_page
label rmpersistent:
python hide:
interface.processing(_("Deleting persistent data..."))
project.current.launch([ 'rmpersistent' ], wait=True)
jump front_page
-459
View File
@@ -1,459 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
################################################################################
# Interface actions.
init python in interface:
from store import OpenURL, config, Return
import store
import os.path
import contextlib
RENPY_URL = "http://www.renpy.org"
RENPY_GAMES_URL = "http://games.renpy.org"
DOC_PATH = os.path.join(config.renpy_base, "doc/index.html")
DOC_URL = "http://www.renpy.org/doc/html/"
LICENSE_PATH = os.path.join(config.renpy_base, "doc/license.html")
LICENSE_URL = "http://www.renpy.org/doc/html/license.html"
if os.path.exists(DOC_PATH):
DOC_LOCAL_URL = "file:///" + DOC_PATH
else:
DOC_LOCAL_URL = None
if os.path.exists(LICENSE_PATH):
LICENSE_LOCAL_URL = "file:///" + LICENSE_PATH
else:
LICENSE_LOCAL_URL = None
def OpenDocumentation():
"""
An action that opens the documentation.
"""
if DOC_LOCAL_URL is not None:
return OpenURL(DOC_LOCAL_URL)
else:
return OpenURL(DOC_URL)
def OpenLicense():
"""
An action that opens the license.
"""
if LICENSE_LOCAL_URL is not None:
return OpenURL(LICENSE_LOCAL_URL)
else:
return OpenURL(LICENSE_URL)
# Should we display the bottom links?
links = True
@contextlib.contextmanager
def nolinks():
global links
links = False
try:
yield
finally:
links = True
# This displays the bottom of the screen. If the tooltip is not None, this displays the
# tooltip. Otherwise, it displays a list of links (to various websites, and to the
# preferences and update screen), or is just blank.
screen bottom_info:
zorder 100
if interface.links:
frame:
style_group "l"
style "l_default"
left_margin (10 + INDENT)
right_margin (10 + INDENT)
xfill True
ypos 536
yanchor 0.0
hbox:
xfill True
hbox:
spacing INDENT
textbutton _("Documentation") style "l_link" action interface.OpenDocumentation()
textbutton _("Ren'Py Website") style "l_link" action OpenURL(interface.RENPY_URL)
textbutton _("Ren'Py Games List") style "l_link" action OpenURL(interface.RENPY_GAMES_URL)
textbutton _("About") style "l_link" action Jump("about")
hbox:
spacing INDENT
xalign 1.0
if ability.can_update:
textbutton _("update") action Jump("update") style "l_link"
textbutton _("preferences") style "l_link" action Jump("preferences")
textbutton _("quit") style "l_link" action Quit(confirm=False)
screen common:
default complete = None
default total = None
default yes = None
default no = None
default choices = None
default cancel = None
default bar_value = None
frame:
style "l_root"
frame:
style_group "l_info"
has vbox
text message:
text_align 0.5
xalign 0.5
layout "subtitle"
if complete is not None:
add SPACER
frame:
style "l_progress_frame"
bar:
range total
value complete
style "l_progress_bar"
if bar_value is not None:
add SPACER
frame:
style "l_progress_frame"
bar:
value bar_value
style "l_progress_bar"
if choices:
add SPACER
for v, l in choices:
textbutton l action SetScreenVariable("selected", v)
if selected is not None:
$ continue_ = Return(selected)
else:
$ continue_ = None
if submessage:
add SPACER
text submessage:
text_align 0.5
xalign 0.5
layout "subtitle"
if yes:
add SPACER
hbox:
xalign 0.5
textbutton _("Yes") style "l_button" action yes
null width 160
textbutton _("No") style "l_button" action no
label title text_color title_color style "l_info_label"
if back:
textbutton _("Back") action back style "l_left_button"
elif cancel:
textbutton _("Cancel") action cancel style "l_left_button"
if continue_:
textbutton _("Continue") action continue_ style "l_right_button"
screen launcher_input:
frame:
style "l_root"
frame:
style_group "l_info"
has vbox
text message:
text_align 0.5
xalign 0.5
layout "subtitle"
add SPACER
input style "l_default" size 24 xalign 0.5 default default color INPUT_COLOR
if filename:
add SPACER
text _("Due to package format limitations, non-ASCII file and directory names are not allowed.")
label title style "l_info_label" text_color QUESTION_COLOR
if cancel:
textbutton _("Cancel") action cancel style "l_left_button"
init python in interface:
import traceback
from store import Jump
def common(title, title_color, message, submessage=None, back=None, continue_=None, pause0=False, show_screen=False, **kwargs):
"""
Displays the info, interaction, and processing screens.
`title`
The title of the screen.
`message`
The main message that is displayed when the screen is.
`submessage`
If not None, a message that is displayed below the main message.
`back`
If not None, a back button will be present. `back` is the action that
is called when the button is clicked.
`cancel`
If not None, a cancel button will be present. `cancel` is the action
that is called when the button is clicked.
`continue_`
If True, a continue button will be present. `continue_` gives the action
that is called when that button is clicked.
`pause0`
If True, a zero-length pause will be inserted before calling the
screen. This will display it to the user and then immediately
return.
`show_screen`
If True, the screen will be show, and will return immediately. if False,
the screen will be called, and interaction will pause.
Other keyword arguments are passed to the screen itself.
"""
if show_screen:
screen_func = renpy.show_screen
else:
screen_func = renpy.call_screen
if pause0:
ui.pausebehavior(0)
return screen_func("common", title=title, title_color=title_color, message=message, submessage=submessage, back=back, continue_=continue_, **kwargs)
def hide_screen():
"""
Hides a screen that was shown with show_screen=True.
"""
renpy.hide_screen("common")
def error(message, submessage=None, label="front_page", **kwargs):
"""
Indicates to the user that an error has occured.
`message`
The message to display.
`submessage`
Optional secondary message information. For example, this may be
used to display an exception string.
`label`
The label to redirect to when the user finishes displaying the error. None
to just return False.
Keyword arguments are passed into the screen so that they can be substituted into
the message.
"""
if label is None:
action = Return(False)
else:
action = Jump(label)
common(_("ERROR"), store.ERROR_COLOR, message=message, submessage=submessage, back=action, **kwargs)
@contextlib.contextmanager
def error_handling(what, label="front_page"):
"""
This is a context manager that catches exceptions and displays them using
interface.error.
`what`
What we're doing when the error occurs. This is usually written using
the present participle.
`label`
The label to jump to when error handling finishes.
As an example of usage::
with interface.error_handling("opening the log file"):
f = open("log.txt", "w")
"""
try:
yield
except Exception, e:
import traceback
traceback.print_exc()
error(_("While [what!q], an error occured:"),
_("[exception!q]"),
what=what,
label=label,
exception=traceback.format_exception_only(type(e), e)[-1][:-1])
def input(title, message, filename=False, sanitize=True, cancel=None, default=""):
"""
Requests typewritten input from the user.
"""
rv = default
while True:
rv = renpy.call_screen("launcher_input", title=title, message=message, filename=filename, cancel=cancel, default=rv)
if sanitize:
if ("[" in rv) or ("{" in rv):
error(_("Text input may not contain the {{ or [[ characters."), label=None)
continue
if filename:
if filename and (filename != "withslash") and (("\\" in rv) or ("/" in rv)):
error(_("File and directory names may not contain / or \\."), label=None)
continue
try:
rv.encode("ascii")
except:
error(_("File and directory names must consist of ASCII characters."), label=None)
continue
return rv
def info(message, submessage=None, pause=True, **kwargs):
"""
Displays an informational message to the user. The user will be asked to click to
confirm that he has read the message.
`message`
The message to display.
`pause`
True if we should pause while showing the info.
Keyword arguments are passed into the screen so that they can be substituted into
the message.
"""
if pause:
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, continue_=Return(True), **kwargs)
else:
common(_("INFORMATION"), store.INFO_COLOR, message, submessage, pause0=True, **kwargs)
def interaction(title, message, submessage=None, **kwargs):
"""
Put up on the screen while an interaction with an external program occurs.
This shows the message, then immediately returns.
`title`
The title of the interaction.
`message`
The message itself.
`submessage`
An optional sub message.
"""
common(title, store.INTERACTION_COLOR, message, submessage, pause0=True, **kwargs)
def processing(message, submessage=None, complete=None, total=None, **kwargs):
"""
Indicates to the user that processing is taking place. This should be used when
there is an indefinite amount of work to be done.
`message`
The message to display.
`submessage`
An additional message to display.
`complete`
The fraction complete the step is.
`total`
The total amount of work to do in this step.
Keyword arguments are passed into the screen so that they can be substituted into
the message.
"""
common(_("PROCESSING"), store.INTERACTION_COLOR, message, submessage, pause0=True, complete=complete, total=total, **kwargs)
def yesno(message, yes=Return(True), no=Return(False), **kwargs):
"""
Asks the user a yes or no question.
`message`
The question to ask.
`yes`
The action to perform if the user answers yes.
`no`
The action to perform if the user answer no.
"""
return common(_("QUESTION"), store.QUESTION_COLOR, message, yes=yes, no=no, **kwargs)
def choice(message, choices, selected, **kwargs):
"""
Asks the user to pick a choice from a menu.
`choices`
A list of (value, label) tuples, giving the choices.
`selected`
The default choice that we mark as selected.
"""
return common(_("CHOICE"), store.QUESTION_COLOR, message, choices=choices, selected=selected, **kwargs)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

-262
View File
@@ -1,262 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python in navigation:
import store.interface as interface
import store.project as project
import store.editor as editor
from store import persistent, Action
# The last navigation screen we've seen. This is the scree we try to go
# to the next time we enter navigation. (We may not be able to go there,
# if the screen is empty.)
if persistent.navigation is None:
persistent.navigation = "label"
# A map from a kind of information, to how we should sort it. Possible
# sorts are alphabetical, by-file, natural.
if persistent.navigation_sort is None:
persistent.navigation_sort = { }
if persistent.navigate_private is None:
persistent.navigate_private = False
if persistent.navigate_library is None:
persistent.navigate_library = False
# A list of kinds of navigation we support.
KINDS = [ "file", "label", "define", "transform", "screen", "callable", "todo" ]
# A map from kind name to adjustment.
adjustments = { }
for i in KINDS:
persistent.navigation_sort.setdefault(i, "by-file")
adjustments[i] = ui.adjustment()
def group_and_sort(kind):
"""
This is responsible for pulling navigation information of the
appropriate kind out of project.current.dump, grouping it,
and sorting it.
This returns a list of (group, list of (name, filename, line)). The
group may be a string or None.
"""
project.current.update_dump()
sort = persistent.navigation_sort[kind]
name_map = project.current.dump.get("location", {}).get(kind, { })
groups = { }
for name, loc in name_map.items():
filename, line = loc
filename = filename.replace("\\", "/")
if sort == "alphabetical":
group = None
else:
group = filename
if group.startswith("game/"):
group = group[5:]
g = groups.get(group, None)
if g is None:
groups[group] = g = [ ]
g.append((name, filename, line))
for g in groups.values():
if sort == "natural":
g.sort(key=lambda a : a[2])
else:
g.sort(key=lambda a : a[0].lower())
rv = list(groups.items())
rv.sort()
return rv
def group_and_sort_files():
rv = [ ]
for fn in project.current.script_files():
shortfn = fn
shortfn = shortfn.replace("\\", "/")
if shortfn.startswith("game/"):
shortfn = fn[5:]
rv.append((shortfn, fn, None))
rv.sort()
return [ (None, rv) ]
class ChangeKind(Action):
"""
Changes the kind of thing we're navigating over.
"""
def __init__(self, kind):
self.kind = kind
def get_selected(self):
return persistent.navigation == self.kind
def __call__(self):
if persistent.navigation == self.kind:
return
persistent.navigation = self.kind
renpy.jump("navigation_loop")
class ChangeSort(Action):
"""
Changes the sort order.
"""
def __init__(self, sort):
self.sort = sort
def get_selected(self):
return persistent.navigation_sort[persistent.navigation] == self.sort
def __call__(self):
if self.get_selected():
return
persistent.navigation_sort[persistent.navigation] = self.sort
renpy.jump("navigation_loop")
screen navigation:
frame:
style_group "l"
style "l_root"
window:
has vbox
frame style "l_label":
has hbox xfill True
text _("Navigate: [project.current.name]") style "l_label_text"
frame:
style "l_alternate"
style_group "l_small"
has hbox
if persistent.navigation != "file":
text _("Order: ")
textbutton _("alphabetical") action navigation.ChangeSort("alphabetical")
text " | "
textbutton _("by-file") action navigation.ChangeSort("by-file")
text " | "
textbutton _("natural") action navigation.ChangeSort("natural")
null width HALF_INDENT
textbutton _("refresh") action Jump("navigation_refresh")
add HALF_SPACER
frame style "l_indent":
hbox:
spacing HALF_INDENT
text _("Category:")
textbutton _("files") action navigation.ChangeKind("file")
textbutton _("labels") action navigation.ChangeKind("label")
textbutton _("defines") action navigation.ChangeKind("define")
textbutton _("transforms") action navigation.ChangeKind("transform")
textbutton _("screens") action navigation.ChangeKind("screen")
textbutton _("callables") action navigation.ChangeKind("callable")
textbutton _("TODOs") action navigation.ChangeKind("todo")
add SPACER
add SEPARATOR
frame style "l_indent_margin":
if groups:
viewport:
mousewheel True
scrollbars "vertical"
yadjustment navigation.adjustments[persistent.navigation]
vbox:
style_group "l_navigation"
for group_name, group in groups:
if group_name is not None:
text "[group_name!q]"
if persistent.navigation == "todo":
vbox:
for name, filename, line in group:
textbutton "[name!q]" action editor.Edit(filename, line)
else:
hbox:
box_wrap True
for name, filename, line in group:
textbutton "[name!q]" action editor.Edit(filename, line)
if group_name is not None:
add SPACER
if persistent.navigation == "file":
add SPACER
textbutton _("+ Add script file") action Jump("add_file") style "l_button"
else:
fixed:
if persistent.navigation == "todo":
text _("No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."):
text_align 0.5
xalign 0.5
yalign 0.5
else:
text _("The list of names is empty."):
xalign 0.5
yalign 0.5
textbutton _("Back") action Jump("front_page") style "l_left_button"
textbutton _("Launch Project") action project.Launch() style "l_right_button"
label navigation:
label navigation_loop:
python in navigation:
kind = persistent.navigation
if kind == "file":
groups = group_and_sort_files()
else:
groups = group_and_sort(kind)
renpy.call_screen("navigation", groups=groups)
label navigation_refresh:
$ project.current.update_dump(True)
jump navigation_loop
-107
View File
@@ -1,107 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
import shutil
import os
import time
import re
screen select_template:
default result = project.manager.get("template")
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Choose Project Template")
hbox:
frame:
style "l_indent"
xmaximum ONETHIRD
viewport:
scrollbars "vertical"
vbox:
for p in project.manager.templates:
textbutton "[p.name!q]" action SetScreenVariable("result", p) style "l_list"
frame:
style "l_indent"
xmaximum TWOTHIRDS
text _("Please select a template to use for your new project. The template sets the default font and the user interface language. If your language is not supported, choose 'english'.")
textbutton _("Back") action Jump("front_page") style "l_left_button"
textbutton _("Continue") action Return(result) style "l_right_button"
label new_project:
if persistent.projects_directory is None:
call choose_projects_directory
python hide:
project_name = interface.input(
_("PROJECT NAME"),
_("Please enter the name of your project:"),
filename=True,
cancel=Jump("front_page"))
project_name = project_name.strip()
if not project_name:
interface.error(_("The project name may not be empty."))
project_dir = os.path.join(persistent.projects_directory, project_name)
if project.manager.get(project_name) is not None:
interface.error(_("[project_name!q] already exists. Please choose a different project name."), project_name=project_name)
if os.path.exists(project_dir):
interface.error(_("[project_dir!q] already exists. Please choose a different project name."), project_dir=project_dir)
if len(project.manager.templates) == 1:
template = project.manager.templates[0]
else:
template = renpy.call_screen("select_template")
template_path = template.path
with interface.error_handling("creating a new project"):
shutil.copytree(template_path, project_dir)
# Delete the tmp directory, if it exists.
if os.path.isdir(os.path.join(project_dir, "tmp")):
os.path.rmtree(os.path.join(project_dir, "tmp"))
# Delete project.json, which must exist.
os.unlink(os.path.join(project_dir, "project.json"))
# Change the save directory in options.rpy
fn = os.path.join(project_dir, "game/options.rpy")
with open(fn, "rb") as f:
options = f.read().decode("utf-8")
options = options.replace("PROJECT_NAME", project_name)
options = options.replace("UNIQUE", str(int(time.time())))
with open(fn, "wb") as f:
f.write(options.encode("utf-8"))
# Activate the project.
with interface.error_handling("activating the new project"):
project.manager.scan()
project.Select(project.manager.get(project_name))()
call choose_theme_callable
jump front_page
-305
View File
@@ -1,305 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
## This file contains some of the options that can be changed to customize
## your Ren'Py game. It only contains the most common options... there
## is quite a bit more customization you can do.
##
## Lines beginning with two '#' marks are comments, and you shouldn't
## uncomment them. Lines beginning with a single '#' mark are
## commented-out code, and you may want to uncomment them when
## appropriate.
init -1 python hide:
## Should we enable the use of developer tools? This should be
## set to False before the game is released, so the user can't
## cheat using developer tools.
config.developer = True
## These control the width and height of the screen.
config.screen_width = 800
config.screen_height = 600
## This controls the title of the window, when Ren'Py is
## running in a window.
config.window_title = u"Ren'Py Launcher"
# These control the name and version of the game, that are reported
# with tracebacks and other debugging logs.
config.name = "Ren'Py Launcher"
config.version = renpy.version().split()[1]
#########################################
# Themes
## We then want to call a theme function. themes.roundrect is
## a theme that features the use of rounded rectangles. It's
## the only theme we currently support.
##
## The theme function takes a number of parameters that can
## customize the color scheme.
theme.roundrect(
## Theme: Roundrect
## Color scheme: Basic Blue
## The color of an idle widget face.
widget = "#003c78",
## The color of a focused widget face.
widget_hover = "#0050a0",
## The color of the text in a widget.
widget_text = "#c8ffff",
## The color of the text in a selected widget. (For
## example, the current value of a preference.)
widget_selected = "#ffffc8",
## The color of a disabled widget face.
disabled = "#404040",
## The color of disabled widget text.
disabled_text = "#c8c8c8",
## The color of informational labels.
label = "#ffffff",
## The color of a frame containing widgets.
frame = "#6496c8",
## The background of the main menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
mm_root = "#dcebff",
## The background of the game menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
gm_root = "#dcebff",
## If this is True, the in-game window is rounded. If False,
## the in-game window is square.
rounded_window = False,
## And we're done with the theme. The theme will customize
## various styles, so if we want to change them, we should
## do so below.
)
#########################################
## Help.
## This lets you configure the help option on the Ren'Py menus.
## It may be:
## - A label in the script, in which case that label is called to
## show help to the user.
## - A file name relative to the base directory, which is opened in a
## web browser.
## - None, to disable help.
config.help = "README.html"
#########################################
## Transitions.
## Used when entering the game menu from the game.
config.enter_transition = None
## Used when exiting the game menu to the game.
config.exit_transition = None
## Used between screens of the game menu.
config.intra_transition = None
## Used when entering the game menu from the main menu.
config.main_game_transition = None
## Used when returning to the main menu from the game.
config.game_main_transition = None
## Used when entering the main menu from the splashscreen.
config.end_splash_transition = None
## Used when entering the main menu after the game has ended.
config.end_game_transition = None
## Used when a game is loaded.
config.after_load_transition = None
## Used when the window is shown.
config.window_show_transition = None
## Used when the window is hidden.
config.window_hide_transition = None
#########################################
## This is the name of the directory where the game's data is
## stored. (It needs to be set early, before any other init code
## is run, so the persistent information can be found by the init code.)
python early:
config.save_directory = "launcher-4"
init -1 python hide:
#########################################
## Default values of Preferences.
## Note: These options are only evaluated the first time a
## game is run. To have them run a second time, delete
## game/saves/persistent
## Should we start in fullscreen mode?
config.default_fullscreen = False
## The default text speed in characters per second. 0 is infinite.
config.default_text_cps = 0
#########################################
## More customizations can go here.
config.sound = False
config.quit_action = Quit(confirm=False)
config.gl_resize = False
config.window_icon = "logo.png"
config.windows_icon = "logo32.png"
config.has_autosave = False
config.log_enable = False
config.mouse_hide_time = 86400 * 366
_game_menu_screen = None
config.underlay = [
renpy.Keymap(
quit = renpy.quit_event,
iconify = renpy.iconify,
choose_renderer = renpy.curried_call_in_new_context("_choose_renderer"),
),
]
config.rollback_enabled = False
## This section controls how to build Ren'Py. (Building the launcher is how
## we build Ren'Py distributions.)
init python:
## We're building Ren'Py tonight.
build.renpy = True
## The version number that's supplied to the updater.
build.version = "Ren'Py {}".format(config.version)
## The name that's used for directories and archive files. For example, if
## this is 'mygame-1.0', the windows distribution will be in the
## directory 'mygame-1.0-win', in the 'mygame-1.0-win.zip' file.
if 'RENPY_NIGHTLY' in os.environ:
build.directory_name = os.environ['RENPY_NIGHTLY']
else:
build.directory_name = "renpy-" + config.version.rsplit('.', 1)[0]
## The name that's uses for executables - the program that users will run
## to start the game. For example, if this is 'mygame', then on Windows,
## users can click 'mygame.exe' to start the game.
build.executable_name = "renpy"
## If True, Ren'Py will include update information into packages. This
## allows the updater to run.
build.include_update = True
## Clear out various file patterns.
build.renpy_patterns = [ ]
build.early_base_patterns = [ ]
build.base_patterns = [ ]
build.late_base_patterns = [ ]
# We don't need to clear out the executable patterns, since they're
# correct for Ren'Py.
## Now, add the Ren'Py distribution in using classify_renpy.
build.classify_renpy("**~", None)
build.classify_renpy("**/#*", None)
build.classify_renpy("**/thumbs.db", None)
build.classify_renpy("**/.*", None)
build.classify_renpy("**.old", None)
build.classify_renpy("**.new", None)
build.classify_renpy("**.bak", None)
build.classify_renpy("**.pyc", None)
build.classify_renpy("**/log.txt", None)
build.classify_renpy("**/saves/", None)
build.classify_renpy("**/tmp/", None)
build.classify_renpy("**/.Editra", None)
# main source.
build.classify_renpy("renpy.py", "source")
build.classify_renpy("renpy/**", "source")
# games.
build.classify_renpy("launcher/game/theme/", None)
build.classify_renpy("launcher/**", "source")
build.classify_renpy("templates/**", "source")
build.classify_renpy("the_question/**", "source")
build.classify_renpy("tutorial/**", "source")
# docs.
build.classify_renpy("doc/", "source")
build.classify_renpy("doc/.doctrees/", None)
build.classify_renpy("doc/_sources/", None)
build.classify_renpy("doc/**", "source")
build.classify_renpy("LICENSE.txt", "source")
# module.
build.classify_renpy("module/", "source")
build.classify_renpy("module/*.c", "source")
build.classify_renpy("module/gen/", "source")
build.classify_renpy("module/gen/*.c", "source")
build.classify_renpy("module/*.h", "source")
build.classify_renpy("module/*.py*", "source")
build.classify_renpy("module/include/", "source")
build.classify_renpy("module/include/*.pxd", "source")
build.classify_renpy("module/pysdlsound/", "source")
build.classify_renpy("module/pysdlsound/*.py", "source")
build.classify_renpy("module/pysdlsound/*.pyx", "source")
# all-platforms binary.
build.classify_renpy("lib/*/renpy", None)
build.classify_renpy("lib/*/renpy.exe", None)
build.classify_renpy("lib/**", "binary")
build.classify_renpy("renpy.sh", "binary")
build.classify_renpy("renpy.exe", "binary")
# renpy.app is now built from scratch from distribute.rpy.
# jedit rules.
build.classify_renpy("jedit/**", "jedit")
# editra rules.
build.classify_renpy("editra/", "editra-all")
build.classify_renpy("editra/Editra.edit.py", "editra-all")
build.classify_renpy("editra/Editra/**", "editra-linux editra-windows")
build.classify_renpy("editra/Editra-mac.app/**", "editra-mac")
build.classify_renpy("editra/lib/**", "editra-windows")
build.classify_renpy("editra/editra.exe", "editra-windows")
# Executable rules.
build.executable("editra/Editra/Editra")
# Packages.
build.packages = [ ]
build.package("sdk", "zip tar.bz2", "source binary")
build.package("source", "tar.bz2", "source", update=False)
build.package("jedit", "zip", "jedit")
build.package("editra-linux", "tar.bz2", "editra-all editra-linux", dlc=True)
build.package("editra-mac", "zip", "editra-all editra-mac", dlc=True)
build.package("editra-windows", "zip", "editra-all editra-windows", dlc=True)
-208
View File
@@ -1,208 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python in distribute:
import time
import zipfile
import tarfile
import zlib
import struct
import stat
import shutil
from zipfile import crc32
zlib.Z_DEFAULT_COMPRESSION = 9
class ZipFile(zipfile.ZipFile):
def write_with_info(self, zinfo, filename):
"""Put the bytes from filename into the archive under the name
arcname."""
if not self.fp:
raise RuntimeError(
"Attempt to write to ZIP archive that was already closed")
st = os.stat(filename)
isdir = stat.S_ISDIR(st.st_mode)
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
if isdir:
zinfo.file_size = 0
zinfo.compress_size = 0
zinfo.CRC = 0
self.filelist.append(zinfo)
self.NameToInfo[zinfo.filename] = zinfo
self.fp.write(zinfo.FileHeader())
return
with open(filename, "rb") as fp:
# 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 * 1024)
if not buf:
break
file_size = file_size + len(buf)
CRC = crc32(buf, CRC) & 0xffffffff
if cmpr:
buf = cmpr.compress(buf)
compress_size = compress_size + len(buf)
self.fp.write(buf)
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
class ZipPackage(object):
"""
A class that creates a zip file.
"""
def __init__(self, filename):
self.zipfile = ZipFile(filename, "w", zipfile.ZIP_DEFLATED)
def add_file(self, name, path, xbit):
if path is None:
raise Exception("path for " + name + " must not be None.")
zi = zipfile.ZipInfo(name)
try:
s = os.stat(path)
zi.date_time = time.gmtime(s.st_mtime)[:6]
except:
zi.date_time = time.gmtime()[:6]
zi.compress_type = zipfile.ZIP_DEFLATED
zi.create_system = 3
if xbit:
zi.external_attr = long(0100755) << 16
else:
zi.external_attr = long(0100644) << 16
self.zipfile.write_with_info(zi, path)
def add_directory(self, name, path):
if path is None:
return
zi = zipfile.ZipInfo(name + "/")
s = os.stat(path)
zi.date_time = time.gmtime(s.st_mtime)[:6]
zi.compress_type = zipfile.ZIP_STORED
zi.create_system = 3
zi.external_attr = (long(0040755) << 16) | 0x10
self.zipfile.write_with_info(zi, path)
def close(self):
self.zipfile.close()
class TarPackage(object):
def __init__(self, filename, mode, notime=False):
"""
notime
If true, times will be forced to the epoch.
"""
self.tarfile = tarfile.open(filename, mode)
self.tarfile.dereference = True
self.notime = notime
def add_file(self, name, path, xbit):
if path is not None:
info = self.tarfile.gettarinfo(path, name)
else:
info = tarfile.TarInfo(name)
info.size = 0
info.mtime = int(time.time())
info.type = tarfile.DIRTYPE
if xbit:
info.mode = 0755
else:
info.mode = 0644
info.uid = 1000
info.gid = 1000
info.uname = "renpy"
info.gname = "renpy"
if self.notime:
info.mtime = 0
if info.isreg():
with open(path, "rb") as f:
self.tarfile.addfile(info, f)
else:
self.tarfile.addfile(info)
def add_directory(self, name, path):
self.add_file(name, path, True)
def close(self):
self.tarfile.close()
class DirectoryPackage(object):
def mkdir(self, path):
if not os.path.isdir(path):
os.mkdir(path, 0755)
def __init__(self, path):
self.path = path
self.mkdir(path)
def add_file(self, name, path, xbit):
fn = os.path.join(self.path, name)
shutil.copy2(path, fn)
if xbit:
os.chmod(fn, 0755)
else:
os.chmod(fn, 0644)
def add_directory(self, name, path):
fn = os.path.join(self.path, name)
self.mkdir(fn)
def close(self):
return
Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 B

File diff suppressed because it is too large Load Diff
-203
View File
@@ -1,203 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
if persistent.gl_enable is None:
persistent.gl_enable = True
config.gl_enable = persistent.gl_enable
if persistent.windows_console is None:
persistent.windows_console = False
def scan_translations():
languages = renpy.known_languages()
if not languages:
return None
rv = [ ( "English", None) ]
for i in languages:
rv.append((i.title(), i))
return rv
screen preferences:
$ translations = scan_translations()
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("Launcher Preferences")
add HALF_SPACER
hbox:
frame:
style "l_indent"
xmaximum ONETHIRD
xfill True
has vbox
# Projects directory selection.
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Projects Directory:")
add HALF_SPACER
frame style "l_indent":
if persistent.projects_directory:
textbutton _("[persistent.projects_directory!q]") action Jump("projects_directory_preference")
else:
textbutton _("Not Set") action Jump("projects_directory_preference")
add SPACER
# Text editor selection.
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Text Editor:")
add HALF_SPACER
frame style "l_indent":
if persistent.editor:
textbutton persistent.editor action Jump("editor_preference")
else:
textbutton _("Not Set") action Jump("editor_preference")
add SPACER
if ability.can_update:
# Update URL selection.
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Update Channel:")
add HALF_SPACER
frame style "l_indent":
textbutton persistent.update_channel action Jump("update_preference")
frame:
style "l_indent"
xmaximum ONETHIRD
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Navigation Options:")
add HALF_SPACER
textbutton _("Include private names") style "l_checkbox" action ToggleField(persistent, "navigate_private")
textbutton _("Include library names") style "l_checkbox" action ToggleField(persistent, "navigate_library")
add SPACER
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Launcher Options:")
add HALF_SPACER
textbutton _("Hardware rendering") style "l_checkbox" action ToggleField(persistent, "gl_enable")
textbutton _("Show templates") style "l_checkbox" action ToggleField(persistent, "show_templates")
if renpy.windows:
textbutton _("Console output") style "l_checkbox" action ToggleField(persistent, "windows_console")
frame:
style "l_indent"
xmaximum ONETHIRD
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Actions:")
add HALF_SPACER
textbutton _("Open launcher project") style "l_nonbox" action [ project.Select("launcher"), Jump("front_page") ]
if translations:
add SPACER
# Text editor selection.
add SEPARATOR2
frame:
style "l_indent"
yminimum 75
has vbox
text _("Language:")
add HALF_SPACER
# frame style "l_indent":
for tlname, tlvalue in translations:
textbutton tlname action Language(tlvalue) style "l_list"
textbutton _("Back") action Jump("front_page") style "l_left_button"
label projects_directory_preference:
call choose_projects_directory
jump preferences
label preferences:
call screen preferences
jump preferences
-559
View File
@@ -1,559 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Code that manages projects.
init python:
try:
import EasyDialogsWin as EasyDialogs
except:
EasyDialogs = None
import os
init python in project:
from store import persistent, config, Action, renpy
import store.util as util
import store.interface as interface
import sys
import os.path
import json
import subprocess
import re
import tempfile
class Project(object):
def __init__(self, path):
while path.endswith("/"):
path = path[:-1]
if not os.path.exists(path):
raise Exception("{} does not exist.".format(path))
# The name of the project.
self.name = os.path.basename(path)
# The path to the project.
self.path = path
# The path to the game directory.
gamedir = os.path.join(path, "game")
if os.path.isdir(gamedir):
self.gamedir = gamedir
else:
self.gamedir = path
# Load the data.
self.load_data()
# The project's temporary directory.
self.tmp = None
# This contains the result of dumping information about the game
# to disk.
self.dump = { }
# The mtime of the last dump file loaded.
self.dump_mtime = 0
def get_dump_filename(self):
self.make_tmp()
return os.path.join(self.tmp, "navigation.json")
def load_data(self):
try:
f = open(os.path.join(self.path, "project.json"), "rb")
self.data = json.load(f)
f.close()
except:
self.data = { }
self.update_data()
def save_data(self):
"""
Saves the project data.
"""
try:
with open(os.path.join(self.path, "project.json"), "wb") as f:
json.dump(self.data, f)
except:
self.load_data()
def update_data(self):
data = self.data
data.setdefault("build_update", False)
data.setdefault("packages", [ "all" ])
def make_tmp(self):
"""
Makes the project's temporary directory, if it doesn't exist
yet.
"""
if self.tmp and os.path.isdir(self.tmp):
return
tmp = os.path.join(self.path, "tmp")
try:
os.mkdir(tmp)
except:
pass
if os.path.isdir(tmp):
self.tmp = tmp
return
self.tmp = tempfile.mkdtemp()
def temp_filename(self, filename):
"""
Returns a filename in the temporary directory.
"""
self.make_tmp()
return os.path.join(self.tmp, filename)
def launch(self, args=[], wait=False, env={}):
"""
Launches the project.
`args`
Additional arguments to give to the project.
`wait`
If true, waits for the launched project to terminate before
continuing.
`env`
Additional variables to include in the environment.
"""
self.make_tmp()
# Find the python executable to run.
executable_path = os.path.dirname(sys.executable)
if renpy.renpy.windows:
extension = ".exe"
else:
extension = ""
if persistent.windows_console:
executables = [ "python" + extension ]
else:
executables = [ "pythonw" + extension ]
executables.append(sys.executable)
for i in executables:
executable = os.path.join(executable_path, i)
if os.path.exists(executable):
break
else:
raise Exception("Python interpreter not found: %r", executables)
# Put together the basic command line.
cmd = [ executable, "-EO", sys.argv[0] ]
cmd.append(self.path)
cmd.extend(args)
# Add flags to dump game info.
cmd.append("--json-dump")
cmd.append(self.get_dump_filename())
if persistent.navigate_private:
cmd.append("--json-dump-private")
if persistent.navigate_library:
cmd.append("--json-dump-common")
environ = dict(os.environ)
environ.update(env)
for k in environ:
environ[k] = renpy.fsencode(environ[k])
# Launch the project.
cmd = [ renpy.fsencode(i) for i in cmd ]
p = subprocess.Popen(cmd, env=environ)
if wait:
p.wait()
def update_dump(self, force=False, gui=True):
"""
If the dumpfile does not exist, runs Ren'Py to create it. Otherwise,
loads it in iff it's newer than the one that's already loaded.
"""
dump_filename = self.get_dump_filename()
if force or not os.path.exists(dump_filename):
if gui:
interface.processing(_("Ren'Py is scanning the project..."))
self.launch(["quit"], wait=True)
if not os.path.exists(dump_filename):
self.dump["error"] = True
return
file_mtime = os.path.getmtime(dump_filename)
if file_mtime == self.dump_mtime:
return
self.dump_mtime = file_mtime
try:
with open(dump_filename, "r") as f:
self.dump = json.load(f)
# add todo list to dump data
self.update_todos()
except:
self.dump["error"] = True
def update_todos(self):
"""
Scans the scriptfiles for lines TODO comments and add them to
the dump data.
"""
todos = self.dump.setdefault("location", {})["todo"] = {}
files = self.script_files()
for f in files:
data = file(self.unelide_filename(f))
for l, line in enumerate(data):
l += 1
try:
line = line.decode("utf-8")
except:
continue
m = re.search(r".*#\s*TODO(\s*:\s*|\s+)(.*)", line, re.I)
if m is None:
continue
raw_todo_text = m.group(2).strip()
todo_text = raw_todo_text
index = 0
while not todo_text or todo_text in todos:
index += 1
todo_text = "{0} ({1})".format(raw_todo_text, index)
todos[todo_text] = [f, l]
def unelide_filename(self, fn):
"""
Unelides the filename relative to the project base.
"""
fn1 = os.path.join(self.path, fn)
if os.path.exists(fn1):
return fn1
fn2 = os.path.join(config.renpy_base, fn)
if os.path.exists(fn2):
return fn2
return fn
def script_files(self):
"""
Return a list of the script files that make up the project. These
are elided, and so need to be passed to unelide_filename before they
can be included in the project.
"""
rv = [ ]
rv.extend(i for i, isdir in util.walk(self.path) if (not isdir) and (i.endswith(".rpy") or i.endswith(".rpym")) )
return rv
class ProjectManager(object):
"""
This maintains a list of the various types of projects that
we know about.
"""
def __init__(self):
# The projects directory.
self.projects_directory = ""
# Normal projects, in alphabetical order by lowercase name.
self.projects = [ ]
# Template projects.
self.templates = [ ]
# All projects - normal, template, and hidden.
self.all_projects = [ ]
# Directories that have been scanned.
self.scanned = set()
self.scan()
def scan(self):
"""
Scans for projects.
"""
if (persistent.projects_directory is not None) and not os.path.isdir(persistent.projects_directory):
persistent.projects_directory = None
self.projects_directory = persistent.projects_directory
self.projects = [ ]
self.templates = [ ]
self.all_projects = [ ]
self.scanned = set()
if self.projects_directory is not None:
self.scan_directory(self.projects_directory)
self.scan_directory(config.renpy_base)
self.scan_directory(os.path.join(config.renpy_base, "templates"))
self.projects.sort(key=lambda p : p.name.lower())
self.templates.sort(key=lambda p : p.name.lower())
def scan_directory(self, d):
"""
Scans for projects in directories directly underneath `d`.
"""
global current
d = os.path.abspath(d)
if not os.path.isdir(d):
return
for pdir in os.listdir(d):
ppath = os.path.join(d, pdir)
# A project must be a directory.
if not os.path.isdir(ppath):
continue
# A project has either a game/ directory, or a project.json
# file.
if (not os.path.isdir(os.path.join(ppath, "game"))) and (not os.path.exists(os.path.join(ppath, "project.json"))):
continue
if ppath in self.scanned:
continue
self.scanned.add(ppath)
# We have a project directory, so create a Project.
p = Project(ppath)
project_type = p.data.get("type", "normal")
if project_type == "hidden":
pass
elif project_type == "template":
self.templates.append(p)
else:
self.projects.append(p)
self.all_projects.append(p)
# Select the default project.
if persistent.active_project is not None:
p = self.get(persistent.active_project)
if p is not None:
current = p
return
p = self.get("tutorial")
if p is not None:
current = p
return
current = None
def get(self, name):
"""
Gets the project with the given name.
Returns None if the project doesn't exist.
"""
for p in self.all_projects:
if p.name == name:
return p
return None
manager = ProjectManager()
# The current project.
current = None
# Actions
class Select(Action):
"""
An action that causes p to become the selected project when it was
clicked. If label is not None, jumps to the given label.
"""
def __init__(self, p, label=None):
"""
`p`
Either a project object, or a string giving the name of a
project.
`label`
The label to jump to when clicked.
"""
if isinstance(p, basestring):
p = manager.get(p)
self.project = p
self.label = label
def get_selected(self):
if self.project is None:
return False
if current is None:
return False
return current.path == self.project.path
def get_sensitive(self):
return self.project is not None
def __call__(self):
global current
current = self.project
persistent.active_project = self.project.name
renpy.restart_interaction()
if self.label is not None:
renpy.jump(self.label)
class Launch(Action):
"""
An action that launches the supplied project, or the current
project if no project is supplied.
"""
def __init__(self, p=None):
if p is None:
self.project = current
elif isinstance(p, basestring):
self.project = manager.get(p)
else:
self.project = p
def get_sensitive(self):
return self.project is not None
def __call__(self):
self.project.launch()
class Rescan(Action):
def __call__(self):
"""
Rescans the projects directory.
"""
manager.scan()
renpy.restart_interaction()
manager.scan()
if isinstance(persistent.projects_directory, str):
persistent.projects_directory = renpy.fsdecode(persistent.projects_directory)
###############################################################################
# Code to choose the projects directory.
label choose_projects_directory:
python hide:
interface.interaction(_("PROJECTS DIRECTORY"), _("Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"), _("This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."),)
path = persistent.projects_directory
if path:
default_path = path
else:
try:
default_path = os.path.dirname(os.path.abspath(config.renpy_base))
except:
default_path = os.path.abspath(config.renpy_base)
if EasyDialogs:
choice = EasyDialogs.AskFolder(defaultLocation=default_path, wanted=unicode)
if choice is not None:
path = choice
else:
path = None
else:
try:
cmd = [ "/usr/bin/python", os.path.join(config.gamedir, "tkaskdir.py"), renpy.fsencode(default_path) ]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
choice = p.stdout.read()
p.wait()
if choice:
path = renpy.fsdecode(choice)
except:
import traceback
traceback.print_exc()
path = None
interface.error(_("Ren'Py was unable to run python with tkinter to choose the projects directory."), label=None)
if path is None:
path = default_path
interface.info(_("Ren'Py has set the projects directory to:"), "[path!q]", path=path)
path = renpy.fsdecode(path)
persistent.projects_directory = path
project.manager.scan()
return
-8
View File
@@ -1,8 +0,0 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAnEdzfwV6FFnmjkbJHJKJ59jqLTGkPSES5LBFbxwweGuC3LU2sNs+
tRlWx+2+kbW6azb5yteP/O05/hzHdtIa4slao7s8A/wf0zA6HbLX4H5iqSosDvuw
FP9DAF46vH0Qn1a3k97JFV2eXoGAbwHZICKhbIPCm7qR39G8FvUrw7grCS+5Scb+
LzqkBv6TnwRDB4agcwhlkA432s6BTU8p9RIFmyldCEgq0SXeK07lkuDmOplp6IdL
bVwLoRWg6pngIEoPo/Qxt8ZnLdBthN+TAsMRiquz17GaAvERbkUBwYtlt7R8qx01
F3vzweKXSCguzr9XQBQflkVu2y6cmIEwPQIDAQAB
-----END RSA PUBLIC KEY-----
Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

-303
View File
@@ -1,303 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init -1 python:
# The color of non-interactive text.
TEXT = "#545454"
# Colors for buttons in various states.
IDLE = "#42637b"
HOVER = "#d86b45"
DISABLED = "#808080"
# Colors for reversed text buttons (selected list entries).
REVERSE_IDLE = "#78a5c5"
REVERSE_HOVER = "#d86b45"
REVERSE_TEXT = "#ffffff"
# Colors for the scrollbar thumb.
SCROLLBAR_IDLE = "#dfdfdf"
SCROLLBAR_HOVER = "#d86b45"
# An image used as a separator pattern.
PATTERN = "pattern.png"
# A displayable used for the background of everything.
BACKGROUND = "background.png"
# A displayable used for the background of windows
# containing commands, preferences, and navigation info.
WINDOW = Frame("window.png", 0, 0, tile=True)
# A displayable used for the background of the projects list.
PROJECTS_WINDOW = Null()
# A displayable used the background of information boxes.
INFO_WINDOW = "#f9f9f9"
# Colors for the titles of information boxes.
ERROR_COLOR = "#d15353"
INFO_COLOR = "#545454"
INTERACTION_COLOR = "#d19753"
QUESTION_COLOR = "#d19753"
# The color of input text.
INPUT_COLOR = "#d86b45"
init 1 python:
INDENT = 20
HALF_INDENT = 10
SCROLLBAR_SIZE = 16
SEPARATOR = Frame(PATTERN, 0, 0, tile=True, ymaximum=5, yalign=1.0)
SEPARATOR2 = Frame(PATTERN, 0, 0, tile=True, ymaximum=10, yalign=1.0)
SPACER_HEIGHT = 12
SPACER = Null(height=SPACER_HEIGHT)
HALF_SPACER_HEIGHT = 6
HALF_SPACER = Null(height=HALF_SPACER_HEIGHT)
# FONTS/WEIGHTS
LIGHT = "Roboto-Light.ttf"
REGULAR = "Roboto-Regular.ttf"
DARK = "Roboto-Medium.ttf"
# DIVIDING THE SCREEN
ONETHIRD = 258
TWOTHIRDS = 496
ONEHALF = 377
# Default style.
style.l_default = Style(style.default)
style.l_default.font = LIGHT
style.l_default.color = TEXT
style.l_default.idle_color = IDLE
style.l_default.hover_color = HOVER
style.l_default.size = 18
style.l_text = Style(style.l_default)
style.l_button = Style(style.l_default)
style.l_button_text = Style(style.l_default)
style.l_button_text.insensitive_color = DISABLED
style.l_button_text.selected_font = REGULAR
# A small button, used at the bottom of the screen.
style.l_link = Style(style.l_default)
style.l_link_text = Style(style.l_default)
style.l_link_text.size = 14
style.l_link_text.font = LIGHT
# Action buttons on the bottom of the screen.
style.l_right_button = Style(style.l_default)
style.l_right_button.xalign = 1.0
style.l_right_button.ypos = 600 - 128 + 12
style.l_right_button.left_margin = 8 + INDENT
style.l_right_button.right_margin = 10 + INDENT
style.l_right_button_text = Style(style.l_default)
style.l_right_button_text.size = 30
style.l_left_button = Style(style.l_right_button)
style.l_left_button.xalign = 0.0
style.l_left_button_text = Style(style.l_right_button_text)
# The root frame. This contains everything but the bottom navigation, back
# button, and tooltip button.
style.l_root = Style(style.l_default)
style.l_root.background = BACKGROUND
style.l_root.xpadding = 10
style.l_root.top_padding = 64
style.l_root.bottom_padding = 128
# An inner window.
style.l_window = Style(style.l_default)
style.l_window.background = WINDOW
style.l_window.left_padding = 6
style.l_window.xfill = True
style.l_window.yfill = True
# Normal-sized labels.
style.l_label = Style(style.l_default)
style.l_label.xfill = True
style.l_label.top_padding = 10
style.l_label.bottom_padding = 8
style.l_label.bottom_margin = 12
style.l_label.background = SEPARATOR
style.l_label_text = Style(style.l_default)
style.l_label_text.size = 24
style.l_label_text.xpos = INDENT
style.l_label_text.yoffset = 6
# Small labels.
style.l_label_small = Style(style.l_default)
style.l_label_small.xfill = True
style.l_label_small.bottom_padding = 8
style.l_label_small.bottom_margin = HALF_SPACER_HEIGHT
style.l_label_small.background = SEPARATOR
style.l_label_small_text = Style(style.l_default)
style.l_label_small_text.xpos = INDENT
style.l_label_small_text.yoffset = 6
style.l_label_small_text.size = 20
# Alternate labels. This nests inside an l_label, and gives a button
# or label that's nested inside another label.
style.l_alternate = Style(style.l_default)
style.l_alternate.xalign = 1.0
style.l_alternate.yalign = 1.0
style.l_alternate.yoffset = 4
style.l_alternate.right_margin = INDENT
style.l_alternate_text = Style(style.l_default)
style.l_alternate_text.size = 14
style.l_alternate_text.font = LIGHT
style.l_alternate_text.text_align = 1.0
style.l_small_button = Style(style.l_button)
style.l_small_button_text = Style(style.l_button_text)
style.l_small_button_text.size = 14
style.l_small_text = Style(style.l_text)
style.l_small_text.size = 14
# Indents its contents.
style.l_indent = Style(style.l_default)
style.l_indent.left_margin = INDENT
# Indents its contents and pads them vertically.
style.l_indent_margin = Style(style.l_indent)
style.l_indent_margin.ymargin = 6
# List button.
style.l_list = Style(style.l_default)
style.l_list.left_padding = HALF_INDENT
style.l_list.xfill = True
style.l_list.selected_background = REVERSE_IDLE
style.l_list.selected_hover_background = REVERSE_HOVER
style.l_list_text = Style(style.l_default)
style.l_list_text.idle_color = IDLE
style.l_list_text.hover_color = HOVER
style.l_list_text.selected_idle_color = REVERSE_TEXT
style.l_list_text.selected_hover_color = REVERSE_TEXT
style.l_list_text.insensitive_color = DISABLED
style.l_list2 = Style(style.l_list)
style.l_list2.left_padding = HALF_INDENT + INDENT
style.l_list2_text = Style(style.l_list_text)
# Scrollbar.
style.l_vscrollbar = Style(style.l_default)
style.l_vscrollbar.thumb = Fixed(
Solid(SCROLLBAR_IDLE, xmaximum=8, xalign=0.5),
Image("vscrollbar_center.png", xalign=0.5, yalign=0.5),
xmaximum = SCROLLBAR_SIZE)
style.l_vscrollbar.hover_thumb = Fixed(
Solid(SCROLLBAR_HOVER, xmaximum=8, xalign=0.5),
Image("vscrollbar_center.png", xalign=0.5, yalign=0.5),
xmaximum = SCROLLBAR_SIZE)
style.l_vscrollbar.xmaximum = SCROLLBAR_SIZE
style.l_vscrollbar.bar_vertical = True
style.l_vscrollbar.bar_invert = True
style.l_vscrollbar.unscrollable = "hide"
# Information window.
style.l_info_vbox = Style(style.vbox)
style.l_info_vbox.yalign = 0.5
style.l_info_vbox.xalign = 0.5
style.l_info_vbox.xfill = True
style.l_info_frame = Style(style.l_default)
style.l_info_frame.ypadding = 21
style.l_info_frame.xfill = True
style.l_info_frame.background = Fixed(
INFO_WINDOW,
Frame(PATTERN, 0, 0, tile=True, ymaximum=5, yalign=0.0, yoffset=8),
Frame(PATTERN, 0, 0, tile=True, ymaximum=5, yalign=1.0, yoffset=-8),
)
style.l_info_frame.yminimum = 180
style.l_info_frame.ypos = 75
style.l_info_label = Style(style.l_default)
style.l_info_label.xalign = 0.5
style.l_info_label.ypos = 75
style.l_info_label.yanchor = 1.0
style.l_info_label.yoffset = 12
style.l_info_label_text = Style(style.l_default)
style.l_info_label_text.size = 36
style.l_info_text = Style(style.l_default)
style.l_info_text.xalign = 0.5
style.l_info_button = Style(style.l_button)
style.l_info_button.xalign = 0.5
style.l_info_button.xmargin = 50
style.l_info_button_text = Style(style.l_button_text)
style.l_info_button_text.text_align = 0.5
style.l_info_button_text.layout = "subtitle"
# Code navigation
style.l_navigation_button = Style(style.l_button)
style.l_navigation_button.size_group = "navigation"
style.l_navigation_button.right_margin = INDENT
style.l_navigation_button.top_margin = 3
style.l_navigation_button_text = Style(style.l_button_text)
style.l_navigation_button_text.size = 14
style.l_navigation_button_text.font = REGULAR
style.l_navigation_text = Style(style.l_text)
style.l_navigation_text.size = 12
style.l_navigation_text.font = LIGHT
style.l_navigation_text.color = TEXT
# Check boxes
style.l_checkbox = Style(style.l_button)
style.l_checkbox.left_padding = INDENT
def checkbox(full, color):
if full:
return im.Twocolor("checkbox_full.png", color, color, yalign=0.5)
else:
return im.Twocolor("checkbox_empty.png", color, color, yalign=0.5)
style.l_checkbox.background = checkbox(False, IDLE)
style.l_checkbox.hover_background = checkbox(False, HOVER)
style.l_checkbox.selected_idle_background = checkbox(True, IDLE)
style.l_checkbox.selected_hover_background = checkbox(True, HOVER)
style.l_checkbox.insensitive_background = checkbox(False, DISABLED)
style.l_checkbox_text = Style(style.l_button_text)
style.l_checkbox_text.selected_font = LIGHT
# A normal button that lines up with checkboxes.
style.l_nonbox = Style(style.l_button)
style.l_nonbox.xpadding = INDENT
style.l_nonbox_text = Style(style.l_button_text)
style.l_nonbox_text.selected_font = LIGHT
# A progress bar and its frame.
style.l_progress_frame = Style(style.l_default)
style.l_progress_frame.background = Frame(PATTERN, 0, 0, tile=True)
style.l_progress_frame.ypadding = 5
style.l_progress_bar = Style(style.l_default)
style.l_progress_bar.left_bar = REVERSE_IDLE
style.l_progress_bar.right_bar = Null()
style.l_progress_bar.ymaximum = 24
# The projects window.
style.l_projects = Style(style.l_default)
style.l_projects.background = PROJECTS_WINDOW
style.hyperlink_text.size = 18
style.hyperlink_text.font = LIGHT
style.hyperlink_text.color = IDLE
style.hyperlink_text.hover_color = HOVER
-44
View File
@@ -1,44 +0,0 @@
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
class FileTail(object):
def __init__(self, filename, lines=8):
self.filename = filename
self.text = ""
self.lines = lines
def update(self):
try:
with open(self.filename) as f:
text = f.read()
text = text.strip()
text = text.split("\n")
newtext = [ ]
for l in text:
if "\r" in l:
_head, _sep, l = l.rpartition("\r")
while l:
newtext.append(l[:100])
l = l[100:]
text = newtext
text = text[-self.lines:]
text = "\n".join(text)
if text != self.text:
self.text = text
renpy.restart_interaction()
except:
pass
-586
View File
@@ -1,586 +0,0 @@
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python in theme_data:
def __PerformScreenOperations(lines, file_picker_rows=5, file_picker_cols=2):
import re
x = 0
correct_section = False
while x < len(lines):
l = lines[x]
m = re.match(r'^screen\s+\w+\s*:\s*$', l)
if m:
correct_section = False
m = re.match(r'^screen\s+file_picker\s*:\s*$', l)
if m:
correct_section = True
if correct_section:
m = re.match(r'^\s+\$\s*columns\s*=\s*(\d+)\s*$', l)
if m:
l = l.replace(str(m.group(1)), str(file_picker_cols))
m = re.match(r'^\s+\$\s*rows\s*=\s*(\d+)\s*$', l)
if m:
l = l.replace(str(m.group(1)), str(file_picker_rows))
lines[x] = l
x = x + 1
return lines
def roundrect_screen_ops(lines):
return __PerformScreenOperations(lines)
def awt_screen_ops(lines):
return __PerformScreenOperations(lines, file_picker_rows=3)
# theme name -> (color scheme name -> code that implements it)
THEME = { }
# The set of theme functions.
THEME_FUNCTIONS = set()
# theme name -> function name to call to munge screens.rpy as appropriate
# for that theme.
THEME_SCREEN_OPERATIONS = { }
# Color schemes that work (technically - some are eye-melting) with the
# roundrect-style themes.
ROUNDRECT_SCHEMES = {
'Basic Blue': {'disabled': '#404040',
'disabled_text': '#c8c8c8',
'frame': '#6496c8',
'gm_root': '#dcebff',
'label': '#ffffff',
'mm_root': '#dcebff',
'widget': '#003c78',
'widget_hover': '#0050a0',
'widget_selected': '#ffffc8',
'widget_text': '#c8ffff'},
'Bloody Mary': {'disabled': '#400000',
'disabled_text': '#260000',
'frame': '#400808',
'gm_root': '#000000',
'label': '#ffffff',
'mm_root': '#000000',
'widget': '#000000',
'widget_hover': '#830000',
'widget_selected': '#ffffff',
'widget_text': '#C2C2C2'},
'Colorblind': {'disabled': '#898989',
'disabled_text': '#666666',
'frame': '#252525',
'gm_root': '#393939',
'label': '#c2c2c2',
'mm_root': '#393939',
'widget': '#898989',
'widget_hover': '#464646',
'widget_selected': '#F2F2F2',
'widget_text': '#CCCCCC'},
'Cotton Candy': {'disabled': '#C8AFA1',
'disabled_text': '#E1D4C9',
'frame': '#FCF5F2',
'gm_root': '#D0B4BA',
'label': '#805C40',
'mm_root': '#D0B4BA',
'widget': '#ECC7D0',
'widget_hover': '#E1D4C9',
'widget_selected': '#805C40',
'widget_text': '#805C40'},
'Creamsicle': {'disabled': '#FFECBF',
'disabled_text': '#ffffff',
'frame': '#FFECBF',
'gm_root': '#FDF5E3',
'label': '#502F13',
'mm_root': '#FDF5E3',
'widget': '#D96B00',
'widget_hover': '#FD9B1C',
'widget_selected': '#ffffff',
'widget_text': '#FCE6B1'},
'Dramatic Flesh': {'disabled': '#ab6038',
'disabled_text': '#BF7C51',
'frame': '#49271b',
'gm_root': '#2a201f',
'label': '#ffffff',
'mm_root': '#2a201f',
'widget': '#BF7C51',
'widget_hover': '#dda570',
'widget_selected': '#ffffff',
'widget_text': '#E5DFDF'},
'Easter Baby': {'disabled': '#DDE9FF',
'disabled_text': '#A6AFBF',
'frame': '#CCF8DC',
'gm_root': '#FBF9DF',
'label': '#698071',
'mm_root': '#FBF9DF',
'widget': '#F5D4EE',
'widget_hover': '#F0DDFF',
'widget_selected': '#000000',
'widget_text': '#698071'},
'Favorite Jeans': {'disabled': '#919994',
'disabled_text': '#B6BFB9',
'frame': '#6f7571',
'gm_root': '#b0b8ba',
'label': '#ffffff',
'mm_root': '#b0b8ba',
'widget': '#8699a7',
'widget_hover': '#9eb1ad',
'widget_selected': '#ffffff',
'widget_text': '#dcdfd6'},
'Fine China': {'disabled': '#ADB9CC',
'disabled_text': '#DFBA14',
'frame': '#ADB9CC',
'gm_root': '#F7F7FA',
'label': '#39435E',
'mm_root': '#F7F7FA',
'widget': '#6A7183',
'widget_hover': '#1A2B47',
'widget_selected': '#E3E3E4',
'widget_text': '#C9C9CB'},
'First Valentines': {'disabled': '#F8F2D0',
'disabled_text': '#BFA1A1',
'frame': '#F8F2D0',
'gm_root': '#D98989',
'label': '#5D1010',
'mm_root': '#D98989',
'widget': '#F09898',
'widget_hover': '#D6C5BB',
'widget_selected': '#B31E1E',
'widget_text': '#593131'},
'Ice Queen': {'disabled': '#F0F2F2',
'disabled_text': '#FBFBFB',
'frame': '#ffffff',
'gm_root': '#E6E6E6',
'label': '#D9D9D9',
'mm_root': '#E6E6E6',
'widget': '#D9D9D9',
'widget_hover': '#F0F2F2',
'widget_selected': '#737373',
'widget_text': '#ffffff'},
'Mocha Latte': {'disabled': '#614D3A',
'disabled_text': '#80654D',
'frame': '#926841',
'gm_root': '#1A140E',
'label': '#F1EBE5',
'mm_root': '#1A140E',
'widget': '#4D3B29',
'widget_hover': '#996E45',
'widget_selected': '#ffffff',
'widget_text': '#B99D83'},
'Muted Horror': {'disabled': '#73735C',
'disabled_text': '#8C8C70',
'frame': '#555544',
'gm_root': '#1A0001',
'label': '#1A0001',
'mm_root': '#1A0001',
'widget': '#777777',
'widget_hover': '#73735C',
'widget_selected': '#000000',
'widget_text': '#404033'},
'Old Polaroid': {'disabled': '#A89E7D',
'disabled_text': '#CCC097',
'frame': '#49403E',
'gm_root': '#A84A3E',
'label': '#ffffff',
'mm_root': '#A84A3E',
'widget': '#A89E7D',
'widget_hover': '#8DB6B9',
'widget_selected': '#ffffff',
'widget_text': '#49403E'},
'Really Red': {'disabled': '#404040',
'disabled_text': '#c8c8c8',
'frame': '#e17373',
'gm_root': '#ffd0d0',
'label': '#ffffff',
'mm_root': '#ffd0d0',
'widget': '#963232',
'widget_hover': '#c83232',
'widget_selected': '#ffffc8',
'widget_text': '#ffffff'},
'Summer Sky': {'disabled': '#6074BF',
'disabled_text': '#7383BF',
'frame': '#6074BF',
'gm_root': '#B4CDD4',
'label': '#94C7D4',
'mm_root': '#B4CDD4',
'widget': '#F2E6AA',
'widget_hover': '#FCFCA4',
'widget_selected': '#1A5766',
'widget_text': '#7DA8B3'},
'Swamp Critter': {'disabled': '#A2521D',
'disabled_text': '#753D00',
'frame': '#797C1C',
'gm_root': '#B09D5A',
'label': '#ffffff',
'mm_root': '#B09B4F',
'widget': '#753D00',
'widget_hover': '#B19A48',
'widget_selected': '#ffffff',
'widget_text': '#CCCAC2'},
'Urban Sprawl': {'disabled': '#8F0000',
'disabled_text': '#333333',
'frame': '#8F0000',
'gm_root': '#000000',
'label': '#ffffff',
'mm_root': '#000000',
'widget': '#333333',
'widget_hover': '#000000',
'widget_selected': '#ffffff',
'widget_text': '#6C8A2F'},
'Victorian Gingerbread': {'disabled': '#7A674F',
'disabled_text': '#664F33',
'frame': '#BF8A73',
'gm_root': '#695640',
'label': '#F2EDC4',
'mm_root': '#695640',
'widget': '#7A674F',
'widget_hover': '#BDA77D',
'widget_selected': '#FDFBEE',
'widget_text': '#F2EDC4'},
'Watermelon Pie': {'disabled': '#FABF46',
'disabled_text': '#FFE06D',
'frame': '#C3CD91',
'gm_root': '#F7F7C5',
'label': '#FCFCD7',
'mm_root': '#F7F7C5',
'widget': '#FFE06D',
'widget_hover': '#E38A4F',
'widget_selected': '#996600',
'widget_text': '#FAA700'},
'White Chocolate': {'disabled': '#614D3A',
'disabled_text': '#80654D',
'frame': '#926841',
'gm_root': '#FBF9EA',
'label': '#F1EBE5',
'mm_root': '#FBF9EA',
'widget': '#33271C',
'widget_hover': '#ECE7C4',
'widget_selected': '#ffffff',
'widget_text': '#B99D83'},
'Winter Mint': {'disabled': '#426143',
'disabled_text': '#819981',
'frame': '#245536',
'gm_root': '#e5f1e5',
'label': '#ffffff',
'mm_root': '#e5f1e5',
'widget': '#7AA27B',
'widget_hover': '#A3C7A3',
'widget_selected': '#ffffff',
'widget_text': '#CDE0CE'},
'Mint Chocolate': {'disabled': '#ffe69c',
'disabled_text': '#ddbc7e',
'frame': '#8ab395',
'gm_root': '#7a4229',
'label': '#7a4229',
'mm_root': '#7a4229',
'widget': '#ffe69c',
'widget_hover': '#f5c153',
'widget_selected': '#7a4229',
'widget_text': '#b5743a'},
'Parachute Pants': {'disabled': '#53c7bb',
'disabled_text': '#97d7bd',
'frame': '#457b9f',
'gm_root': '#37397f',
'label': '#cce2ae',
'mm_root': '#37397f',
'widget': '#53c7bb',
'widget_hover': '#97d7bd',
'widget_selected': '#37397f',
'widget_text': '#457b9f'},
'Strawberry Orchard': {'disabled': '#b3c292',
'disabled_text': '#525748',
'frame': '#d8ebae',
'gm_root': '#e7f3cb',
'label': '#525748',
'mm_root': '#e7f3cb',
'widget': '#525748',
'widget_hover': '#f45c73',
'widget_selected': '#ffce95',
'widget_text': '#e7f3cb'},
'Grape Jelly': {'disabled': '#81859a',
'disabled_text': '#5e2862',
'frame': '#8ea9b0',
'gm_root': '#5e2862',
'label': '#ffffff',
'mm_root': '#5e2862',
'widget': '#c45693',
'widget_hover': '#5e2862',
'widget_selected': '#e59eae',
'widget_text': '#ffffff'},
'Dreamscape': {'disabled': '#966077',
'disabled_text': '#c75f77',
'frame': '#836177',
'gm_root': '#c75f77',
'label': '#fefab6',
'mm_root': '#c75f77',
'widget': '#77a493',
'widget_hover': '#8accb3',
'widget_selected': '#c75f77',
'widget_text': '#ffffff'},
'Unrequited Love': {'disabled': '#dbe4dd',
'disabled_text': '#bd9ca9',
'frame': '#fffeed',
'gm_root': '#b38698',
'label': '#23000e',
'mm_root': '#b38698',
'widget': '#7fa1b3',
'widget_hover': '#b38698',
'widget_selected': '#fffeed',
'widget_text': '#ffffff'},
'Watermelon': {'disabled': '#f9cdad',
'disabled_text': '#fc9d9a',
'frame': '#f9cdad',
'gm_root': '#83af9b',
'label': '#fe4365',
'mm_root': '#83af9b',
'widget': '#fc9d9a',
'widget_hover': '#fe4365',
'widget_selected': '#e5fcc2',
'widget_text': '#ffffff'},
'City Lights': {'disabled': '#638e89',
'disabled_text': '#594f4f',
'frame': '#547980',
'gm_root': '#594f4f',
'label': '#e5fcc2',
'mm_root': '#594f4f',
'widget': '#45ada8',
'widget_hover': '#2e5860',
'widget_selected': '#e5fcc2',
'widget_text': '#9de0ad'},
'Vampire Bite': {'disabled': '#971140',
'disabled_text': '#bd4b40',
'frame': '#bd1550',
'gm_root': '#490a3d',
'label': '#f8ca00',
'mm_root': '#490a3d',
'widget': '#e97f02',
'widget_hover': '#f5a240',
'widget_selected': '#490a3d',
'widget_text': '#bd1550'},
'Underground Rave': {'disabled': '#57cdff',
'disabled_text': '#717be5',
'frame': '#04b4ff',
'gm_root': '#cd249b',
'label': '#000000',
'mm_root': '#cd249b',
'widget': '#8833ce',
'widget_hover': '#cd249b',
'widget_selected': '#b6d754',
'widget_text': '#000000'},
'Tree Frog': {'disabled': '#ffffff',
'disabled_text': '#1c140d',
'frame': '#cbe86b',
'gm_root': '#ffffff',
'label': '#1c140d',
'mm_root': '#ffffff',
'widget': '#1c140d',
'widget_hover': '#86827e',
'widget_selected': '#f2e9e1',
'widget_text': '#cbe86b'},
'Sun Kissed': {'disabled': '#ffffff',
'disabled_text': '#ec4c51',
'frame': '#f0874d',
'gm_root': '#f8c821',
'label': '#ffffff',
'mm_root': '#f8c821',
'widget': '#ec4c51',
'widget_hover': '#dc454a',
'widget_selected': '#f8c821',
'widget_text': '#ffffff'},
'Vintage Faded': {'disabled': '#b17d6f',
'disabled_text': '#8c4e3d',
'frame': '#ab7464',
'gm_root': '#935844',
'label': '#f7d3c8',
'mm_root': '#935844',
'widget': '#8c4e3d',
'widget_hover': '#734032',
'widget_selected': '#fcf5ed',
'widget_text': '#e2b9ad'},
'Vintage': {'disabled': '#883e35',
'disabled_text': '#b86258',
'frame': '#b86258',
'gm_root': '#a24637',
'label': '#ffffff',
'mm_root': '#a24637',
'widget': '#6c2921',
'widget_hover': '#832f26',
'widget_selected': '#ffc7c0',
'widget_text': '#fff4eb'},
'Earth Tones': {'disabled': '#12612f',
'disabled_text': '#2c6e44',
'frame': '#00551f',
'gm_root': '#6b4a27',
'label': '#ffffff',
'mm_root': '#568153',
'widget': '#ad8c31',
'widget_hover': '#568153',
'widget_selected': '#f2edc4',
'widget_text': '#ffffff'},
'Kindergarten': {'disabled': '#1ca4b2',
'disabled_text': '#22d5b3',
'frame': '#22d5b3',
'gm_root': '#ffeca6',
'label': '#ffffff',
'mm_root': '#ffeca6',
'widget': '#1781b1',
'widget_hover': '#12678e',
'widget_selected': '#f2edc4',
'widget_text': '#fdfbee'},
'Phone Operator': {'disabled': '#929292',
'disabled_text': '#ababab',
'frame': '#d2d2d2',
'gm_root': '#59667a',
'label': '#343e4d',
'mm_root': '#59667a',
'widget': '#59667a',
'widget_hover': '#343e4d',
'widget_selected': '#bed4f6',
'widget_text': '#ffffff'},
}
ROUNDRECT_VARIANTS = [
("Roundrect", "roundrect"),
("Bordered", "bordered"),
("Diamond", "diamond"),
("Regal", "regal"),
("Austen", "austen"),
("TV", "tv"),
("3D", "threeD"),
("Glow", "glow"),
("Marker", "marker"),
("Crayon", "crayon"),
]
ROUNDRECT_CODE = """theme.%(function)s(
## Theme: %(theme)s
## Color scheme: %(scheme)s
## The color of an idle widget face.
widget = "%(widget)s",
## The color of a focused widget face.
widget_hover = "%(widget_hover)s",
## The color of the text in a widget.
widget_text = "%(widget_text)s",
## The color of the text in a selected widget. (For
## example, the current value of a preference.)
widget_selected = "%(widget_selected)s",
## The color of a disabled widget face.
disabled = "%(disabled)s",
## The color of disabled widget text.
disabled_text = "%(disabled_text)s",
## The color of informational labels.
label = "%(label)s",
## The color of a frame containing widgets.
frame = "%(frame)s",
## The background of the main menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
mm_root = "%(mm_root)s",
## The background of the game menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
gm_root = "%(gm_root)s",
## If this is True, the in-game window is rounded. If False,
## the in-game window is square.
rounded_window = False,
## And we're done with the theme. The theme will customize
## various styles, so if we want to change them, we should
## do so below.
)"""
for theme, function in ROUNDRECT_VARIANTS:
THEME[theme] = { }
THEME_FUNCTIONS.add(function)
THEME_SCREEN_OPERATIONS[theme] = roundrect_screen_ops
for scheme, colors in ROUNDRECT_SCHEMES.iteritems():
subs = dict(colors)
subs["function"] = function
subs["theme"] = theme
subs["scheme"] = scheme
THEME[theme][scheme] = ROUNDRECT_CODE % (subs)
AWT_CODE = """theme.a_white_tulip(
## Theme: A White Tulip
## Scheme %(scheme)s
## The color of an idle widget face.
widget = "%(widget)s",
## The color of a focused widget face.
widget_hover = "%(widget_hover)s",
## The color of the text in a selected widget. (For
## example, the current value of a preference.)
widget_selected = "%(widget_selected)s",
## The color of a disabled widget face.
disabled = "%(disabled)s",
## The color of a frame containing widgets.
frame = "%(frame)s",
## The background of the main menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
mm_root = "%(mm_root)s",
## The background of the game menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
gm_root = "%(gm_root)s",
## And we're done with the theme. The theme will customize
## various styles, so if we want to change them, we should
## do so below.
)"""
THEME["A White Tulip"] = { }
THEME_FUNCTIONS.add("a_white_tulip")
THEME_SCREEN_OPERATIONS["A White Tulip"] = awt_screen_ops
for scheme, colors in ROUNDRECT_SCHEMES.iteritems():
subs = dict(colors)
subs["scheme"] = scheme
THEME["A White Tulip"][scheme] = AWT_CODE % (subs)
THEME["A White Tulip"]["A White Tulip"] = AWT_CODE % dict(
scheme = "A White Tulip",
widget = "#c1c6d3",
widget_hover = "#d7dbe5",
widget_text = "#6b6b6b",
widget_selected = "#c1c6d3",
disabled = "#b4b4b4",
disabled_text = "#6b6b6b",
label = "#6b6b6b",
frame = "#9391c9",
mm_root = "#ffffff",
gm_root = "#ffffff",
)
-26
View File
@@ -1,26 +0,0 @@
#!/usr/bin/env python
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This is used on Linux and Mac to prompt the user for the projects
# directory.
import sys
# Python3 and Python2-style imports.
try:
from tkinter import Tk
from tkinter.filedialog import askdirectory
except ImportError:
from Tkinter import Tk
from tkFileDialog import askdirectory
# Create the TK canvas.
if __name__ == "__main__":
root = Tk()
root.withdraw()
result = askdirectory(initialdir=sys.argv[1], parent=root, title="Select Ren'Py Projects Directory")
sys.stdout.write(result)
-17
View File
@@ -1,17 +0,0 @@
MTLc3m.ttf is destributed under Apache License 2.0.
--------------------------------
Copyright (C) 2008 The Android Open Source Project
Copyright (C) 2010 MOTOYA CO.,LTD.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Binary file not shown.
-15
View File
@@ -1,15 +0,0 @@
translate japanese strings:
# game/about.rpy:21
old "[version!q]"
new "[version!q]"
# game/about.rpy:25
old "View license"
new "ライセンス"
# game/about.rpy:27
old "Back"
new "戻る"
-23
View File
@@ -1,23 +0,0 @@
translate japanese strings:
# game/add_file.rpy:7
old "FILENAME"
new "ファイル名"
# game/add_file.rpy:7
old "Enter the name of the script file to create."
new "作成するスクリプトファイル名を入力してください。"
# game/add_file.rpy:10
old "The filename must have the .rpy extension."
new "ファイル名は拡張子 .rpy を持つ必要があります。"
# game/add_file.rpy:18
old "The file already exists."
new "ファイルは既に存在します。"
# game/add_file.rpy:21
old "# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n"
new "# Ren'Pyは .rpy で終わるすべてのスクリプトファイルを自動的にロードします。このファイルを使用するためにはラベルを定義し、他のファイルからそこにジャンプしてください。\n"
-107
View File
@@ -1,107 +0,0 @@
translate japanese strings:
# game/android.rpy:12
old "To build Android packages, please download RAPT (from {a=http://www.renpy.org/dl/android}here{/a}), unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
new "Androidパッケージをビルドするためには{a=http://www.renpy.org/dl/android}RAPT{/a}をダウンロードして解凍し、Ren'Py ディレクトリーに配置してからランチャーを再起動してください。"
# game/android.rpy:13
old "RAPT has been installed, but you'll need to install the Android SDK before you can build Android packages. Choose Install SDK to do this."
new "RAPT はインストールされましたが、Androidパッケージをビルドする前に Android SDK もインストールする必要があります。このためにSDKをインストールしてください。"
# game/android.rpy:14
old "RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore."
new "RAPT はインストールされましたが、キーが設定されていません。新しいキーを作成するか、android.keystore を復帰させてください。"
# game/android.rpy:15
old "The current project has not been configured. Use \"Configure\" to configure it before building."
new "現在のプロジェクトは設定されていません。「設定」を利用してビルド前に設定してください。"
# game/android.rpy:16
old "Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device."
new "「ビルド」を選択して現在のプロジェクトをビルドするか、Android デバイスを接続して「ビルド & インストール」を選択し、ビルド後そのデバイスにインストールしてください。"
# game/android.rpy:18
old "Attempts to emulate an Android phone.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android Phoneをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみです。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
# game/android.rpy:19
old "Attempts to emulate an Android tablet.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android tabletをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみです。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
# game/android.rpy:20
old "Attempts to emulate an OUYA console.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android OUYAをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
# game/android.rpy:22
old "Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package."
new "Android SDKをダウンロード後インストールします。任意でサインに必要なキーを生成します。"
# game/android.rpy:23
old "Configures the package name, version, and other information about this project."
new "このプロジェクトについてパッケージ名、バージョン、その他の情報を設定してください。"
# game/android.rpy:24
old "Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details."
new "Google Play key を含むファイルをエディターで開いてください。\n\nこれはアプリが拡張APKを使用する場合のみ必要となります。詳細はドキュメントを参照してください。"
# game/android.rpy:25
old "Builds the Android package."
new "Androidパッケージをビルドします。"
# game/android.rpy:26
old "Builds the Android package, and installs it on an Android device connected to your computer."
new "Androidパッケージをビルドし、コンピューターに接続されたAndroidデバイスにインストールします。"
# game/android.rpy:142
old "{a=%s}%s{/a}"
new "{a=%s}%s{/a}"
# game/android.rpy:151
old "QUESTION"
new "質問"
# game/android.rpy:351
old "Android: [project.current.name!q]"
new "Android: [project.current.name!q]"
# game/android.rpy:371
old "Emulation:"
new "エミュレーター:"
# game/android.rpy:379
old "Phone"
new "Phone"
# game/android.rpy:383
old "Tablet"
new "Tablet"
# game/android.rpy:387
old "Television / OUYA"
new "Television / OUYA"
# game/android.rpy:399
old "Build:"
new "ビルド:"
# game/android.rpy:407
old "Install SDK & Create Keys"
new "SDKのインストール & キーの作成"
# game/android.rpy:411
old "Configure"
new "設定"
# game/android.rpy:415
old "Build Package"
new "パッケージのビルド"
# game/android.rpy:419
old "Build & Install"
new "ビルド & インストール"
# game/android.rpy:13
old "A 32-bit Java Development Kit is required to build Android packages on Windows. The JDK is different from the JRE, so it's possible you have Java without having the JDK.\n\nPlease {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}download and install the JDK{/a}, then restart the Ren'Py launcher."
new "Windowsでは、Androidパッケージのビルドに32-bitのJava開発キットが必要です。JDKはJREとは異なるため、JDKが無くてもJavaが利用できます。\n\n{a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}JDKのダウンロードとインストール{/a}を行い、Ren'Pyランチャーを再起動して下さい。"
@@ -1,43 +0,0 @@
translate japanese strings:
# game/choose_theme.rpy:274
old "Could not change the theme. Perhaps options.rpy was changed too much."
new "テーマを変更出来ません。 options.rpy が変更されすぎているかもしれません。"
# game/choose_theme.rpy:332
old "Display"
new "Display"
# game/choose_theme.rpy:333
old "Window"
new "Window"
# game/choose_theme.rpy:334
old "Fullscreen"
new "Fullscreen"
# game/choose_theme.rpy:335
old "Planetarium"
new "Planetarium"
# game/choose_theme.rpy:342
old "Sound Volume"
new "Sound Volume"
# game/choose_theme.rpy:376
old "Choose Theme"
new "Choose Theme"
# game/choose_theme.rpy:389
old "Theme"
new "テーマ"
# game/choose_theme.rpy:413
old "Color Scheme"
new "カラースキーム"
# game/choose_theme.rpy:444
old "Continue"
new "続行"
-312
View File
@@ -1,312 +0,0 @@
translate japanese strings:
# renpy/common/00action_file.rpy:124
old "%b %d, %H:%M"
new "%m月%d日, %H:%M"
# renpy/common/00action_file.rpy:587
old "Quick save complete."
new "クイックセーブ完了。"
translate japanese strings:
# renpy/common/00gallery.rpy:521
old "Image [index] of [count] locked."
new "画像 [index] / [count] はロックされています。"
# renpy/common/00gallery.rpy:539
old "prev"
new "前へ"
# renpy/common/00gallery.rpy:540
old "next"
new "次へ"
# renpy/common/00gallery.rpy:541
old "slideshow"
new "スライドショー"
# renpy/common/00gallery.rpy:542
old "return"
new "戻る"
translate japanese strings:
# renpy/common/00gltest.rpy:50
old "Graphics Acceleration"
new "グラフィック・アクセラレーション"
# renpy/common/00gltest.rpy:54
old "Automatically Choose"
new "自動選択"
# renpy/common/00gltest.rpy:59
old "Force Angle/DirectX Renderer"
new "Angle/DirectX による描画を強制"
# renpy/common/00gltest.rpy:63
old "Force OpenGL Renderer"
new "OpenGL による描画を強制"
# renpy/common/00gltest.rpy:67
old "Force Software Renderer"
new "ソフトウェアによる描画を強制"
# renpy/common/00gltest.rpy:73
old "Changes will take effect the next time this program is run."
new "変更は、次にプログラムを起動した時に反映されます。"
# renpy/common/00gltest.rpy:77
old "Quit"
new "終了"
# renpy/common/00gltest.rpy:82
old "Return"
new "戻る"
# renpy/common/00gltest.rpy:112
old "Performance Warning"
new "パフォーマンスに関する注意"
# renpy/common/00gltest.rpy:117
old "This computer is using software rendering."
new "このコンピュータはソフトウェアレンダリングを使用しています。"
# renpy/common/00gltest.rpy:119
old "This computer is not using shaders."
new "このコンピューターはシェーダーを使用していません。"
# renpy/common/00gltest.rpy:121
old "This computer is displaying graphics slowly."
new "このコンピューターは描画速度が遅いです。"
# renpy/common/00gltest.rpy:123
old "This computer has a problem displaying graphics: [problem]."
new "このコンピューターはグラフィックスの表示に問題があります: [problem]。"
# renpy/common/00gltest.rpy:128
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
new "グラフィックドライバーは古いか、あるいは正常に動作していません。これはグラフィックスの表示が遅くなったり、正常に表示されない原因となります。DirectXをアップデートするとこの問題を解決できます。"
# renpy/common/00gltest.rpy:130
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
new "グラフィックドライバーは古いか、あるいは正常に動作していません。これはグラフィックスの表示が遅くなったり、正常に表示されない原因となります。"
# renpy/common/00gltest.rpy:135
old "Update DirectX"
new "DirectXのアップデート"
# renpy/common/00gltest.rpy:141
old "Continue, Show this warning again"
new "今後も、この注意を表示する"
# renpy/common/00gltest.rpy:145
old "Continue, Don't show warning again"
new "今後は、この注意を表示しない"
# renpy/common/00gltest.rpy:171
old "Updating DirectX."
new "DirectXのアップデート中"
# renpy/common/00gltest.rpy:175
old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
new "DirectXウェブセットアップが開始されました。タスクバーに最小化された状態で開始したので、画面に従ってDirectXをインストールして下さい。"
# renpy/common/00gltest.rpy:179
old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
new "{b}メモ:{/b} MicrosoftのDirectXウェブセットアッププログラムは、デフォルトでBingツールバーをインストールします。このツールバーが不要な場合は、対応したチェックボックスを解除して下さい。"
# renpy/common/00gltest.rpy:183
old "When setup finishes, please click below to restart this program."
new "セットアップが完了したら、以下をクリックしてプログラムを再起動して下さい。"
# renpy/common/00gltest.rpy:185
old "Restart"
new "再起動"
translate japanese strings:
# renpy/common/00keymap.rpy:168
old "Saved screenshot as %s."
new "スクリーンショットを %s に保存しました。"
translate japanese strings:
# renpy/common/00layout.rpy:421
old "Are you sure?"
new "本当にいいですか?"
# renpy/common/00layout.rpy:422
old "Are you sure you want to delete this save?"
new "この保存データを本当に削除しますか?"
# renpy/common/00layout.rpy:423
old "Are you sure you want to overwrite your save?"
new "本当に保存データを上書きしますか?"
# renpy/common/00layout.rpy:424
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
new "読み込みによって未保存のゲームが失われます。\n本当に読み込みますか?"
# renpy/common/00layout.rpy:425
old "Are you sure you want to quit?"
new "本当にゲームを終了しますか?"
# renpy/common/00layout.rpy:426
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
new "本当にメインメニューに戻りますか?\nこれによって未保存のゲームが失われます。"
# renpy/common/00layout.rpy:427
old "Are you sure you want to begin skipping?"
new "本当にスキップモードを開始しますか?"
# renpy/common/00layout.rpy:428
old "Are you sure you want to skip to the next choice?"
new "本当に次の選択肢までスキップしますか?"
# renpy/common/00layout.rpy:429
old "Are you sure you want to skip to unseen dialogue or the next choice?"
new "本当に未読の会話、もしくは次の選択肢までスキップしますか?"
translate japanese strings:
# renpy/common/00library.rpy:77
old "Skip Mode"
new "スキップモード"
# renpy/common/00library.rpy:80
old "Fast Skip Mode"
new "高速スキップモード"
translate japanese strings:
# renpy/common/00updater.rpy:1258
old "Updater"
new "アップデーター"
# renpy/common/00updater.rpy:1267
old "This program is up to date."
new "このプログラムは最新版です。"
# renpy/common/00updater.rpy:1269
old "[u.version] is available. Do you want to install it?"
new "[u.version] が利用可能です。インストールしますか?"
# renpy/common/00updater.rpy:1271
old "Preparing to download the updates."
new "アップデートをダウンロードする準備をしています。"
# renpy/common/00updater.rpy:1273
old "Downloading the updates."
new "アップデートをダウンロードしています。"
# renpy/common/00updater.rpy:1275
old "Unpacking the updates."
new "アップデートを展開しています。"
# renpy/common/00updater.rpy:1279
old "The updates have been installed. The program will restart."
new "アップデートがインストールされました。プログラムを再起動します。"
# renpy/common/00updater.rpy:1281
old "The updates have been installed."
new "アップデートがインストールされました。"
# renpy/common/00updater.rpy:1283
old "The updates were cancelled."
new "アップデートがキャンセルされました。"
translate japanese strings:
# renpy/common/_compat/gamemenu.rpym:180
old "Empty Slot."
new "空のスロット"
# renpy/common/_compat/gamemenu.rpym:337
old "Previous"
new "前へ"
# renpy/common/_compat/gamemenu.rpym:344
old "Next"
new "次へ"
translate japanese strings:
# renpy/common/_compat/preferences.rpym:411
old "Joystick Mapping"
new "ジョイスティックのマッピング"
translate japanese strings:
# renpy/common/_errorhandling.rpym:408
old "An exception has occurred."
new "例外が発生しました。"
# renpy/common/_errorhandling.rpym:434
old "Rollback"
new "ロールバック"
# renpy/common/_errorhandling.rpym:436
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
new "一つ前へのロールバックを試み、セーブまたは他の選択肢を選ぶことを許可します。"
# renpy/common/_errorhandling.rpym:439
old "Ignore"
new "無視"
# renpy/common/_errorhandling.rpym:441
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
new "例外を無視し、ゲームの継続を許可します。この場合、付加的なエラーが発生する原因となることがあります。"
# renpy/common/_errorhandling.rpym:444
old "Reload"
new "再読み込み"
# renpy/common/_errorhandling.rpym:446
old "Reloads the game from disk, saving and restoring game state if possible."
new "ディスクからゲームを再読み込みし、可能であればゲームの保存と復元をします。"
# renpy/common/_errorhandling.rpym:448
old "Open Traceback"
new "トレースバックを開く"
# renpy/common/_errorhandling.rpym:450
old "Opens the traceback.txt file in a text editor."
new "テキストエディターで traceback.txt を開きます。"
# renpy/common/_errorhandling.rpym:456
old "Quits the game."
new "ゲームを終了します。"
# renpy/common/_errorhandling.rpym:483
old "Parsing the script failed."
new "スクリプトの変換に失敗しました。"
# renpy/common/_errorhandling.rpym:510
old "Open Parse Errors"
new "変換エラーを開く"
# renpy/common/_errorhandling.rpym:512
old "Opens the errors.txt file in a text editor."
new "テキストエディターで errors.txt を開きます。"
translate japanese strings:
# renpy/common/_layout/classic_load_save.rpym:152
old "a"
new "a"
# renpy/common/_layout/classic_load_save.rpym:161
old "q"
new "q"
-39
View File
@@ -1,39 +0,0 @@
translate japanese strings:
# game/distribute.rpy:335
old "Nothing to do."
new "何もしません。"
# game/distribute.rpy:339
old "Scanning project files..."
new "プロジェクトをスキャンしています…"
# game/distribute.rpy:346
old "Scanning Ren'Py files..."
new "Ren'Pyファイルをスキャンしています…"
# game/distribute.rpy:496
old "Archiving files..."
new "ファイルをアーカイブしています…"
# game/distribute.rpy:747
old "Writing the [variant] [format] package."
new "[variant] [format] パッケージを書き出しています。."
# game/distribute.rpy:760
old "Making the [variant] update zsync file."
new "[variant] のアップデート用 zsync ファイルを書き出しています。"
# game/distribute.rpy:856
old "Processed {b}[complete]{/b} of {b}[total]{/b} files."
new "{b}[total]{/b} 中 {b}[complete]{/b} ファイルが処理されました。"
# game/distribute.rpy:917
old "All packages have been built.\n\nDue to the presence of permission information, unpacking and repacking the Linux and Macintosh distributions on Windows is not supported."
new "すべてのパッケージがビルドされました。\n\nパーミッション情報のために、Windows上でのLinuxやMacintosh用の配布物の解凍、再圧縮はサポートされません。"
# game/distribute.rpy:358
old "No packages are selected, so there's nothing to do."
new "パッケージが選択されていないため、何もすることがありません。"
@@ -1,47 +0,0 @@
translate japanese strings:
# game/distribute_gui.rpy:139
old "Build Distributions: [project.current.name!q]"
new "配布物のビルド: [project.current.name!q]"
# game/distribute_gui.rpy:154
old "Directory Name:"
new "ディレクトリー名:"
# game/distribute_gui.rpy:158
old "Executable Name:"
new "実行ファイル名:"
# game/distribute_gui.rpy:167
old "Actions:"
new "アクション:"
# game/distribute_gui.rpy:175
old "Edit options.rpy"
new "options.rpy を編集"
# game/distribute_gui.rpy:176
old "Refresh"
new "更新"
# game/distribute_gui.rpy:193
old "Build Packages:"
new "パッケージをビルド"
# game/distribute_gui.rpy:208
old "Build Updates"
new "アップデートをビルド"
# game/distribute_gui.rpy:212
old "Build"
new "ビルド"
# game/distribute_gui.rpy:219
old "Errors were detected when running the project. Please ensure the project runs without errors before building distributions."
new "プロジェクトの実行時にエラーが検出されました。配布物をビルドする前にエラーなしでプロジェクトが実行するようにしてください。"
# game/distribute_gui.rpy:236
old "Your project does not contain build information. Would you like to add build information to the end of options.rpy?"
new "プロジェクトにビルド情報がありません。options.rpy の末尾にビルド情報を追加しますか?"
-58
View File
@@ -1,58 +0,0 @@
translate japanese strings:
# game/editor.rpy:120
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
new "{b}推奨{/b} スペルチュックのような開発目的のインターフェースや機能を簡単に使用可能なベータエディターです。Editraは現在中国、韓国、日本語の入力に必要な IME のサポートに欠陥があります。"
# game/editor.rpy:121
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
new "{b}推奨{/b} スペルチェックのような開発目的のインターフェースや機能を簡単に使用可能なベータエディターです。Editraは現在中国、韓国、日本語の入力に必要な IME のサポートに欠陥があります。LinuxではEditraはwxpythonを必要とします。"
# game/editor.rpy:137
old "This may have occured because wxPython is not installed on this system."
new "これはおそらくwxPythonがこのシステムにインストールされていないため発生しました。"
# game/editor.rpy:144
old "Up to 22 MB download required."
new "22MB までのダウンロードが必要です。"
# game/editor.rpy:157
old "1.8 MB download required."
new "1.8 MB のダウンロードが必要です。"
# game/editor.rpy:158
old "This may have occured because Java is not installed on this system."
new "これはおそらくJavaがこのシステムにインストールされていないため発生しました。"
# game/editor.rpy:327
old "An exception occured while launching the text editor:\n[exception!q]"
new "テキストエディターの選択中にエラーが発生しました:\n[exception!q]"
# game/editor.rpy:423
old "Select Editor"
new "エディターを選択"
# game/editor.rpy:438
old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
new "テキストエディタはRen'Pyスクリプトファイルを編集するためのプログラムです。ここではRen'Pyが使用するエディターを選択可能です。存在しなければエディターは自動的にダウンロードされインストールされます。"
# game/editor.rpy:460
old "Cancel"
new "キャンセル"
translate japanese strings:
# game/editor.rpy:155
old "A mature editor that requires Java."
new "Javaを必要とする成熟したエディターです。"
# game/editor.rpy:164
old "Invokes the editor your operating system has associated with .rpy files."
new "オペレーティングシステムで .rpy ファイルに関連づけたエディターを実行します。"
# game/editor.rpy:180
old "Prevents Ren'Py from opening a text editor."
new "Ren'Pyのテキストエディターの実行を停止します。"
-91
View File
@@ -1,91 +0,0 @@
translate japanese strings:
# game/front_page.rpy:67
old "refresh"
new "更新"
# game/front_page.rpy:94
old "+ Create New Project"
new "+ 新規プロジェクトの作成"
# game/front_page.rpy:106
old "Launch Project"
new "プロジェクトの起動"
# game/front_page.rpy:127
old "Tutorial"
new "Tutorial"
# game/front_page.rpy:128
old "The Question"
new "The Question"
# game/front_page.rpy:144
old "Active Project"
new "アクティブなプロジェクト"
# game/front_page.rpy:152
old "Open Directory"
new "ディレクトリーを開く"
# game/front_page.rpy:157
old "game"
new "game"
# game/front_page.rpy:158
old "base"
new "base"
# game/front_page.rpy:164
old "Edit File"
new "ファイル編集"
# game/front_page.rpy:172
old "All script files"
new "すべてのスクリプト"
# game/front_page.rpy:181
old "Navigate Script"
new "スクリプトのナビゲート"
# game/front_page.rpy:192
old "Check Script (Lint)"
new "スクリプトチェック(Lint)"
# game/front_page.rpy:193
old "Change Theme"
new "テーマ変更"
# game/front_page.rpy:194
old "Delete Persistent"
new "永続データ削除"
# game/front_page.rpy:202
old "Build Distributions"
new "配布物のビルド"
# game/front_page.rpy:204
old "Android"
new "Android"
# game/front_page.rpy:205
old "Generate Translations"
new "翻訳の生成"
# game/front_page.rpy:206
old "Extract Dialogue"
new "台詞の抽出"
# game/front_page.rpy:222
old "Checking script for potential problems..."
new "潜在的な問題のためにスクリプトをチェックしています…"
# game/front_page.rpy:237
old "Deleting persistent data..."
new "永続データを削除しています…"
# game/front_page.rpy:122
old "[p.name!q] (template)"
new "[p.name!q] (テンプレート)"
-83
View File
@@ -1,83 +0,0 @@
translate japanese strings:
# game/interface.rpy:89
old "Documentation"
new "ドキュメント"
# game/interface.rpy:90
old "Ren'Py Website"
new "Ren'Pyサイト"
# game/interface.rpy:91
old "Ren'Py Games List"
new "Ren'Pyゲームリスト"
# game/interface.rpy:92
old "About"
new "About"
# game/interface.rpy:99
old "update"
new "アップデート"
# game/interface.rpy:101
old "preferences"
new "設定"
# game/interface.rpy:102
old "quit"
new "終了"
# game/interface.rpy:174
old "Yes"
new "Yes"
# game/interface.rpy:176
old "No"
new "No"
# game/interface.rpy:211
old "Due to package format limitations, non-ASCII file and directory names are not allowed."
new "パッケージフォーマットの制限により、アスキーコード以外のファイル、ディレクトリー名は許可されません。"
# game/interface.rpy:213
old "[title]"
new "[title]"
# game/interface.rpy:299
old "ERROR"
new "エラー"
# game/interface.rpy:328
old "While [what!q], an error occured:"
new "[what!q] 中にエラーが発生しました。:"
# game/interface.rpy:329
old "[exception!q]"
new "[exception!q]"
# game/interface.rpy:347
old "Text input may not contain the {{ or [[ characters."
new "{{ または [[ はテキスト入力出来ません。"
# game/interface.rpy:352
old "File and directory names may not contain / or \\."
new "ファイル、ディレクトリーが / または \\. を含んでいるかもしれません。"
# game/interface.rpy:358
old "File and directory names must consist of ASCII characters."
new "ファイル、ディレクトリー名はアスキーコードの文字列で構成される必要があります。"
# game/interface.rpy:379
old "INFORMATION"
new "情報"
# game/interface.rpy:422
old "PROCESSING"
new "処理中"
# game/interface.rpy:452
old "CHOICE"
new "選択"
-67
View File
@@ -1,67 +0,0 @@
translate japanese strings:
# game/navigation.rpy:150
old "Navigate: [project.current.name]"
new "ナビゲーション: [project.current.name]"
# game/navigation.rpy:159
old "Order: "
new "並び順:"
# game/navigation.rpy:160
old "alphabetical"
new "アルファベット順"
# game/navigation.rpy:162
old "by-file"
new "ファイル順"
# game/navigation.rpy:164
old "natural"
new "natural"
# game/navigation.rpy:176
old "Category:"
new "カテゴリー:"
# game/navigation.rpy:178
old "files"
new "ファイル"
# game/navigation.rpy:179
old "labels"
new "ラベル"
# game/navigation.rpy:180
old "defines"
new "定義"
# game/navigation.rpy:181
old "transforms"
new "変換"
# game/navigation.rpy:182
old "screens"
new "スクリーン"
# game/navigation.rpy:183
old "callables"
new "関数"
# game/navigation.rpy:184
old "TODOs"
new "TODO"
# game/navigation.rpy:223
old "+ Add script file"
new "+ スクリプトファイルを追加する。"
# game/navigation.rpy:231
old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
new "TODOコメントは見つかりません。\n\n作成には \"# TODO\" をスクリプトに加えてください。"
# game/navigation.rpy:238
old "The list of names is empty."
new "名前のリストは空です。"
-31
View File
@@ -1,31 +0,0 @@
translate japanese strings:
# game/new_project.rpy:22
old "Choose Project Template"
new "テンプレートを選んでください"
# game/new_project.rpy:40
old "Please select a template to use for your new project. The template sets the default font and the user interface language. If your language is not supported, choose 'english'."
new "新しいプロジェクトで使用するテンプレートを選択してください。Ren'Pyはデフォルトのフォントとユーザーインターフェイスの言語を設定します。あなたの言語がサポートされていないなら 'english' を選択してください。"
# game/new_project.rpy:55
old "PROJECT NAME"
new "プロジェクト名"
# game/new_project.rpy:56
old "Please enter the name of your project:"
new "プロジェクト名を入力してください:"
# game/new_project.rpy:62
old "The project name may not be empty."
new "プロジェクト名が空です。"
# game/new_project.rpy:67
old "[project_name!q] already exists. Please choose a different project name."
new "[project_name!q] は既に存在します。違う名前を選択してください。"
# game/new_project.rpy:70
old "[project_dir!q] already exists. Please choose a different project name."
new "[project_dir!q] は既に存在します。違う名前を選択してください。"
-63
View File
@@ -1,63 +0,0 @@
translate japanese strings:
# game/preferences.rpy:40
old "Launcher Preferences"
new "ランチャー設定"
# game/preferences.rpy:61
old "Projects Directory:"
new "プロジェクトディレクトリー:"
# game/preferences.rpy:68
old "[persistent.projects_directory!q]"
new "[persistent.projects_directory!q]"
# game/preferences.rpy:70
old "Not Set"
new "未設定"
# game/preferences.rpy:84
old "Text Editor:"
new "テキストエディター:"
# game/preferences.rpy:106
old "Update Channel:"
new "アップデートチャンネル:"
# game/preferences.rpy:126
old "Navigation Options:"
new "ナビゲートオプション:"
# game/preferences.rpy:130
old "Include private names"
new "内部使用の名前を含める"
# game/preferences.rpy:131
old "Include library names"
new "本体の名前を含める"
# game/preferences.rpy:141
old "Launcher Options:"
new "ランチャー設定:"
# game/preferences.rpy:145
old "Hardware rendering"
new "ハードウェアレンダリング"
# game/preferences.rpy:148
old "Console output"
new "コンソール出力"
# game/preferences.rpy:169
old "Open launcher project"
new "ランチャーのプロジェクトを開く"
# game/preferences.rpy:183
old "Language:"
new "言語:"
# game/preferences.rpy:146
old "Show templates"
new "テンプレートの表示"
-27
View File
@@ -1,27 +0,0 @@
translate japanese strings:
# game/project.rpy:204
old "Ren'Py is scanning the project..."
new "Ren'Py プロジェクトをスキャンしています…"
# game/project.rpy:503
old "PROJECTS DIRECTORY"
new "プロジェクトディレクトリー"
# game/project.rpy:503
old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
new "プロジェクトディレクトリーを選択してください。\n{b}ディレクトリー選択画面がこのウィンドウの下に隠れている場合があります。{/b}"
# game/project.rpy:503
old "This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."
new "ランチャーはこのディレクトリーでプロジェクトをスキャンし、新しいプロジェクトを作成し、ビルドしたプロジェクトを出力します。"
# game/project.rpy:543
old "Ren'Py was unable to run python with tkinter to choose the projects directory."
new "Ren'Py はプロジェクトディレクトリーを選択するために tkinter でpythonを実行することは出来ません。"
# game/project.rpy:547
old "Ren'Py has set the projects directory to:"
new "Ren'Py は以下にプロジェクトディレクトリーを設定します:"
-15
View File
@@ -1,15 +0,0 @@
translate japanese python:
MTLC = "tl/japanese/MTLc3m.ttf"
style.l_default.font = MTLC
style.l_default.size = 16
style.l_button_text.selected_font = MTLC
style.l_button_text.selected_bold = True
style.l_link_text.font = MTLC
style.l_alternate_text.font = MTLC
style.l_navigation_button_text.font = MTLC
style.l_navigation_text.font = MTLC
style.l_navigation_text.bold = True
style.l_checkbox_text.selected_font = MTLC
style.l_nonbox_text.selected_font = MTLC
style.hyperlink_text.font = MTLC
make_style_backup()
@@ -1,35 +0,0 @@
translate japanese strings:
# game/translations.rpy:10
old "Create or Update Translations"
new "翻訳の作成または更新"
# game/translations.rpy:10
old "Please enter the name of the language for which you want to create or update translations."
new "翻訳を作成または更新したい言語名を入力してください。"
# game/translations.rpy:15
old "The language name can not be the empty string."
new "言語名は空の文字列であってはなりません。"
# game/translations.rpy:26
old "Ren'Py is generating translations...."
new "Ren'Pyは翻訳を生成しています…"
# game/translations.rpy:30
old "Ren'Py has finished generating [language] translations."
new "Ren'Pyは [language] の翻訳ファイルを生成しました。"
# game/translations.rpy:44
old "What format would you like for the extracted dialogue?"
new "どのフォーマットで台詞を抽出しますか?"
# game/translations.rpy:56
old "Ren'Py is extracting dialogue...."
new "Ren'Pyは台詞を抽出しています…"
# game/translations.rpy:60
old "Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[format] in the base directory."
new "Ren'Pyは台詞を抽出し終えました。抽出した台詞はベースディレクトリーの dialogue.[format] にあります。"
-87
View File
@@ -1,87 +0,0 @@
translate japanese strings:
# game/updater.rpy:54
old "Select Update Channel"
new "アップデートチャンネルを選択してください"
# game/updater.rpy:65
old "The update channel controls the version of Ren'Py the updater will download. Please select an update channel:"
new "アップデートチャンネルはアップデーターがダウンロードするRen'Pyのバージョンを制御します。アップデートチャンネルを選択してください。"
# game/updater.rpy:70
old "Release"
new "Release"
# game/updater.rpy:76
old "{b}Recommended.{/b} The version of Ren'Py that should be used in all newly-released games."
new "{b}推奨{/b} 全ての新しく配布されるゲームで使用されるべきRen'Pyのバージョンです。"
# game/updater.rpy:81
old "Prerelease"
new "Prerelease"
# game/updater.rpy:87
old "A preview of the next version of Ren'Py that can be used for testing and taking advantage of new features, but not for final releases of games."
new "テストや新機能利用のために使用されるRen'Pyの次期バージョンのプレビューですが、\nゲームの最終リリースには向きません。"
# game/updater.rpy:93
old "Experimental"
new "Experimental"
# game/updater.rpy:99
old "Experimental versions of Ren'Py. You shouldn't select this channel unless asked by a Ren'Py developer."
new "Ren'Pyの試験的なバージョンです。開発者に頼まれない限りこのバージョンを使用するべきではありません。"
# game/updater.rpy:119
old "An error has occured:"
new "エラーが発生しました:"
# game/updater.rpy:121
old "Checking for updates."
new "アップデートをチェックしています。"
# game/updater.rpy:123
old "Ren'Py is up to date."
new "Ren'Pyは最新です。"
# game/updater.rpy:125
old "[u.version] is now available. Do you want to install it?"
new "[u.version] が利用可能です。インストールしますか?"
# game/updater.rpy:127
old "Preparing to download the update."
new "アップデートのダウンロード準備をしています。"
# game/updater.rpy:129
old "Downloading the update."
new "アップデートをダウンロードしています。"
# game/updater.rpy:131
old "Unpacking the update."
new "アップデートを解凍しています。"
# game/updater.rpy:133
old "Finishing up."
new "完了しました。"
# game/updater.rpy:135
old "The update has been installed. Ren'Py will restart."
new "アップデートはインストールされました。Ren'Pyは再起動します。"
# game/updater.rpy:137
old "The update has been installed."
new "アップデートはインストールされました。"
# game/updater.rpy:139
old "The update was cancelled."
new "アップデートはキャンセルされました。"
# game/updater.rpy:156
old "Ren'Py Update"
new "Ren'Py アップデート"
# game/updater.rpy:162
old "Proceed"
new "続行"
-9
View File
@@ -1,9 +0,0 @@
translate spanish strings:
# game/about.rpy:21
old "[version!q]"
new "[version!q]"
# game/about.rpy:25
old "View license"
new "Ver licencia"
-21
View File
@@ -1,21 +0,0 @@
translate spanish strings:
# game/add_file.rpy:7
old "FILENAME"
new "Nombre del archivo"
# game/add_file.rpy:7
old "Enter the name of the script file to create."
new "Introduce el nombre del archivo de script para crearlo."
# game/add_file.rpy:10
old "The filename must have the .rpy extension."
new "El nombre del archivo debe tener la extensión .rpy."
# game/add_file.rpy:18
old "The file already exists."
new "El archivo ya existe."
# game/add_file.rpy:21
old "# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n"
new "# Ren'Py carga automaticamente todos los archivos que terminan en .rpy. Para usar este\n# archivo, defina una etiqueta y salte a el desde otro archivo\n"
-105
View File
@@ -1,105 +0,0 @@
translate spanish strings:
# game/android.rpy:13
old "A 32-bit Java Development Kit is required to build Android packages on Windows. The JDK is different from the JRE, so it's possible you have Java without having the JDK.\n\nPlease {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}download and install the JDK{/a}, then restart the Ren'Py launcher."
new "Se necesita Java Development Kit de 32-bit para construir paquetes de Android en Windows. El JDK es diferente al JRE, es posible que tenga Java sin tener el JDK.\n\nPor favor {a=http://www.oracle.com/technetwork/java/javase/downloads/index.html}descarga e instala el JDK{/a}, después, reinicia Ren'Py."
# game/android.rpy:14
old "To build Android packages, please download RAPT (from {a=http://www.renpy.org/dl/android}here{/a}), unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
new "Para construir paquetes de Android, por favor descarga RAPT (desde {a=http://www.renpy.org/dl/android}aquí{/a}), descomprímelo y cópialo dentro de la carpeta de Ren'Py. Después reinicia el launcher de Ren'Py."
# game/android.rpy:15
old "RAPT has been installed, but you'll need to install the Android SDK before you can build Android packages. Choose Install SDK to do this."
new "RAPT está instalado, pero tendrás que instalar el SDK de Android para poder construir paquetes de Android. Selecciona instalar SDK para instalarlo."
# game/android.rpy:16
old "RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore."
new "RAPT está instalado, pero la clave aun no se ha configurado. Por favor crea una nueva clave, o restaura android.keystore."
# game/android.rpy:17
old "The current project has not been configured. Use \"Configure\" to configure it before building."
new "El proyecto actual no se ha configurado. Usa \"Configurar\" para configurarlo antes de construirlo."
# game/android.rpy:18
old "Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device."
new "Selecciona \"Construir\" para construir el proyecto actual, o conecta un dispositivo Android y selecciona \"Construir & instalar\" para construirlo e instalarlo en el dispositivo."
# game/android.rpy:20
old "Attempts to emulate an Android phone.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Al intentar emular un teléfono Android. \n\nLa entrada táctil se emula mediante el ratón, pero sólo cuando el botón se mantiene pulsado. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
# game/android.rpy:21
old "Attempts to emulate an Android tablet.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Al intentar emular una tablet Android. \n\nLa entrada táctil se emula mediante el ratón, pero sólo cuando el botón se mantiene pulsado. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
# game/android.rpy:22
old "Attempts to emulate an OUYA console.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Al intentar emular una consola OUYA. \n\nPara el control se usan las flechas, Intro está asignado al botón select. Escape está asignado al botón de menú, y PageUp está asignado al botón Atrás."
# game/android.rpy:23
old "Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package."
new "Descarga e instala el SDK de android y los paquetes de soporte. Opcionalmente, genera la clave necesaria para firmar el paquete."
# game/android.rpy:24
old "Configures the package name, version, and other information about this project."
new "Configura el nombre del paquete, la versión, y otra información de este proyecto."
# game/android.rpy:25
old "Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details."
new "Abre el archivo que contiene las claves de Google Play en el editor. \n\nEsto sólo es necesario si la aplicación usa una expansión APK. Para más información lee la documentación."
# game/android.rpy:26
old "Builds the Android package."
new "Construir el paquete de Android."
# game/android.rpy:27
old "Builds the Android package, and installs it on an Android device connected to your computer."
new "Construye el paquete de Android, e instálalo en un dispositivo Android connectado a tu ordenador."
# game/android.rpy:148
old "{a=%s}%s{/a}"
new "{a=%s}%s{/a}"
# game/android.rpy:157
old "QUESTION"
new "PREGUNTA"
# game/android.rpy:367
old "Android: [project.current.name!q]"
new "Android: [project.current.name!q]"
# game/android.rpy:387
old "Emulation:"
new "Emulación:"
# game/android.rpy:395
old "Phone"
new "Teléfono"
# game/android.rpy:399
old "Tablet"
new "Tablet"
# game/android.rpy:403
old "Television / OUYA"
new "Televisión / OUYA"
# game/android.rpy:415
old "Build:"
new "Construir:"
# game/android.rpy:423
old "Install SDK & Create Keys"
new "Instalar SDK y Crear claves"
# game/android.rpy:427
old "Configure"
new "Configurar"
# game/android.rpy:431
old "Build Package"
new "Construir Paquete"
# game/android.rpy:435
old "Build & Install"
new "Construir & Instalar"
-37
View File
@@ -1,37 +0,0 @@
translate spanish strings:
# game/choose_theme.rpy:274
old "Could not change the theme. Perhaps options.rpy was changed too much."
new "No se puede cambiar el tema. Quizás options.rpy ha sufrido muchos cambios."
# game/choose_theme.rpy:332
old "Display"
new "Display"
# game/choose_theme.rpy:333
old "Window"
new "Window"
# game/choose_theme.rpy:334
old "Fullscreen"
new "Fullscreen"
# game/choose_theme.rpy:335
old "Planetarium"
new "Planetarium"
# game/choose_theme.rpy:342
old "Sound Volume"
new "Sound Volume"
# game/choose_theme.rpy:376
old "Choose Theme"
new "Elegir Tema"
# game/choose_theme.rpy:389
old "Theme"
new "Tema"
# game/choose_theme.rpy:413
old "Color Scheme"
new "Combinación de colores"
-322
View File
@@ -1,322 +0,0 @@
#translation: renpy/common/00action_file.rpy
translate spanish strings:
# renpy/common/00action_file.rpy:124
old "%b %d, %H:%M"
new "%d %b, %H:%M"
# renpy/common/00action_file.rpy:587
old "Quick save complete."
new "Guardado rapido completado"
#translation: renpy/common/00gallery.rpy
translate spanish strings:
# renpy/common/00gallery.rpy:521
old "Image [index] of [count] locked."
new "Imagen [index] de [count] bloqueada."
# renpy/common/00gallery.rpy:539
old "prev"
new "prev"
# renpy/common/00gallery.rpy:540
old "next"
new "siguiente"
# renpy/common/00gallery.rpy:541
old "slideshow"
new "presentación"
# renpy/common/00gallery.rpy:542
old "return"
new "volver"
#translation: renpy/common/00gltest.rpy
translate spanish strings:
# renpy/common/00gltest.rpy:50
old "Graphics Acceleration"
new "Aceleración Gráfica"
# renpy/common/00gltest.rpy:54
old "Automatically Choose"
new "Seleccionar automaticamente"
# renpy/common/00gltest.rpy:59
old "Force Angle/DirectX Renderer"
new "Forzar Angle/DirectX Renderer"
# renpy/common/00gltest.rpy:63
old "Force OpenGL Renderer"
new "Forzar OpenGL Renderer"
# renpy/common/00gltest.rpy:67
old "Force Software Renderer"
new "Forzar renderización por software"
# renpy/common/00gltest.rpy:73
old "Changes will take effect the next time this program is run."
new "Los cambios tendrán efecto la próxima vez que este programa se ejecute."
# renpy/common/00gltest.rpy:77
old "Quit"
new "Salir"
# renpy/common/00gltest.rpy:82
old "Return"
new "Volver"
# renpy/common/00gltest.rpy:112
old "Performance Warning"
new "Advertencia de rendimiento"
# renpy/common/00gltest.rpy:117
old "This computer is using software rendering."
new "Este equipo usa renderización por software."
# renpy/common/00gltest.rpy:119
old "This computer is not using shaders."
new "Este equipo no utiliza shaders."
# renpy/common/00gltest.rpy:121
old "This computer is displaying graphics slowly."
new "Este equipo está mostrando gráficos lentamente."
# renpy/common/00gltest.rpy:123
old "This computer has a problem displaying graphics: [problem]."
new "Este equipo tiene un problema monstrando gráficos: [problem]."
# renpy/common/00gltest.rpy:128
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
new "Sus drivers gráficos pueden estar desactualizados o no funcionar correctamente. Esto puede ocasionar visualización de gráficos lenta o incorrecta. Actualizar DirectX podría solucionar este problema."
# renpy/common/00gltest.rpy:130
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
new "Sus drivers gráficos pueden estar desactualizados o no funcionar correctamente. Esto puede ocasionar visualización de gráficos lenta o incorrecta."
# renpy/common/00gltest.rpy:135
old "Update DirectX"
new "Actualizar DirectX"
# renpy/common/00gltest.rpy:141
old "Continue, Show this warning again"
new "Continuar, Mostrar este aviso otra vez"
# renpy/common/00gltest.rpy:145
old "Continue, Don't show warning again"
new "Continuar, No mostrar este aviso otra vezn"
# renpy/common/00gltest.rpy:171
old "Updating DirectX."
new "Actualizando DirectX."
# renpy/common/00gltest.rpy:175
old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
new "Se ha iniciado DirectX web setup. Puede inciiar minimizado en la barra de tareas. Por favor siga las instrucciones para instalar DirectX."
# renpy/common/00gltest.rpy:179
old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
new "{b}Nota:{/b} Programa de instalación web de Microsoft DirectX, por defecto, instala la barra de herramientas de Bing. Si no quieres que se instale, desactiva la casilla correspondiente."
# renpy/common/00gltest.rpy:183
old "When setup finishes, please click below to restart this program."
new "Cuando finalize la configuración, por favor haga click abajo para reiniciar el programa."
# renpy/common/00gltest.rpy:185
old "Restart"
new "Reiniciar"
#translation: renpy/common/00keymap.rpy
translate spanish strings:
# renpy/common/00keymap.rpy:168
old "Saved screenshot as %s."
new "Screenshot guardada como %s."
#translation: renpy/common/00layout.rpy
translate spanish strings:
# renpy/common/00layout.rpy:421
old "Are you sure?"
new "¿Estás seguro?"
# renpy/common/00layout.rpy:422
old "Are you sure you want to delete this save?"
new "¿Seguro que quieres eliminar esta partida guardada?"
# renpy/common/00layout.rpy:423
old "Are you sure you want to overwrite your save?"
new "¿Seguro que quieres sobreescribir esta partida guardada?"
# renpy/common/00layout.rpy:424
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
new "Cargando, perderas el progreso no guardado. \n¿Seguro que quieres hacer esto?"
# renpy/common/00layout.rpy:425
old "Are you sure you want to quit?"
new "¿Seguro que quieres salir?"
# renpy/common/00layout.rpy:426
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
new "Seguro que quieres volver al menu principal?\nPerderas el progreso no guardado."
# renpy/common/00layout.rpy:427
old "Are you sure you want to begin skipping?"
new "Seguro que quieres comenzar a omitir?"
# renpy/common/00layout.rpy:428
old "Are you sure you want to skip to the next choice?"
new "¿Seguro que quieres saltarte la siguiente eleccion?"
# renpy/common/00layout.rpy:429
old "Are you sure you want to skip to unseen dialogue or the next choice?"
new "¿Seugro que quieres saltarte los diálogos no vistos o la sigueinte elección?"
#translation: renpy/common/00library.rpy
translate spanish strings:
# renpy/common/00library.rpy:77
old "Skip Mode"
new "Modo Salto"
# renpy/common/00library.rpy:80
old "Fast Skip Mode"
new "Modo de salto rápido"
#translation: renpy/common/00updater.rpy
translate spanish strings:
# renpy/common/00updater.rpy:1258
old "Updater"
new "Actualizador"
# renpy/common/00updater.rpy:1267
old "This program is up to date."
new "Este programa está actualizado."
# renpy/common/00updater.rpy:1269
old "[u.version] is available. Do you want to install it?"
new "[u.version] está disponible. ¿Quieres instalarla?"
# renpy/common/00updater.rpy:1271
old "Preparing to download the updates."
new "Preparando para descargar las actualizaciones."
# renpy/common/00updater.rpy:1273
old "Downloading the updates."
new "Descargando actualizaciones."
# renpy/common/00updater.rpy:1275
old "Unpacking the updates."
new "Desempaquetando las actualizaciones."
# renpy/common/00updater.rpy:1279
old "The updates have been installed. The program will restart."
new "Se han instalado las actualizaciones. El programa se reiniciará."
# renpy/common/00updater.rpy:1281
old "The updates have been installed."
new "se han instalado las actualizaciones."
# renpy/common/00updater.rpy:1283
old "The updates were cancelled."
new "Se han cancelado las actualizaciones."
#translation: renpy/common/_compat/gamemenu.rpym
translate spanish strings:
# renpy/common/_compat/gamemenu.rpym:180
old "Empty Slot."
new "Ranura vacía."
# renpy/common/_compat/gamemenu.rpym:337
old "Previous"
new "Anterior"
# renpy/common/_compat/gamemenu.rpym:344
old "Next"
new "Siguiente"
#translation: renpy/common/_compat/preferences.rpym
translate spanish strings:
# renpy/common/_compat/preferences.rpym:411
old "Joystick Mapping"
new "Asignar Joystick"
#translation: renpy/common/_errorhandling.rpym
translate spanish strings:
# renpy/common/_errorhandling.rpym:408
old "An exception has occurred."
new "Se ha producido una excepción."
# renpy/common/_errorhandling.rpym:434
old "Rollback"
new "Regresar"
# renpy/common/_errorhandling.rpym:436
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
new "Intente volver atŕas, le permitirá guardar o elegir una opción diferente."
# renpy/common/_errorhandling.rpym:439
old "Ignore"
new "Ignorar"
# renpy/common/_errorhandling.rpym:441
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
new "Ignora la excepción, le permite continuar. Esto suele conducir a errores adicionales."
# renpy/common/_errorhandling.rpym:444
old "Reload"
new "recargar"
# renpy/common/_errorhandling.rpym:446
old "Reloads the game from disk, saving and restoring game state if possible."
new "Vuelve a cargar el juego desde el disco. guarda y restaura el estado del juego si es posible."
# renpy/common/_errorhandling.rpym:448
old "Open Traceback"
new "Abrir Traceback"
# renpy/common/_errorhandling.rpym:450
old "Opens the traceback.txt file in a text editor."
new "Abrir el archivo traceback.txt en un editor de texto."
# renpy/common/_errorhandling.rpym:456
old "Quits the game."
new "Salir del juego."
# renpy/common/_errorhandling.rpym:483
old "Parsing the script failed."
new "Analizando el script fallido."
# renpy/common/_errorhandling.rpym:510
old "Open Parse Errors"
new "Abrir Analisis de Errores"
# renpy/common/_errorhandling.rpym:512
old "Opens the errors.txt file in a text editor."
new "Abre el archivo errors.txt en un editor de texto."
#translation: renpy/common/_layout/classic_load_save.rpym
translate spanish strings:
# renpy/common/_layout/classic_load_save.rpym:152
old "a"
new "a"
# renpy/common/_layout/classic_load_save.rpym:161
old "q"
new "q"
-33
View File
@@ -1,33 +0,0 @@
translate spanish strings:
# game/distribute.rpy:358
old "No packages are selected, so there's nothing to do."
new "Ningún paquete seleccionado. No hay nada que hacer."
# game/distribute.rpy:363
old "Scanning project files..."
new "Escaneando archivos del proyecto..."
# game/distribute.rpy:373
old "Scanning Ren'Py files..."
new "Escaneando los archivos de Ren'Py..."
# game/distribute.rpy:421
old "All packages have been built.\n\nDue to the presence of permission information, unpacking and repacking the Linux and Macintosh distributions on Windows is not supported."
new "Se han construido todos los paquetes.\n\nDebido a la presencia de información de permisos, desempaquetar y reempaquetar las distribuciones para Linux y Macintosh no es compatible en Windows."
# game/distribute.rpy:545
old "Archiving files..."
new "Archivando archivos..."
# game/distribute.rpy:801
old "Writing the [variant] [format] package."
new "Escribiendo el paquete [format] para [variant]."
# game/distribute.rpy:814
old "Making the [variant] update zsync file."
new "Creando el archivo de actualización zsync para [variant]."
# game/distribute.rpy:910
old "Processed {b}[complete]{/b} of {b}[total]{/b} files."
new "Procesados {b}[complete]{/b} de {b}[total]{/b} archivos."
@@ -1,45 +0,0 @@
translate spanish strings:
# game/distribute_gui.rpy:139
old "Build Distributions: [project.current.name!q]"
new "Construir Distibuciones: [project.current.name!q]"
# game/distribute_gui.rpy:154
old "Directory Name:"
new "Nombre de la carpeta:"
# game/distribute_gui.rpy:158
old "Executable Name:"
new "Nombre del ejecutable:"
# game/distribute_gui.rpy:167
old "Actions:"
new "Acciones:"
# game/distribute_gui.rpy:175
old "Edit options.rpy"
new "Editar options.rpy"
# game/distribute_gui.rpy:176
old "Refresh"
new "Recargar"
# game/distribute_gui.rpy:193
old "Build Packages:"
new "Construir Paquetes:"
# game/distribute_gui.rpy:208
old "Build Updates"
new "Construir Actualizaciones"
# game/distribute_gui.rpy:212
old "Build"
new "Construir"
# game/distribute_gui.rpy:219
old "Errors were detected when running the project. Please ensure the project runs without errors before building distributions."
new "Se detectaron errores al ejecutar el proyecto. Por favor asegúrese de que el proyecto se ejecuta sin errores antes de construir distibuciones."
# game/distribute_gui.rpy:236
old "Your project does not contain build information. Would you like to add build information to the end of options.rpy?"
new "Tu proyecto no tiene información de construcción. ¿Te gustaría añadir la información de construcción al final del archivo options.rpy?"
-64
View File
@@ -1,64 +0,0 @@
translate spanish strings:
# description for the option: "Editra"
# game/editor.rpy:120
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
new "{b}Recomendado.{/b} Un editor beta con una interfaz fácil de usar y funciones que ayudan en el desarrollo, como la corrección ortográfica. Editra actualmente carece de soporte IME necesario para la introducción de texto Chino, Japonés y Coreano."
# description for "Editra" on Linux
# game/editor.rpy:121
old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
new "{b}Recomendado.{/b} Un editor beta con una interfaz fácil de usar y funciones que ayudan en el desarrollo, como la corrección ortográfica. Editra actualmente carece de soporte IME necesario para la introducción de texto Chino, Japonés y Coreano. En Linux, Editra requiere wxPython."
# game/editor.rpy:137
old "This may have occured because wxPython is not installed on this system."
new "Esto puede haber ocurrido porque wxPython no está instalado en este sistema."
# game/editor.rpy:144
old "Up to 22 MB download required."
new "Requiere descargar hasta 22 MB."
# description for the option: "JEdit"
# game/editor.rpy:155
old "A mature editor that requires Java."
new "Un editor muy maduro que requiere Java."
# game/editor.rpy:157
old "1.8 MB download required."
new "Requiere descargar 1.8 MB."
# game/editor.rpy:158
old "This may have occured because Java is not installed on this system."
new "Esto puede haber ocurrido porque Java no está instalado en este sistema"
# option: "System Editor"
# game/editor.rpy:163
old "System Editor"
new "Editor del sistema"
# description for the option: "System Editor"
# game/editor.rpy:164
old "Invokes the editor your operating system has associated with .rpy files."
new "Usar el editor de su sistema operativo para que se asocie con los archivos .rpy."
# option: "None"
# game/editor.rpy:179
old "None"
new "Ninguno"
# description for the option: "None"
# game/editor.rpy:180
old "Prevents Ren'Py from opening a text editor."
new "Evita que Ren'Py abra un editor de texto."
# game/editor.rpy:327
old "An exception occured while launching the text editor:\n[exception!q]"
new "Ha ocurrido una excepción mientras se ejecutaba el editor de texto:\[exception!q]"
# game/editor.rpy:423
old "Select Editor"
new "Seleccionar Editor"
# game/editor.rpy:438
old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
new "Un editor de texto es el programa que vas a utilizar para editar los scripts de Ren'Py. Aquí, puedes seleccionar el editor que Ren'Py usará. Si no está disponible, el editor se descargará e instalará automáticamente."
-93
View File
@@ -1,93 +0,0 @@
translate spanish strings:
# game/font_page.rpy 65
old "PROJECTS:"
new "PROYECTOS:"
# game/front_page.rpy:67
old "refresh"
new "recargar"
# game/front_page.rpy:94
old "+ Create New Project"
new "+ Crear Un Proyecto Nuevo"
# game/front_page.rpy:106
old "Launch Project"
new "Ejecutar Proyecto"
# game/front_page.rpy:122
old "[p.name!q] (template)"
new "[p.name!q] (plantilla)"
# game/front_page.rpy:127
old "Tutorial"
new "Tutorial"
# game/front_page.rpy:128
old "The Question"
new "The Question"
# game/front_page.rpy:144
old "Active Project"
new "Proyecto Activo"
# game/front_page.rpy:152
old "Open Directory"
new "Abrir Carpeta"
# game/front_page.rpy:157
old "game"
new "game"
# game/front_page.rpy:158
old "base"
new "base"
# game/front_page.rpy:164
old "Edit File"
new "Editar Archivo"
# game/front_page.rpy:172
old "All script files"
new "Todos los scripts"
# game/front_page.rpy:181
old "Navigate Script"
new "Navegar por los Scripts"
# game/front_page.rpy:192
old "Check Script (Lint)"
new "Comprobar Script (Lint)"
# game/front_page.rpy:193
old "Change Theme"
new "Cambiar Tema"
# game/front_page.rpy:194
old "Delete Persistent"
new "Eliminar Datos Persistentes"
# game/front_page.rpy:202
old "Build Distributions"
new "Construir Distibuciones"
# game/front_page.rpy:204
old "Android"
new "Android"
# game/front_page.rpy:205
old "Generate Translations"
new "Generar Traducciones"
# game/front_page.rpy:206
old "Extract Dialogue"
new "Extraer Diálogos"
# game/front_page.rpy:222
old "Checking script for potential problems..."
new "Comprobando script por problemas potenciales..."
# game/front_page.rpy:237
old "Deleting persistent data..."
new "Eliminando datos persistentes..."
-93
View File
@@ -1,93 +0,0 @@
translate spanish strings:
# game/interface.rpy:89
old "Documentation"
new "Documentación"
# game/interface.rpy:90
old "Ren'Py Website"
new "Web de Ren'Py"
# game/interface.rpy:91
old "Ren'Py Games List"
new "Lista de juegos Ren'Py"
# game/interface.rpy:92
old "About"
new "Acerca de"
# game/interface.rpy:99
old "update"
new "actualizar"
# game/interface.rpy:101
old "preferences"
new "preferencias"
# game/interface.rpy:102
old "quit"
new "salir"
# game/interface.rpy:174
old "Yes"
new "Sí"
# game/interface.rpy:176
old "No"
new "No"
# game/interface.rpy:182
old "Back"
new "Atrás"
# game/interface.rpy:184
old "Cancel"
new "Cancelar"
# game/interface.rpy:187
old "Continue"
new "Continuar"
# game/interface.rpy:211
old "Due to package format limitations, non-ASCII file and directory names are not allowed."
new "Debido a las limitaciones del formato de paquete, no se permite el uso de nombres de archivos y carpetas que no sean ASCII"
# game/interface.rpy:213
old "[title]"
new "[title]"
# game/interface.rpy:299
old "ERROR"
new "ERROR"
# game/interface.rpy:328
old "While [what!q], an error occured:"
new "Mientras [what!q], se produjo un error:"
# game/interface.rpy:329
old "[exception!q]"
new "[exception!q]"
# game/interface.rpy:347
old "Text input may not contain the {{ or [[ characters."
new "La entrada de texto no puede contener los caracteres {{ o [[."
# game/interface.rpy:352
old "File and directory names may not contain / or \\."
new "Los nombres de archivos y carpetas no pueden contener / o \\."
# game/interface.rpy:358
old "File and directory names must consist of ASCII characters."
new "Los nombres de archivos y carpetas deben ser caracteres ASCII."
# game/interface.rpy:379
old "INFORMATION"
new "INFORMACIÓN"
# game/interface.rpy:422
old "PROCESSING"
new "PROCESANDO"
# game/interface.rpy:452
old "CHOICE"
new "SELECCIONA"
-65
View File
@@ -1,65 +0,0 @@
translate spanish strings:
# game/navigation.rpy:150
old "Navigate: [project.current.name]"
new "Navegando por: [project.current.name]"
# game/navigation.rpy:159
old "Order: "
new "Orden: "
# game/navigation.rpy:160
old "alphabetical"
new "alfabético"
# game/navigation.rpy:162
old "by-file"
new "por archivo"
# game/navigation.rpy:164
old "natural"
new "natural"
# game/navigation.rpy:176
old "Category:"
new "Categoría:"
# game/navigation.rpy:178
old "files"
new "archivos"
# game/navigation.rpy:179
old "labels"
new "Etiquetas"
# game/navigation.rpy:180
old "defines"
new "defines"
# game/navigation.rpy:181
old "transforms"
new "transforms"
# game/navigation.rpy:182
old "screens"
new "pantallas"
# game/navigation.rpy:183
old "callables"
new "callables"
# game/navigation.rpy:184
old "TODOs"
new "TODO"
# game/navigation.rpy:223
old "+ Add script file"
new "+ Añadir archivo de script"
# game/navigation.rpy:231
old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
new "No se han encontrado comentarios \"TODO\". Para crear uno, incluye \"# TODO\" en tu script."
# game/navigation.rpy:238
old "The list of names is empty."
new "La lista de nombres está vacía."
-29
View File
@@ -1,29 +0,0 @@
translate spanish strings:
# game/new_project.rpy:22
old "Choose Project Template"
new "Elige una plantilla para el proyecto"
# game/new_project.rpy:40
old "Please select a template to use for your new project. The template sets the default font and the user interface language. If your language is not supported, choose 'english'."
new "Por favor selecciona una plantilla para usar en tu nuevo proyecto. La plantilla establece la fuente predeterminada y el idioma de la interfaz de usuario, Si tu idioma no está soportado, elige \"English\"."
# game/new_project.rpy:55
old "PROJECT NAME"
new "NOMBRE DEL PROYECTO"
# game/new_project.rpy:56
old "Please enter the name of your project:"
new "Por favor introduce el nombre de tu proyecto:"
# game/new_project.rpy:62
old "The project name may not be empty."
new "El nombre del proyecto no puede estar vacío."
# game/new_project.rpy:67
old "[project_name!q] already exists. Please choose a different project name."
new "[project_name!q] ya existe. Por favor elige un nombre diferente para el proyecto."
# game/new_project.rpy:70
old "[project_dir!q] already exists. Please choose a different project name."
new "[project_dir!q] ya existe. Por favor elige un nombre diferente para el proyecto."
-61
View File
@@ -1,61 +0,0 @@
translate spanish strings:
# game/preferences.rpy:40
old "Launcher Preferences"
new "Preferencias del Launcher"
# game/preferences.rpy:61
old "Projects Directory:"
new "Carpeta de Proyectos:"
# game/preferences.rpy:68
old "[persistent.projects_directory!q]"
new "[persistent.projects_directory!q]"
# game/preferences.rpy:70
old "Not Set"
new "No establecido"
# game/preferences.rpy:84
old "Text Editor:"
new "Editor de texto:"
# game/preferences.rpy:106
old "Update Channel:"
new "Canal de actualización"
# game/preferences.rpy:126
old "Navigation Options:"
new "Opciones de navegación:"
# game/preferences.rpy:130
old "Include private names"
new "Incluir nombres privados"
# game/preferences.rpy:131
old "Include library names"
new "Incluir nombres de bibliotecas"
# game/preferences.rpy:141
old "Launcher Options:"
new "Opciones del Launcher:"
# game/preferences.rpy:145
old "Hardware rendering"
new "Renderización por hardware"
# game/preferences.rpy:146
old "Show templates"
new "Mostrar plantillas"
# game/preferences.rpy:148
old "Console output"
new "Salida de la consola"
# game/preferences.rpy:169
old "Open launcher project"
new "Abrir el launcher"
# game/preferences.rpy:183
old "Language:"
new "Idioma:"
-25
View File
@@ -1,25 +0,0 @@
translate spanish strings:
# game/project.rpy:204
old "Ren'Py is scanning the project..."
new "Ren'Py está escaneando el proyecto..."
# game/project.rpy:503
old "PROJECTS DIRECTORY"
new "CARPETA DEL PROYECTO"
# game/project.rpy:503
old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
new "Por favor elige la carpeta del proyecto usando el selector de proyecto. \n{b}El selector de carpetas puede haberse abierto detrás de esta ventana."
# game/project.rpy:503
old "This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."
new "El launcher buscará proyectos en esta carpeta, creará nuevos proyectos en esta carpeta, y colocará los proyectos en este directorio."
# game/project.rpy:543
old "Ren'Py was unable to run python with tkinter to choose the projects directory."
new "Ren'Py ha podido ejecutar python con tkinter para elegir el directorio de proyectos."
# game/project.rpy:547
old "Ren'Py has set the projects directory to:"
new "Ren'Py ha establecido el directorio de proyectos:"
-3
View File
@@ -1,3 +0,0 @@
translate spanish python:
make_style_backup()
-33
View File
@@ -1,33 +0,0 @@
translate spanish strings:
# game/translations.rpy:10
old "Create or Update Translations"
new "Crear o Actualizar Traducciones"
# game/translations.rpy:10
old "Please enter the name of the language for which you want to create or update translations."
new "Por favor introduce el nombre del idioma para el que desea crear o actualizar una traducción."
# game/translations.rpy:15
old "The language name can not be the empty string."
new "El nombre del idioma no puede estar vacío."
# game/translations.rpy:26
old "Ren'Py is generating translations...."
new "Ren'Py está generando las traducciones..."
# game/translations.rpy:30
old "Ren'Py has finished generating [language] translations."
new "Ren'Py ha terminado de generar las traducciones [language]"
# game/translations.rpy:44
old "What format would you like for the extracted dialogue?"
new "¿Qué formato te gustaría para los diálogos extraidos?"
# game/translations.rpy:56
old "Ren'Py is extracting dialogue...."
new "Ren'Py está extrayendo los diálogos..."
# game/translations.rpy:60
old "Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[format] in the base directory."
new "Ren'Py ha terminado de extraer los diálogos. Los diálogo extraídos se pueden encontrar en el dialogue.[format] en el directorio base."

Some files were not shown because too many files have changed in this diff Show More