Compare commits
188 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5196a970a0 | |||
| efcbc92e7a | |||
| 142fa33548 | |||
| 4b6e871ac6 | |||
| 1fbbad053a | |||
| 61aa933d97 | |||
| 70c3ea773e | |||
| a16de04682 | |||
| 0280a12589 | |||
| 4dc8fef9c1 | |||
| 2c02645ec7 | |||
| 40bad327fe | |||
| f5653d3c4d | |||
| 4026d7818b | |||
| a0fda2f058 | |||
| 93546e2d5c | |||
| 85a562713a | |||
| 4e9beb1a5d | |||
| 522333e0f5 | |||
| b4c4d0264c | |||
| 21c3187fa3 | |||
| b377cfcdef | |||
| 5d384e531d | |||
| 2b00c64973 | |||
| 7c777dea22 | |||
| 9d0c77917d | |||
| 6d40ced435 | |||
| 0675ee7f79 | |||
| 0aec15a848 | |||
| 2ff01a99ac | |||
| 0596ed7739 | |||
| d8beb99964 | |||
| 648dfd8d75 | |||
| 279a7a3fc8 | |||
| a62aede62f | |||
| b07bbbc1c9 | |||
| 547ce87eaa | |||
| c206456d00 | |||
| 590dd13f8f | |||
| afd0e70479 | |||
| b9166b35b3 | |||
| 333fa51862 | |||
| ec6d256707 | |||
| 86764d92a6 | |||
| cf1c9b3e5e | |||
| b15d7179b6 | |||
| 72312f1249 | |||
| 373198f628 | |||
| e96d8c774b | |||
| 8e221e183d | |||
| 2249c49303 | |||
| 388362d318 | |||
| a554ea8e8b | |||
| 090719deee | |||
| e29a162a85 | |||
| e17fa9edc2 | |||
| e57529257e | |||
| 866f9228ef | |||
| 3a38a8b89b | |||
| 0509a23881 | |||
| cbb0741ab9 | |||
| 716bb0fac1 | |||
| acb193bd7b | |||
| 0a09beb731 | |||
| 93dca3df73 | |||
| 008143a3da | |||
| 30a4db432e | |||
| 65546baf01 | |||
| 8be5069490 | |||
| 802410644b | |||
| e74b172372 | |||
| 23ac59588e | |||
| 7f6e9de5e5 | |||
| 143906ae9d | |||
| b003371456 | |||
| 1e6fa37a10 | |||
| 935786a161 | |||
| 23c4d07432 | |||
| 77107ef1eb | |||
| cac4238b12 | |||
| 8c402c2dc3 | |||
| 9bff95826a | |||
| fc0f7cecc4 | |||
| 0b5c5ce17e | |||
| 9aa61532ff | |||
| 3271557f8a | |||
| 9587342129 | |||
| 9b4821308d | |||
| 663978906a | |||
| 60f3308b8b | |||
| a305d6e725 | |||
| 1feff344b8 | |||
| 4fa4ffae54 | |||
| 4ecd72de6e | |||
| 3ec495c3fc | |||
| 5efc437384 | |||
| a777f4d3b1 | |||
| ff139808ff | |||
| 07136f9be8 | |||
| 35fc2295e9 | |||
| 2b262ccca3 | |||
| d42aab3dff | |||
| 612c347498 | |||
| 3c4540131a | |||
| 43317f6e02 | |||
| 523742d8de | |||
| 9516ee910e | |||
| 3ea31a3862 | |||
| 649411a4ef | |||
| a0e60e5453 | |||
| e3f1f40a78 | |||
| d0177f4c52 | |||
| 84a3a55a03 | |||
| 048075b47a | |||
| fab097c92a | |||
| 9d26bd8c04 | |||
| 664d243c23 | |||
| 9a0906655d | |||
| 13d60f2741 | |||
| 7d4de64d0b | |||
| 9ada2d9884 | |||
| a5f1951cfb | |||
| 98850e4c5c | |||
| 709e1f925d | |||
| b11ae331a5 | |||
| 3ba4b26b99 | |||
| b864077017 | |||
| d411dff1c0 | |||
| 7fc7453450 | |||
| 1799971885 | |||
| b999911292 | |||
| 29e0f9ad21 | |||
| d821b7eb8b | |||
| 272a214304 | |||
| 7f15b351ee | |||
| 5a6a12a14a | |||
| 01493c7063 | |||
| 244055fcb7 | |||
| 0415af5f31 | |||
| f73372c924 | |||
| 65cdc24e37 | |||
| 1b2d439651 | |||
| b383942c69 | |||
| 73bd109abb | |||
| 33ffd5dedb | |||
| 7422fe43b8 | |||
| 879c45a5b3 | |||
| db0d205374 | |||
| f20594a2b5 | |||
| ee017f4bc6 | |||
| 4d089f9a0e | |||
| e7f9c5c2ac | |||
| 2df8d38c2f | |||
| 17ac44d610 | |||
| 3c52c2ae3f | |||
| 5a5115e29f | |||
| 5c7ff1c97b | |||
| cc820a3595 | |||
| 48fff48d28 | |||
| 1684243e57 | |||
| 45e14781eb | |||
| 5ceea7b4a5 | |||
| 17e716b4c3 | |||
| adfdbf3246 | |||
| 03b757d60e | |||
| 12c6d77990 | |||
| 8a7373f412 | |||
| df28ff5bdc | |||
| 2afc2beb5d | |||
| 3896bf3aad | |||
| 744ace5ab6 | |||
| 4bf0b74b6c | |||
| 5c6e624ff7 | |||
| 6c0d5a7a10 | |||
| b34cb21f0c | |||
| b77eb7ed0b | |||
| 34193c510e | |||
| 55f1eaf5da | |||
| 9b74b5a367 | |||
| 008922edc6 | |||
| 82edca785f | |||
| b271baecd5 | |||
| 9b48cd2a35 | |||
| 183f6ace88 | |||
| b5987cd6ea | |||
| 6e153a5070 | |||
| 56e59d91dd | |||
| fd91c6811f |
@@ -0,0 +1,56 @@
|
||||
build
|
||||
dist
|
||||
dists
|
||||
renpy.app
|
||||
**/*.rpyc
|
||||
**/*.rpyb
|
||||
**/*.rpymc
|
||||
_renpy.c
|
||||
nativemidi.c
|
||||
sound.c
|
||||
winmixer.c
|
||||
jedit
|
||||
lint.txt
|
||||
renpy.code
|
||||
traceback.txt
|
||||
doc/common.css
|
||||
doc/images
|
||||
doc/index.html
|
||||
doc/monobook.css
|
||||
doc/monobook2.css
|
||||
doc/reference
|
||||
doc/shared.css
|
||||
doc/tutorials
|
||||
doc/www.renpy.org
|
||||
testing
|
||||
translations.rpy
|
||||
launchertrans.rpy
|
||||
jcc
|
||||
scite/scite.zip
|
||||
screenshot*
|
||||
.ropeproject
|
||||
release_cardgame.sh
|
||||
cardgame
|
||||
dse.split
|
||||
empty
|
||||
empty-linux-x86.tar.bz2
|
||||
empty-mac.zip
|
||||
empty.zip
|
||||
errors.txt
|
||||
icons
|
||||
iliad-icon.png
|
||||
iliad-work
|
||||
kuroi
|
||||
lsprofcalltree.py
|
||||
manifest.xml
|
||||
mediatest
|
||||
musicroom
|
||||
nobmtest
|
||||
renpy-iliad.sh
|
||||
renpy.kcg
|
||||
renpy.stats
|
||||
renpygame-1.2.zip
|
||||
speedtest
|
||||
styles.txt
|
||||
renpygame-demo/game/saves
|
||||
./lib
|
||||
@@ -1,3 +1,427 @@
|
||||
New in Ren'Py 6.9.1
|
||||
-------------------
|
||||
|
||||
The music and video playback code has been completely rewritten. The
|
||||
new implementation uses the ffmpeg library. It includes the following
|
||||
features:
|
||||
|
||||
* Support for ogg, mp3, mp2, wav, and flac audio.
|
||||
|
||||
* Support for theora, mpeg4 part 2 (including DivX and Xvid), mpeg2,
|
||||
and mpeg1 video.
|
||||
|
||||
* Support for an arbitrary number of named channels, replacing the
|
||||
previous eight numbered channels.
|
||||
|
||||
* Audio files are now automatically converted to the output sampling
|
||||
rate (by default, 44100hz). This prevents the problems that would
|
||||
previously crop up when playing audio sampled at other rates.
|
||||
|
||||
* The play, queue, and stop statements now take a channel name as the
|
||||
second argument, which makes using user-defined channels easier.
|
||||
|
||||
As part of this rewrite, we have eliminated support for mod formats,
|
||||
as they are not supported by ffmpeg.
|
||||
|
||||
Please read the reference manual documentation for Audio and Movies to
|
||||
learn the new interface.
|
||||
|
||||
The new code requires some changes in the saved data. As a result,
|
||||
loading a file saved with a prior version of Ren'Py may lead to a lack
|
||||
of music until the next track is played.
|
||||
|
||||
|
||||
|
||||
The new window statement allows one to control if an empty window is
|
||||
shown when no character is speaking. Specifically, the
|
||||
|
||||
window show [transition]
|
||||
|
||||
statement shows the window, and the
|
||||
|
||||
window hide [transition]
|
||||
|
||||
statement hides it. Both can take an optional
|
||||
transition. config.empty_window is responsible for displaying the
|
||||
window, while config.window_show_transition and
|
||||
config.window_hide_transition are default transitions. The state of
|
||||
the window can be determined by testing _window. The
|
||||
renpy.shown_window function can be called to suppress displaying the
|
||||
empty window, and is called automatically when characters speak.
|
||||
|
||||
|
||||
Hotspots for the game menu buttons can be defined as part of
|
||||
layout.imagemap_load_save, layout.imagemap_preferences, and
|
||||
layout.imagemap_yesno_prompt. Doing so prevents layout.navigation from
|
||||
being called for that screen. It also allows opaque imagemaps to be
|
||||
used, rather than forcing them to be transparent to allow the
|
||||
navigation to show through.
|
||||
|
||||
|
||||
There is a new config.windows_icon variable, that lets one set the
|
||||
window icon for Windows separately from Mac OS X and Linux.
|
||||
|
||||
|
||||
Ren'Py now automatically scales itself down when it detects that the
|
||||
game window is too large for the screen.
|
||||
|
||||
|
||||
The define.move_transitions function can now pass keyword arguments to
|
||||
the moves it creates. The most useful thing with this is to pass
|
||||
subpixel=True, in order to create subpixel move transitions.
|
||||
|
||||
|
||||
The Motion (including Move and Pan), Zoom, RotoZoom, and FactorZoom
|
||||
displayables now use the style.motion style, which now has xanchor and
|
||||
yanchor both set to 0. This gives these movements the same semantics
|
||||
when used inside an image clause as they have outside one.
|
||||
|
||||
|
||||
im.Grayscale and im.Sepia now take properties, so they can be
|
||||
positioned.
|
||||
|
||||
|
||||
The new renpy.get_placement function returns information about the
|
||||
placement of displayables.
|
||||
|
||||
|
||||
Improved the render management code, so there should no longer be any
|
||||
leaks reported during shutdown.
|
||||
|
||||
|
||||
Deal with the case where a bmfont has a negative offset for the first
|
||||
character in a string.
|
||||
|
||||
|
||||
Added more verbose diagnostics when illegal statements are run in the
|
||||
init phase.
|
||||
|
||||
|
||||
Added _rollback, which controls if rollback is enabled.
|
||||
|
||||
|
||||
Added a target parameter to renpy.full_restart, which allows the main
|
||||
menu screen to be selected after a restart.
|
||||
|
||||
|
||||
|
||||
Fixed a bug that caused layout.imagemap_main_menu to call a label even
|
||||
though there was a button with the same name.
|
||||
|
||||
Fixed a bug that prevented Zoom from working in non-bilinear mode.
|
||||
|
||||
Fixed a bug that could cause buttons not not consume events when using
|
||||
an imagemap main menu.
|
||||
|
||||
Fixed a bug that caused Transform to produce an incorrectly-sized
|
||||
render.
|
||||
|
||||
Fixed a bug that could cause crashing when rolling back to a Zoom with
|
||||
an after_child.
|
||||
|
||||
Fixed a bug that could cause segfaults when saving overly-complicated
|
||||
images.
|
||||
|
||||
|
||||
New in Ren'Py 6.9.0
|
||||
-------------------
|
||||
|
||||
This release features a rewritten rendering system. The rendering
|
||||
subsystem is what manages drawing to the screen. There have been
|
||||
several major improvements:
|
||||
|
||||
* The render system has been simplified. Although still complex, it's
|
||||
now easier to understand than the old system, while also being
|
||||
naturally a bit faster.
|
||||
|
||||
* That being said, the render system now focuses more on framerate
|
||||
consistency than raw speed.
|
||||
|
||||
* The render system now supports subpixel drawing, drawing images at
|
||||
locations that are not integer pixel boundaries. This is enabled by
|
||||
setting the subpixel style property to True for a displayable. (It
|
||||
makes the most sense to do this for Move and Pan, and less sense to
|
||||
do this for non-moving displayables.)
|
||||
|
||||
* The render system supports specifying subpixel placement of
|
||||
displayables. This is done using the new absolute type. (A
|
||||
floating-point position is still interpreted as a fraction of the
|
||||
area in which the displayable is placed.)
|
||||
|
||||
* The render system supports a rotate-zoom-alpha mode, in which allows
|
||||
a displayable to be rotated, zoomed, and have its alpha
|
||||
changed. When this mode is used, the cost remains constant, even
|
||||
when multiple transformations are composed. Currently, this is only
|
||||
used by Transform and ui.transform.
|
||||
|
||||
* The render system supports rotating and scaling focusable objects.
|
||||
|
||||
Improved the transform routine used by RotoZoom and Transform. It's
|
||||
now both more accurate and faster. On Intel computers, it is now
|
||||
accelerated using MMX instructions.
|
||||
|
||||
|
||||
The image statement now implicitly places itself inside an init block
|
||||
if it's not inside an init block to begin with. The code:
|
||||
|
||||
image bg world = "world.jpg"
|
||||
|
||||
is now equivalent to:
|
||||
|
||||
init 990:
|
||||
image bg world = "world.jpg"
|
||||
|
||||
|
||||
When compiling python blocks containing strings with a unicode
|
||||
character in them, Ren'Py will automatically prepend a u to any string
|
||||
that's missing it. This should make life easier for users of non-ASCII
|
||||
languages.
|
||||
|
||||
|
||||
The new ui.autobar function makes it easy to make a bar that
|
||||
varies between two values over time.
|
||||
|
||||
|
||||
The new renpy.Container class can be subclassed to create a user-defined
|
||||
displayable thatr contains other displayables, like Transforms.
|
||||
|
||||
|
||||
The new im.FactorScale image manipulator allows images to be scaled by
|
||||
a specified factor at preload time. This is generally faster than doing the
|
||||
equivalent scaling at display time with FactorZoom.
|
||||
|
||||
|
||||
The new renpy.sound.set_pan function allows sound and music to be
|
||||
smoothly panned over time.
|
||||
|
||||
|
||||
The new config.label_callback variable allows a function to be called
|
||||
whenever control reaches a label. It can distinguish between jumps to
|
||||
that label and control falling through.
|
||||
|
||||
|
||||
There have been a couple of places where properly documented functions
|
||||
have superseded semi-documented calls into the Ren'Py internals:
|
||||
|
||||
The renpy.game_menu and ui.gamemenus functions are now the preferred ways
|
||||
of getting access to the game menu.
|
||||
|
||||
The ui.jumps function now takes a transition argument, allowing it to subsume
|
||||
the undocumented _intra_jumps.
|
||||
|
||||
|
||||
Ren'Py now looks for the file environment.txt in the directory
|
||||
containing Ren'Py itself. If it finds it, it loads the file as a
|
||||
python file, and uses it to set the default values of environment
|
||||
variables. This allows things like the editor or the scale factor to
|
||||
be set even on platforms that don't make it easy to change environment
|
||||
variables globally.
|
||||
|
||||
|
||||
The reporting of parse errors involving missing quotes has been
|
||||
improved.
|
||||
|
||||
|
||||
Changed the behavior of overlays during transitions. Now, both the old
|
||||
and new screens will use the new overlay. Previously, the overlay was
|
||||
cleared out during a transition, which didn't work well, as (for
|
||||
example) a dissolve would cause the overlay to blink out and then
|
||||
dissolve back in again.
|
||||
|
||||
|
||||
MoveTransition and define.move_transitions have been changed to take
|
||||
a layers argument, giving the list of layers the transition applies
|
||||
to. By default, this is only the master layer, which is a change in
|
||||
their behavior.
|
||||
|
||||
|
||||
Calling theme.roundrect() no longer implies layout.button_menu().
|
||||
|
||||
|
||||
Ren'Py now autosaves when entering the quit prompt, and will not actually
|
||||
quit until this autosave is complete.
|
||||
|
||||
|
||||
The default framerate limit (config.framerate) has been raised to
|
||||
100fps. This make tearing less noticable than on a 60hz screen.
|
||||
|
||||
|
||||
Added renpy.partial as a version of renpy.curry that requires two
|
||||
function calls, rather than three.
|
||||
|
||||
|
||||
Fixed a divide by zero error that occured when Alpha was used for 0
|
||||
seconds.
|
||||
|
||||
|
||||
Libvorbis has been upgraded to version 1.2.0.
|
||||
|
||||
|
||||
To reduce distribution size, OGG Speex support was dropped.
|
||||
|
||||
|
||||
New in Ren'Py 6.8.1
|
||||
-------------------
|
||||
|
||||
Added support for the iRex iLiad ebook reader platform. This required
|
||||
adding the following features, which may prove useful for other
|
||||
platforms:
|
||||
|
||||
Added support for the RENPY_SCALE_WIDTH environment variable, which
|
||||
allows the game to be scaled to a specific width, if it's larger.
|
||||
|
||||
Added support for the RENPY_LESS_MEMORY environment variable, which
|
||||
reduces the amount of memory used by Ren'Py in exchanged for reduced
|
||||
speed.
|
||||
|
||||
Added support for the RENPY_LESS_UPDATES environment variable, which
|
||||
tries to reduce the number of screen updates to one per interaction.
|
||||
|
||||
Added support for the RENPY_LESS_MOUSE environment variable, which
|
||||
prevents the mouse from being shown.
|
||||
|
||||
The iLiad support was sponsored by Hixbooks.
|
||||
|
||||
|
||||
It is now possible to rebuild the distribution of a game by unzipping
|
||||
it underneath the Ren'Py directory, selecting it as a project, and
|
||||
building the distributions. This makes it easy to upgrade the version
|
||||
of Ren'Py used by a game, or to build a version of it that works on
|
||||
your favorite platform.
|
||||
|
||||
|
||||
The new Alpha function can be used to change the alpha level of a
|
||||
displayable. (im.Alpha can only be used with other image
|
||||
manipulators.)
|
||||
|
||||
|
||||
User-defined statements are now documented in the reference manual,
|
||||
making them officially supported.
|
||||
|
||||
A user-defined statement can now be used as the default
|
||||
statement. This allows you to replace the say statement with an
|
||||
alternate of your own devising.
|
||||
|
||||
|
||||
Fixed a bug that occured when space characters were inserted
|
||||
immediately after a newline.
|
||||
|
||||
Fixed a problem displaying a presplash image on the mac platform.
|
||||
|
||||
|
||||
New in Ren'Py 6.8.0
|
||||
-------------------
|
||||
|
||||
Ren'Py now includes its own font-handling library, derived from
|
||||
pygame.font/SDL_ttf, which it uses in place of them when
|
||||
possible. This gives two advantages:
|
||||
|
||||
* Outlined text is now possible. The new outlines style property
|
||||
allows you to specify one or more outlines, including offset
|
||||
ones. This allows for several fairly complicated text effects, similar
|
||||
to what you'd see in modern subtitles.
|
||||
|
||||
* The bug preventing fonts from being archived has probably been
|
||||
fixed. It should now be possible to include a font in an archive, and
|
||||
have that work. The archiver has been modified to allow ttf files to
|
||||
be archived again. Please report any bugs/crashes that occur.
|
||||
|
||||
|
||||
There is now a new justify style property, that causes lines of text
|
||||
to have additional whitespace inserted between words so that the left
|
||||
and right margins are even, except on the last line of a paragraph.
|
||||
|
||||
|
||||
Ren'Py now supports the MudgeFont and BMFont image-based font file
|
||||
formats. The new renpy.register_mudgefont function is used to register
|
||||
a MudgeFont, and the renpy.register_bmfon function is used to register
|
||||
a BMFont.
|
||||
|
||||
|
||||
Newly-created games will have a Help option on the main and game
|
||||
menus. This is controlled by the config.help variable. By default
|
||||
the help system shows the README.html file in the game's base directory.
|
||||
|
||||
|
||||
If the file icon.ico is present in the base directory, it will be used
|
||||
as the icon of the windows exe when building the windows
|
||||
distribution. Similarly, the file icon.icns will be used as the icon
|
||||
of the Macintosh application. (Note that .icns is a different file format
|
||||
from .ico.)
|
||||
|
||||
|
||||
On Mac OS X, Ren'Py will not change the application icon unless
|
||||
config.window_icon is set. More specifically, it will default to the
|
||||
launcher icon rather than a generic pygame icon.
|
||||
|
||||
|
||||
The Macintosh application will now show the name of the game in the
|
||||
menu bar, rather than "Ren'Py Launcher".
|
||||
|
||||
|
||||
The "Continue Game" option on the main menu has been renamed "Load
|
||||
Game", for consistency with the game menu.
|
||||
|
||||
|
||||
When config.developer is set and an undefined image is used in a show
|
||||
or scene statement, a list of undefined images will appear centered at
|
||||
the top of the screen. A black screen (configurable with
|
||||
config.missing_background) will be shown instead of any missing
|
||||
background. This makes it easier to write a script before all images
|
||||
are present.
|
||||
|
||||
|
||||
The newly-documented Style.set_parent method lets you change the
|
||||
parent of a style. The new style.rebuild function allows styles to be
|
||||
rebuilt even after the game has begun running, with some
|
||||
caveats. (Changes are not persisted, for one thing.)
|
||||
|
||||
|
||||
The new unscrollable style property allows one to choose how
|
||||
unscrollbable scrollbars are displays. None keeps the current
|
||||
behavior, which shows the bar normally. If set to "insensitive", the
|
||||
bar becomes insensitive, while if set to "hide", the bar is not
|
||||
drawn at all.
|
||||
|
||||
|
||||
The new renpy.easy_displayable method can be used by user-defined
|
||||
displayables to convert strings into Solid or Image displayables.
|
||||
|
||||
|
||||
Alt-F4 and Command-Q now trigger the quit event, as if you pressed the
|
||||
quit button on the top of the window. The first press brings up the
|
||||
quit prompt, and a second press forcibly terminates the game.
|
||||
|
||||
Alt-M and Command-M iconify the window.
|
||||
|
||||
|
||||
The new RENPY_SCREENSHOT_PATTERN environment variable lets you
|
||||
configure the name of screenshot files. Ren'Py can now write out
|
||||
screenshots as JPGs, as well as PNGs.
|
||||
|
||||
|
||||
Several of the libraries underlying Ren'Py have been updated. Pygame
|
||||
has been updated to version 1.8.1, while Freetype is now at version
|
||||
2.3.7.
|
||||
|
||||
|
||||
The presplash code now looks for presplash.jpg in the game directory
|
||||
if presplash.png is not found.
|
||||
|
||||
|
||||
On Windows, config.window_icon will be scaled to 32x32 if it is wider
|
||||
than 32 pixels. This allows the same icon to be used across platforms.
|
||||
|
||||
|
||||
Custom mouse cursors should now be properly hidden when the mouse
|
||||
leaves the window. Previously, this failed to work on the Mac OS X
|
||||
platform.
|
||||
|
||||
|
||||
The launcher has been moved into the launcher/ directory. This really
|
||||
shouldn't matter much, but may affect packaging and translation.
|
||||
|
||||
|
||||
New in Ren'Py 6.7.1
|
||||
-------------------
|
||||
|
||||
@@ -48,11 +472,20 @@ what to archive. This makes it easier to break the files up into
|
||||
multiple archives, in a single game.
|
||||
|
||||
|
||||
The new renpy.copy_images function copies images with one prefix to a
|
||||
second prefix.
|
||||
|
||||
|
||||
The launcher will no longer include directories beginning with a dot
|
||||
(like .svn and .bzr) when copying the template directory to create a
|
||||
new project.
|
||||
|
||||
|
||||
This version includes a refresh of the character art included with
|
||||
"The Question". The new art is by Deji, and the full-color version of
|
||||
the art is available from http://wiki.renai.us/.
|
||||
|
||||
|
||||
|
||||
New in Ren'Py 6.7.0
|
||||
-------------------
|
||||
@@ -3966,4 +4399,3 @@ 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.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Copyright 2004-2007 PyTom <pytom@bishoujo.us>
|
||||
Ren'Py itself is covered by the terms of the following (MIT) license:
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
@@ -19,9 +20,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
(The above is the MIT License)
|
||||
|
||||
Please see each individual source file for a list of copyright
|
||||
holders. The pictures of Eileen in the demo are Copyright 2006
|
||||
@@ -34,25 +32,20 @@ launchers may contain code taken from the following projects:
|
||||
* Pygame (LGPL)
|
||||
* SDL (LGPL)
|
||||
* SDL_image (LGPL)
|
||||
* SDL_sound (LGPL)
|
||||
* SDL_ttf (LGPL)
|
||||
* SDL_mixer (LGPL)
|
||||
* Freetype (LGPL)
|
||||
* FFmpeg (LGPL)
|
||||
* jpeg (JPEG License)
|
||||
* libmodplug (Public Domain)
|
||||
* libogg (Xiph.org License)
|
||||
* libpng (PNG license)
|
||||
* libvorbis (Xiph.org License)
|
||||
* smpeg (LGPL)
|
||||
* speex (Xiph.org License)
|
||||
* zlib (Zlib License)
|
||||
* zlib (Zlib License)
|
||||
* bzip2 (Bzip2 License)
|
||||
* pyobjc (MIT License)
|
||||
|
||||
The Linux launcher may also include code from:
|
||||
The Linux build may also include code from:
|
||||
|
||||
* directfb (LGPL)
|
||||
* svgalib (LGPL)
|
||||
* svgalib (LGPL)
|
||||
|
||||
For the purpose of LGPL compliance, the source code to all LGPL
|
||||
software we depend on is either in the Ren'Py package (available from
|
||||
@@ -61,9 +54,13 @@ http://www.renpy.org/), or in the renpy-deps package
|
||||
by including a copy of this license with every copy of Ren'Py you
|
||||
distribute, and referring to it in your project's README file.
|
||||
|
||||
The default Ren'Py build distributes Ren'Py alongside jEdit, which is
|
||||
licensed under the GNU GPL. The source code to jEdit is distributed as
|
||||
part of the renpy-deps package (http://www.renpy.org/dl/lgpl/).
|
||||
|
||||
|
||||
GNU Lesser General Public License
|
||||
---------------------------------
|
||||
=================================
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
@@ -575,7 +572,7 @@ That's all there is to it!
|
||||
|
||||
|
||||
Python License
|
||||
--------------
|
||||
==============
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
@@ -625,7 +622,7 @@ Agreement.
|
||||
|
||||
|
||||
Jpeg License
|
||||
------------
|
||||
============
|
||||
|
||||
In plain English:
|
||||
|
||||
@@ -674,39 +671,8 @@ commercial products, provided that all warranty or liability claims are
|
||||
assumed by the product vendor.
|
||||
|
||||
|
||||
Xiph.org License
|
||||
----------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
PNG License
|
||||
-----------
|
||||
===========
|
||||
|
||||
The PNG Reference Library is supplied "AS IS". The Contributing Authors
|
||||
and Group 42, Inc. disclaim all warranties, expressed or implied,
|
||||
@@ -734,9 +700,8 @@ supporting the PNG file format in commercial products. If you use this
|
||||
source code in a product, acknowledgment is not required but would be
|
||||
appreciated.
|
||||
|
||||
|
||||
Zlib License
|
||||
------------
|
||||
============
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -754,8 +719,9 @@ Zlib License
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
|
||||
Bzip2 License
|
||||
-------------
|
||||
=============
|
||||
|
||||
This program, "bzip2", the associated library "libbzip2", and all
|
||||
documentation, are copyright (C) 1996-2005 Julian R Seward. All
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
This file contains boilerplate information about running Ren'Py that
|
||||
can be included into the README for your game. It may be necessary to
|
||||
change some of the filenames in this document, to make it specific to
|
||||
your game.
|
||||
|
||||
Feel free to use this in your projects.
|
||||
|
||||
|
||||
|
||||
Running the Game
|
||||
================
|
||||
|
||||
(Windows)
|
||||
|
||||
If this game was installed on Windows using an installer, then you can
|
||||
run it by choosing the shortcut left by the installer. If this game
|
||||
was installed on Windows using the cross-platform zip file, then it
|
||||
can be run by executing the run_game.exe file.
|
||||
|
||||
(Macintosh)
|
||||
|
||||
For information about running Ren'Py games on Mac OS 10.3 or higher,
|
||||
please go to http://www.bishoujo.us/renpy/mac.html .
|
||||
|
||||
(Linux/Unix)
|
||||
|
||||
For information about running Ren'Py games under Linux and Unix,
|
||||
please go to http://www.bishoujo.us/renpy/linux.html . At the very
|
||||
least, you will need to compile the _renpy module. Read
|
||||
the file module/README.txt for details.
|
||||
|
||||
|
||||
Playing the Game
|
||||
================
|
||||
|
||||
By default, the game starts running in full screen mode. On some
|
||||
computers, especially some virtual machines, this can lead to mouse
|
||||
problems. To fix this, press 'f'.
|
||||
|
||||
Some of the more interesting game actions can be performed as follows:
|
||||
|
||||
- The left mouse button is used to advance to the next line of
|
||||
dialogue, or to pick menu options.
|
||||
|
||||
- The right mouse button brings you into a menu screen where you can
|
||||
save the game, load the game, change preferences, return to the main
|
||||
menu, or quit entirely.
|
||||
|
||||
- Scrolling the mouse wheel up or pushing page up returns you to the
|
||||
previous screen.
|
||||
|
||||
- Holding down the CTRL key skips dialogue. By default, it only
|
||||
skips read dialogue, but this can be changed by a preference. Tab
|
||||
toggles skip mode.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
A version of dissolve that only draws the pixels that are being
|
||||
dissolved, while doing a straight-blit on pixels that remain the same
|
||||
between the two images.
|
||||
|
||||
Figure out some way of having variables updated in a new context saved
|
||||
permanently, even if we return to the outer context because of a
|
||||
rollback or something. Need to be very careful here.
|
||||
|
||||
Dynamic variables, parameterized labels, etc.
|
||||
|
||||
Implement an extension mechanism of some sort, so that users can drop
|
||||
packages of Ren'Py code into the Ren'Py directory, and get stuff like
|
||||
speech support.
|
||||
|
||||
Implement speech control support.
|
||||
|
||||
BPP conversion (perhaps as a package).
|
||||
|
||||
Automatically scale to a fixed size.
|
||||
|
||||
Hide picture-mouse when leaving window, restore it when entering window.
|
||||
@@ -1 +0,0 @@
|
||||
build_exe.py run_game
|
||||
@@ -18,7 +18,9 @@ def main():
|
||||
setup(name="RenPy",
|
||||
windows=[ dict(script="renpy.py",
|
||||
dest_base="renpy",
|
||||
icon_resources=[ (1, "newicon.ico") ] ) ],
|
||||
icon_resources=[ (1, "newicon.ico") ],
|
||||
),
|
||||
],
|
||||
|
||||
console=[ dict(script="renpy.py", dest_base="console") ],
|
||||
|
||||
@@ -29,6 +31,7 @@ def main():
|
||||
'pygame.surfarray',
|
||||
'pygame.mixer',
|
||||
'pygame.mixer_music',
|
||||
'pygame.font',
|
||||
'_ssl',
|
||||
'_hashlib',
|
||||
'win32con',
|
||||
@@ -57,6 +60,9 @@ def main():
|
||||
if fn in seen:
|
||||
continue
|
||||
|
||||
if fn == "SDL_mixer.dll":
|
||||
continue
|
||||
|
||||
seen[fn] = True
|
||||
|
||||
zfnew.writestr(fn, zfold.read(fn))
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
1#!/usr/bin/env python
|
||||
|
||||
import glob
|
||||
import re
|
||||
from sets import Set as set
|
||||
import sys
|
||||
|
||||
seen_files = set()
|
||||
seen_strings = set()
|
||||
|
||||
def tl(fn, s):
|
||||
|
||||
s = eval(s)
|
||||
|
||||
if len(s) < 3:
|
||||
return
|
||||
|
||||
if s in seen_strings:
|
||||
return
|
||||
|
||||
if fn not in seen_files:
|
||||
print >>out
|
||||
print >>out, " # Translatable strings found in", fn
|
||||
print >>out
|
||||
seen_files.add(fn)
|
||||
|
||||
print >>out, " config.translations[%r] = %r" % (s, s)
|
||||
seen_strings.add(s)
|
||||
|
||||
def process(fn):
|
||||
|
||||
data = file(fn).read()
|
||||
|
||||
for m in re.finditer(r'\bu\"(\\"|[^"])+\"', data):
|
||||
tl(fn, m.group(0))
|
||||
|
||||
for m in re.finditer(r"\bu\'(\\'|[^'])+\'", data):
|
||||
tl(fn, m.group(0))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# out = file("extras/translations.rpy", "w")
|
||||
out = sys.stdout
|
||||
|
||||
print >>out, "# This file contains a list of all of the phrases you can translate"
|
||||
print >>out, "# from the Ren'Py launcher."
|
||||
print >>out, ""
|
||||
print >>out, "init python:"
|
||||
|
||||
for fn in glob.glob("launcher/*.rpy"):
|
||||
process(fn)
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
files = glob.glob("common/*.rpy")
|
||||
files.sort()
|
||||
|
||||
styles = [ ]
|
||||
|
||||
for fn in files:
|
||||
f = file(fn)
|
||||
|
||||
fi = iter(f)
|
||||
|
||||
for l in iter(fi):
|
||||
|
||||
l = l.strip()
|
||||
|
||||
if l.startswith("### "):
|
||||
|
||||
prefix, style, parent = l.split()
|
||||
|
||||
desc = ""
|
||||
|
||||
for l in fi:
|
||||
|
||||
l = l.strip()
|
||||
if not l.startswith("# "):
|
||||
break
|
||||
|
||||
desc = desc + " " + l[2:]
|
||||
|
||||
styles.append(' style.create("%s", "%s", "%s")' % (style, parent, desc[1:]))
|
||||
|
||||
f.close()
|
||||
|
||||
f = file("common/style.rpy")
|
||||
of = file("common/style.rpy.new", "w")
|
||||
|
||||
fi = iter(f)
|
||||
|
||||
for l in fi:
|
||||
|
||||
of.write(l)
|
||||
|
||||
if l.startswith("# AUTOMATICALLY GENERATED"):
|
||||
|
||||
for l in styles:
|
||||
of.write(l + "\n")
|
||||
|
||||
for l in fi:
|
||||
if l.startswith("# END AUTOMATICALLY GENERATED"):
|
||||
break
|
||||
|
||||
of.write(l)
|
||||
|
||||
f.close()
|
||||
of.close()
|
||||
|
||||
os.rename("common/style.rpy", "common/style.rpy.bak")
|
||||
os.rename("common/style.rpy.new", "common/style.rpy")
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 335 B |
@@ -1,697 +0,0 @@
|
||||
# cardgame.rpy - Cardgame support for Ren'Py
|
||||
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# This software may be distributed in modified or unmodified form,
|
||||
# provided:
|
||||
#
|
||||
# (1) This complete license notice is retained.
|
||||
#
|
||||
# (2) This software and all software and data files distributed
|
||||
# alongside this software and intended to be loaded in the same
|
||||
# memory space may be redistributed without requirement for
|
||||
# payment, notification, or other forms of compensation.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Commercial licensing for this software is available, please
|
||||
# contact pytom@bishoujo.us for information.
|
||||
|
||||
init python:
|
||||
|
||||
import pygame
|
||||
|
||||
DRAG_NONE = 0
|
||||
DRAG_CARD = 1
|
||||
DRAG_ABOVE = 2
|
||||
DRAG_STACK = 3
|
||||
DRAG_TOP = 4
|
||||
|
||||
# Returns the overlap of the area between the two
|
||||
# rectangles.
|
||||
def __rect_overlap_area(r1, r2):
|
||||
if r1 is None or r2 is None:
|
||||
return 0
|
||||
|
||||
x1, y1, w1, h1 = r1
|
||||
x2, y2, w2, h2 = r2
|
||||
|
||||
maxleft = max(x1, x2)
|
||||
minright = min(x1 + w1, x2 + w2)
|
||||
maxtop = max(y1, y2)
|
||||
minbottom = min(y1 + h1, y2 + h2)
|
||||
|
||||
if minright < maxleft:
|
||||
return 0
|
||||
|
||||
if minbottom < maxtop:
|
||||
return 0
|
||||
|
||||
return (minright - maxleft) * (minbottom - maxtop)
|
||||
|
||||
def __default_can_drag(table, stack, card):
|
||||
return table.get_faceup(card)
|
||||
|
||||
class Table(renpy.Displayable):
|
||||
|
||||
def __init__(self, back=None, base=None, springback=0.1, rotate=0.1, can_drag=__default_can_drag, doubleclick=.33, **kwargs):
|
||||
|
||||
renpy.Displayable.__init__(self, **kwargs)
|
||||
|
||||
# A map from card value to the card object corresponding to
|
||||
# that value.
|
||||
self.cards = { }
|
||||
|
||||
# A list of the stacks that have been defined.
|
||||
self.stacks = [ ]
|
||||
|
||||
# The back of cards that don't have a more specific back
|
||||
# defined.
|
||||
self.back = renpy.easy.displayable_or_none(back)
|
||||
|
||||
# The base of stacks that don't have a more specific base
|
||||
# defined.
|
||||
self.base = renpy.easy.displayable_or_none(base)
|
||||
|
||||
# The amount of time it takes for cards to springback
|
||||
# into their rightful place.
|
||||
self.springback = springback
|
||||
|
||||
# The amount of time it takes for cards to rotate into
|
||||
# their proper orientation.
|
||||
self.rotate = rotate
|
||||
|
||||
# A function that is called to tell if we can drag a
|
||||
# particular card.
|
||||
self.can_drag = can_drag
|
||||
|
||||
# The time between clicks for the click to be considered a
|
||||
# double-click.
|
||||
self.doubleclick = doubleclick
|
||||
|
||||
# Are we sensitive to input? [doc]
|
||||
self.sensitive = True
|
||||
|
||||
# The last click event.
|
||||
self.last_event = CardEvent()
|
||||
|
||||
# The card that has been clicked.
|
||||
self.click_card = None
|
||||
|
||||
# The stack that has been clicked.
|
||||
self.click_stack = None
|
||||
|
||||
# The list of cards that are being dragged.
|
||||
self.drag_cards = [ ]
|
||||
|
||||
# Are we dragging the cards?
|
||||
self.dragging = False
|
||||
|
||||
# The position where we clicked.
|
||||
self.click_x = 0
|
||||
self.click_y = 0
|
||||
|
||||
# The amount of time we've been shown for.
|
||||
self.st = 0
|
||||
|
||||
# This shows the table on the given layer.
|
||||
def show(self, layer='master'):
|
||||
|
||||
for v in self.cards.itervalues():
|
||||
v.offset = __Fixed(0, 0)
|
||||
|
||||
ui.layer(layer)
|
||||
ui.add(self)
|
||||
ui.close()
|
||||
|
||||
# This hides the table.
|
||||
def hide(self, layer='master'):
|
||||
ui.layer(layer)
|
||||
ui.remove(self)
|
||||
ui.close()
|
||||
|
||||
# This controls sensitivity.
|
||||
def set_sensitive(self, value):
|
||||
self.sensitive = value
|
||||
|
||||
def get_card(self, value):
|
||||
if value not in self.cards:
|
||||
raise Exception("No card has the value %r." % value)
|
||||
|
||||
return self.cards[value]
|
||||
|
||||
# This sets the faceup status of a card.
|
||||
def set_faceup(self, card, faceup=True):
|
||||
self.get_card(card).faceup = faceup
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def get_faceup(self, card):
|
||||
return self.get_card(card).faceup
|
||||
|
||||
# This sets the rotation of a card.
|
||||
def set_rotate(self, card, rotation):
|
||||
__Rotate(self.get_card(card), rotation)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def get_rotate(self, card):
|
||||
return self.get_card(card).rotate.rotate_limit()
|
||||
|
||||
def add_marker(self, card, marker):
|
||||
self.get_card(card).markers.append(marker)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def remove_marker(self, card, marker):
|
||||
self.get_card(card).markers.remove(marker)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
# Called to create a new card.
|
||||
def card(self, value, face, back=None):
|
||||
self.cards[value] = __Card(self, value, face, back)
|
||||
|
||||
# Called to create a new stack.
|
||||
def stack(self, x, y, xoff=0, yoff=0, show=1024, base=None,
|
||||
click=False, drag=DRAG_NONE, drop=False, hidden=False):
|
||||
|
||||
rv = __Stack(self, x, y, xoff, yoff, show, base, click, drag, drop, hidden)
|
||||
|
||||
self.stacks.append(rv)
|
||||
return rv
|
||||
|
||||
# Force a redraw on each interaction.
|
||||
def per_interact(self):
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
self.st = st
|
||||
|
||||
rv = renpy.Render(width, height)
|
||||
|
||||
for s in self.stacks:
|
||||
|
||||
if s.hidden:
|
||||
s.rect = None
|
||||
for c in s.cards:
|
||||
c.rect = None
|
||||
continue
|
||||
|
||||
s.render_to(rv, width, height, st, at)
|
||||
|
||||
for c in s.cards:
|
||||
c.render_to(rv, width, height, st, at)
|
||||
|
||||
return rv
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
self.st = st
|
||||
|
||||
if not self.sensitive:
|
||||
return
|
||||
|
||||
grabbed = renpy.display.focus.get_grab()
|
||||
|
||||
if (grabbed is not None) and (grabbed is not self):
|
||||
return
|
||||
|
||||
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
|
||||
|
||||
if self.click_stack:
|
||||
return
|
||||
|
||||
stack = None
|
||||
card = None
|
||||
|
||||
for s in self.stacks:
|
||||
|
||||
sx, sy, sw, sh = s.rect
|
||||
if sx <= x and sy <= y and sx + sw > x and sy + sh > y:
|
||||
stack = s
|
||||
|
||||
|
||||
for c in s.cards[-s.show:]:
|
||||
if c.rect is None:
|
||||
continue
|
||||
|
||||
cx, cy, cw, ch = c.rect
|
||||
if cx <= x and cy <= y and cx + cw > x and cy + ch > y:
|
||||
card = c
|
||||
stack = c.stack
|
||||
|
||||
if stack is None:
|
||||
return
|
||||
|
||||
# Grab the display.
|
||||
renpy.display.focus.set_grab(self)
|
||||
|
||||
# Don't let the user grab a moving card.
|
||||
if card is not None:
|
||||
xoffset, yoffset = card.offset.offset()
|
||||
if xoffset or yoffset:
|
||||
return
|
||||
|
||||
# Move the stack containing the card to the front.
|
||||
self.stacks.remove(stack)
|
||||
self.stacks.append(stack)
|
||||
|
||||
if stack.click or stack.drag:
|
||||
self.click_card = card
|
||||
self.click_stack = stack
|
||||
|
||||
if card is None or not self.can_drag(self, card.stack, card.value):
|
||||
self.drag_cards = [ ]
|
||||
elif card.stack.drag == DRAG_CARD:
|
||||
self.drag_cards = [ card ]
|
||||
elif card.stack.drag == DRAG_ABOVE:
|
||||
self.drag_cards = [ ]
|
||||
for c in card.stack.cards:
|
||||
if c is card or self.drag_cards:
|
||||
self.drag_cards.append(c)
|
||||
elif card.stack.drag == DRAG_STACK:
|
||||
self.drag_cards = list(card.stack.cards)
|
||||
elif card.stack.drag == DRAG_TOP:
|
||||
if card.stack.cards[-1] is card:
|
||||
self.drag_cards = [ card ]
|
||||
else:
|
||||
self.drag_cards = [ ]
|
||||
|
||||
for c in self.drag_cards:
|
||||
c.offset = __Fixed(0, 0)
|
||||
|
||||
self.click_x = x
|
||||
self.click_y = y
|
||||
self.dragging = False
|
||||
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
if ev.type == pygame.MOUSEMOTION or (ev.type == pygame.MOUSEBUTTONUP and ev.button == 1):
|
||||
|
||||
if abs(x - self.click_x) > 7 or abs(y - self.click_y) > 7:
|
||||
self.dragging = True
|
||||
|
||||
dx = x - self.click_x
|
||||
dy = y - self.click_y
|
||||
|
||||
for c in self.drag_cards:
|
||||
xoffset, yoffset = c.offset.offset()
|
||||
|
||||
cdx = dx - xoffset
|
||||
cdy = dy - yoffset
|
||||
|
||||
c.offset = __Fixed(dx, dy)
|
||||
|
||||
if c.rect:
|
||||
cx, cy, cw, ch = c.rect
|
||||
cx += cdx
|
||||
cy += cdy
|
||||
c.rect = (cx, cy, cw, ch)
|
||||
|
||||
area = 0
|
||||
dststack = None
|
||||
dstcard = None
|
||||
|
||||
for s in self.stacks:
|
||||
if not s.drop:
|
||||
continue
|
||||
|
||||
for c in self.drag_cards:
|
||||
|
||||
if c.stack == s:
|
||||
continue
|
||||
a = __rect_overlap_area(c.rect, s.rect)
|
||||
if a >= area:
|
||||
dststack = s
|
||||
dstcard = None
|
||||
area = a
|
||||
|
||||
for c1 in s.cards:
|
||||
a = __rect_overlap_area(c.rect, c1.rect)
|
||||
if a >= area:
|
||||
dststack = s
|
||||
dstcard = c1
|
||||
area = a
|
||||
|
||||
if area == 0:
|
||||
dststack = None
|
||||
dstcard = None
|
||||
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
if ev.type == pygame.MOUSEMOTION:
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
if ev.type == pygame.MOUSEBUTTONUP and ev.button == 1:
|
||||
|
||||
# Ungrab the display.
|
||||
renpy.display.focus.set_grab(None)
|
||||
|
||||
evt = None
|
||||
|
||||
if self.dragging:
|
||||
if dststack is not None and self.drag_cards:
|
||||
|
||||
evt = CardEvent()
|
||||
evt.type = "drag"
|
||||
evt.table = self
|
||||
evt.stack = self.click_stack
|
||||
evt.card = self.click_card.value
|
||||
evt.drag_cards = [c.value for c in self.drag_cards]
|
||||
evt.drop_stack = dststack
|
||||
if dstcard:
|
||||
evt.drop_card = dstcard.value
|
||||
evt.time = st
|
||||
|
||||
else:
|
||||
|
||||
if self.click_stack.click:
|
||||
|
||||
evt = CardEvent()
|
||||
evt.type = "click"
|
||||
evt.table = self
|
||||
evt.stack = self.click_stack
|
||||
if self.click_card:
|
||||
evt.card = self.click_card.value
|
||||
else:
|
||||
evt.card = None
|
||||
|
||||
evt.time = st
|
||||
|
||||
if (evt.type == self.last_event.type
|
||||
and evt.stack == self.last_event.stack
|
||||
and evt.card == self.last_event.card
|
||||
and evt.time < self.last_event.time + self.doubleclick):
|
||||
|
||||
evt.type = "doubleclick"
|
||||
|
||||
if evt is not None:
|
||||
self.last_event = evt
|
||||
|
||||
for c in self.drag_cards:
|
||||
c.springback()
|
||||
|
||||
self.click_card = None
|
||||
self.click_stack = None
|
||||
self.drag_cards = [ ]
|
||||
|
||||
if evt is not None:
|
||||
return evt
|
||||
else:
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
|
||||
class CardEvent(object):
|
||||
|
||||
def __init__(self):
|
||||
self.type = None
|
||||
self.stack = None
|
||||
self.card = None
|
||||
self.drag_cards = None
|
||||
self.drop_stack = None
|
||||
self.drop_card = None
|
||||
self.time = 0
|
||||
|
||||
# Represents a stack of one or more cards, which can be placed on the
|
||||
# table.
|
||||
class __Stack(object):
|
||||
|
||||
def __init__(
|
||||
self, table,
|
||||
x, y,
|
||||
xoff, yoff,
|
||||
show, base,
|
||||
click, drag, drop,
|
||||
hidden):
|
||||
|
||||
|
||||
# The table this stack belongs to.
|
||||
self.table = table
|
||||
|
||||
# The x and y coordinates of the center of the top card of
|
||||
# this stack.
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
# The offset in the x and y directions of each successive
|
||||
# card.
|
||||
self.xoff = xoff
|
||||
self.yoff = yoff
|
||||
|
||||
# The number of cards to show from this stack. (We show the
|
||||
# last show cards if this is less than the numebr of cards
|
||||
# in the stack.)
|
||||
self.show = show
|
||||
|
||||
# The image that is shown behind the stack. If None, the
|
||||
# background is taken from the table.
|
||||
self.base = base
|
||||
|
||||
# Should we report click events on this stack?
|
||||
self.click = click
|
||||
|
||||
# Should we allow dragging this stack? If so, how?
|
||||
self.drag = drag
|
||||
|
||||
# Should we allow dropping to this stack?
|
||||
self.drop = drop
|
||||
|
||||
# Is this stack hidden?
|
||||
self.hidden = hidden
|
||||
|
||||
# The list of cards in this stack.
|
||||
self.cards = [ ]
|
||||
|
||||
# The rectangle for the background of this effect.
|
||||
self.rect = None
|
||||
|
||||
def insert(self, index, card):
|
||||
card = self.table.get_card(card)
|
||||
|
||||
if card.stack:
|
||||
card.stack.cards.remove(card)
|
||||
|
||||
card.stack = self
|
||||
self.cards.insert(index, card)
|
||||
|
||||
self.table.stacks.remove(self)
|
||||
self.table.stacks.append(self)
|
||||
|
||||
card.springback()
|
||||
|
||||
def append(self, card):
|
||||
if card in self.cards:
|
||||
self.insert(len(self.cards) - 1, card)
|
||||
else:
|
||||
self.insert(len(self.cards), card)
|
||||
|
||||
def remove(self, card):
|
||||
card = self.table.get_card(card)
|
||||
self.cards.remove(card)
|
||||
card.stack = None
|
||||
card.rect = None
|
||||
|
||||
def deal(self):
|
||||
if not self.cards:
|
||||
return None
|
||||
|
||||
card = self.cards[-1]
|
||||
self.remove(card.value)
|
||||
return card.value
|
||||
|
||||
def shuffle(self):
|
||||
renpy.random.shuffle(self.cards)
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cards)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.cards[idx].value
|
||||
|
||||
def __iter__(self):
|
||||
for i in self.cards:
|
||||
yield i.value
|
||||
|
||||
def __contains__(self, item):
|
||||
return self.table.get_card(card) in self.cards
|
||||
|
||||
def render_to(self, rv, width, height, st, at):
|
||||
|
||||
base = self.base or self.table.base
|
||||
|
||||
if base is None:
|
||||
return
|
||||
|
||||
surf = renpy.render(base, width, height, st, at)
|
||||
cw, ch = surf.get_size()
|
||||
|
||||
cx = self.x - cw / 2
|
||||
cy = self.y - ch / 2
|
||||
|
||||
self.rect = (cx, cy, cw, ch)
|
||||
rv.blit(surf, (cx, cy))
|
||||
|
||||
class __Card(object):
|
||||
|
||||
def __init__(self, table, value, face, back):
|
||||
|
||||
# The table this card belongs to.
|
||||
self.table = table
|
||||
|
||||
# The value of this card.
|
||||
self.value = value
|
||||
|
||||
# The face of this card.
|
||||
self.face = renpy.easy.displayable(face)
|
||||
|
||||
# The back of this card. If None, then the back is taken from
|
||||
# the table the card belongs to.
|
||||
self.back = renpy.easy.displayable_or_none(back)
|
||||
|
||||
# Is this card faceup (or face down?)
|
||||
self.faceup = True
|
||||
|
||||
# Object that's called to decide how rotated this card should
|
||||
# be.
|
||||
self.rotate = None
|
||||
|
||||
# A series of highlights that should be drawn over this card.
|
||||
self.highlights = [ ]
|
||||
|
||||
# The stack this card is in.
|
||||
self.stack = None
|
||||
|
||||
# An object that gives the offset of this card relative to
|
||||
# where it would normally be placed.
|
||||
self.offset = __Fixed(0, 0)
|
||||
|
||||
# The rectangle where this card was last drawn to the screen
|
||||
# at.
|
||||
self.rect = None
|
||||
|
||||
__Rotate(self, 0)
|
||||
|
||||
# Returns the base x and y placement of this card.
|
||||
def place(self):
|
||||
s = self.stack
|
||||
offset = max(len(s.cards) - s.show, 0)
|
||||
index = max(s.cards.index(self) - offset, 0)
|
||||
|
||||
return (s.x + s.xoff * index, s.y + s.yoff * index)
|
||||
|
||||
def springback(self):
|
||||
if self.rect is None:
|
||||
self.offset = __Fixed(0, 0)
|
||||
else:
|
||||
self.offset = __Springback(self)
|
||||
|
||||
def render_to(self, rv, width, height, st, at):
|
||||
|
||||
x, y = self.place()
|
||||
xoffset, yoffset = self.offset.offset()
|
||||
x += xoffset
|
||||
y += yoffset
|
||||
|
||||
if self.faceup:
|
||||
d = self.face
|
||||
else:
|
||||
d = self.back or self.table.back
|
||||
|
||||
# TODO: Figure out if we can reuse some of this.
|
||||
|
||||
if self.highlights:
|
||||
d = Fixed(* ([d] + [renpy.easy.displayable(i) for i in self.highlights]))
|
||||
|
||||
r = self.rotate.rotate()
|
||||
if r:
|
||||
d = RotoZoom(r, r, 0, 1, 1, 0)(d)
|
||||
|
||||
surf = renpy.render(d, width, height, st, at)
|
||||
w, h = surf.get_size()
|
||||
|
||||
x -= w / 2
|
||||
y -= h / 2
|
||||
|
||||
self.rect = (x, y, w, h)
|
||||
|
||||
rv.blit(surf, (x, y))
|
||||
|
||||
def __repr__(self):
|
||||
return "<__Card %r>" % self.value
|
||||
|
||||
|
||||
class __Springback(object):
|
||||
|
||||
def __init__(self, card):
|
||||
self.card = card
|
||||
self.table = table = card.table
|
||||
|
||||
self.start = table.st
|
||||
|
||||
cx, cy, cw, ch = self.card.rect
|
||||
x = cx + cw / 2
|
||||
y = cy + ch / 2
|
||||
|
||||
self.startx = x
|
||||
self.starty = y
|
||||
|
||||
def offset(self):
|
||||
|
||||
t = (self.table.st - self.start) / self.table.springback
|
||||
t = min(t, 1.0)
|
||||
|
||||
if t < 1.0:
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
px, py = self.card.place()
|
||||
|
||||
return int((self.startx - px) * (1.0 - t)), int((self.starty - py) * (1.0 - t))
|
||||
|
||||
|
||||
class __Fixed(object):
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def offset(self):
|
||||
return self.x, self.y
|
||||
|
||||
|
||||
class __Rotate(object):
|
||||
def __init__(self, card, amount):
|
||||
|
||||
self.table = table = card.table
|
||||
self.start = table.st
|
||||
|
||||
if card.rotate is None:
|
||||
self.start_rotate = amount
|
||||
else:
|
||||
self.start_rotate = card.rotate.rotate()
|
||||
|
||||
self.end_rotate = amount
|
||||
|
||||
card.rotate = self
|
||||
|
||||
|
||||
def rotate(self):
|
||||
|
||||
if self.start_rotate == self.end_rotate:
|
||||
return self.start_rotate
|
||||
|
||||
t = (self.table.st - self.start) / self.table.springback
|
||||
t = min(t, 1.0)
|
||||
|
||||
if t < 1.0:
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
return self.start_rotate + (self.end_rotate - self.start_rotate) * t
|
||||
|
||||
def rotate_limit(self):
|
||||
return self.end_rotate
|
||||
|
Before Width: | Height: | Size: 140 KiB |
@@ -1,336 +0,0 @@
|
||||
# klondike.rpy - Klondike Solitaire
|
||||
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# This software may be distributed in modified or unmodified form,
|
||||
# provided:
|
||||
#
|
||||
# (1) This complete license notice is retained.
|
||||
#
|
||||
# (2) This software and all software and data files distributed
|
||||
# alongside this software and intended to be loaded in the same
|
||||
# memory space may be redistributed without requirement for
|
||||
# payment, notification, or other forms of compensation.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Commercial licensing for this software is available, please
|
||||
# contact pytom@bishoujo.us for information.
|
||||
|
||||
init python:
|
||||
|
||||
class Klondike(object):
|
||||
|
||||
# We represent a card as a (suit, rank) tuple. The suit is one of the
|
||||
# following four constants, while the rank is 1 for ace, 2 for 2,
|
||||
# ..., 10 for 10, 11 for jack, 12 for queen, 13 for king.
|
||||
CLUB = 0
|
||||
SPADE = 1
|
||||
HEART = 2
|
||||
DIAMOND = 3
|
||||
|
||||
def __init__(self, deal=3):
|
||||
|
||||
# Constants that let us easily change where the game is
|
||||
# located.
|
||||
LEFT=140
|
||||
TOP=58
|
||||
COL_SPACING = 90
|
||||
ROW_SPACING = 120
|
||||
CARD_XSPACING = 20
|
||||
CARD_YSPACING = 30
|
||||
|
||||
# Store the parameters.
|
||||
self.deal = deal
|
||||
|
||||
# Create the table, stock, and waste.
|
||||
self.table = t = Table(base="card/base.png", back="card/back.png")
|
||||
self.stock = t.stack(LEFT, TOP, xoff=0, yoff=0, click=True)
|
||||
self.waste = t.stack(LEFT + COL_SPACING, TOP, xoff=CARD_XSPACING, drag=DRAG_TOP, show=self.deal, click=True)
|
||||
|
||||
# The 4 foundation stacks.
|
||||
self.foundations = [ ]
|
||||
for i in range(0, 4):
|
||||
s = t.stack(LEFT + COL_SPACING * (i + 3), TOP, xoff=0, yoff=0, drag=DRAG_TOP, drop=True)
|
||||
self.foundations.append(s)
|
||||
|
||||
# The 7 tableau stacks.
|
||||
self.tableau = [ ]
|
||||
for i in range(0, 7):
|
||||
s = t.stack(LEFT + COL_SPACING * i, TOP + ROW_SPACING, xoff=0, yoff=CARD_YSPACING, drag=DRAG_ABOVE, click=True, drop=True)
|
||||
self.tableau.append(s)
|
||||
|
||||
# Create the stock and shuffle it.
|
||||
for rank in range(1, 14):
|
||||
for suit in range(0, 4):
|
||||
value = (suit, rank)
|
||||
t.card(value, "card/%d.png" % self.card_num(suit, rank))
|
||||
t.set_faceup(value, False)
|
||||
self.stock.append(value)
|
||||
|
||||
self.stock.shuffle()
|
||||
|
||||
# Deal out the initial tableau.
|
||||
for i in range(0, 7):
|
||||
for j in range(i, 7):
|
||||
c = self.stock.deal()
|
||||
self.tableau[j].append(c)
|
||||
|
||||
# Ensure that the bottom of each tableau is faceup.
|
||||
for i in range(0, 7):
|
||||
if self.tableau[i]:
|
||||
self.table.set_faceup(self.tableau[i][-1], True)
|
||||
|
||||
|
||||
# This figures out the image filename for a given suit and rank.
|
||||
def card_num(self, suit, rank):
|
||||
ranks = [ None, 1, 49, 45, 41, 37, 33, 29, 25, 21, 17, 13, 9, 5 ]
|
||||
return suit + ranks[rank]
|
||||
|
||||
def show(self):
|
||||
self.table.show()
|
||||
|
||||
def hide(self):
|
||||
self.table.hide()
|
||||
|
||||
def tableau_drag(self, evt):
|
||||
|
||||
card = evt.drag_cards[0]
|
||||
cards = evt.drag_cards
|
||||
stack = evt.drop_stack
|
||||
|
||||
csuit, crank = card
|
||||
|
||||
# If the stack is empty, allow a king to be dragged to it.
|
||||
if not stack:
|
||||
if crank == 13:
|
||||
for i in cards:
|
||||
stack.append(i)
|
||||
|
||||
return "tableau_drag"
|
||||
|
||||
# Otherwise, the stack has a bottom card.
|
||||
bottom = stack[-1]
|
||||
bsuit, brank = bottom
|
||||
|
||||
# Figure out which of the stacks are black.
|
||||
cblack = (csuit == self.SPADE) or (csuit == self.CLUB)
|
||||
bblack = (bsuit == self.SPADE) or (bsuit == self.CLUB)
|
||||
|
||||
# Can we legally place the cards?
|
||||
if (bblack != cblack) and (crank == brank - 1):
|
||||
|
||||
# Place the cards:
|
||||
for i in cards:
|
||||
stack.append(i)
|
||||
|
||||
return "tableau_drag"
|
||||
|
||||
return False
|
||||
|
||||
def foundation_drag(self, evt):
|
||||
|
||||
# We can only drag one card at a time to a foundation.
|
||||
if len(evt.drag_cards) != 1:
|
||||
return False
|
||||
|
||||
suit, rank = evt.drag_cards[0]
|
||||
|
||||
# If there is a card on the foundation already, then
|
||||
# check to see if we're dropping then next one in
|
||||
# sequence.
|
||||
if len(evt.drop_stack):
|
||||
dsuit, drank = evt.drop_stack[-1]
|
||||
if suit == dsuit and rank == drank + 1:
|
||||
evt.drop_stack.append(evt.drag_cards[0])
|
||||
return "foundation_drag"
|
||||
|
||||
# Otherwise, make sure we're dropping an ace.
|
||||
else:
|
||||
if rank == 1:
|
||||
evt.drop_stack.append(evt.drag_cards[0])
|
||||
return "foundation_drag"
|
||||
|
||||
return False
|
||||
|
||||
def tableau_doubleclick(self, evt):
|
||||
|
||||
# Make sure that there's at least one card in the stack.
|
||||
if not evt.stack:
|
||||
return False
|
||||
|
||||
# The bottom card in the stack.
|
||||
card = evt.stack[-1]
|
||||
suit, rank = card
|
||||
|
||||
# If the card is an ace, find an open foundation and put it
|
||||
# there.
|
||||
if rank == 1:
|
||||
for i in self.foundations:
|
||||
if not i:
|
||||
i.append(card)
|
||||
break
|
||||
return "foundation_drag"
|
||||
|
||||
# Otherwise, see if there's a foundation where we can put
|
||||
# the card.
|
||||
for i in self.foundations:
|
||||
if not i:
|
||||
continue
|
||||
|
||||
fsuit, frank = i[-1]
|
||||
if suit == fsuit and rank == frank + 1:
|
||||
i.append(card)
|
||||
return "foundation_drag"
|
||||
|
||||
return False
|
||||
|
||||
def stock_click(self, evt):
|
||||
|
||||
# If there are cards in the stock, dispense up to three3
|
||||
# of them.
|
||||
if self.stock:
|
||||
for i in range(0, self.deal):
|
||||
if self.stock:
|
||||
c = self.stock[-1]
|
||||
self.table.set_faceup(c, True)
|
||||
self.waste.append(c)
|
||||
|
||||
return "stock_click"
|
||||
|
||||
# Otherwise, move the contents of the waste to the stock.
|
||||
else:
|
||||
while self.waste:
|
||||
c = self.waste[-1]
|
||||
self.table.set_faceup(c, False)
|
||||
self.stock.append(c)
|
||||
|
||||
return "stock_click"
|
||||
|
||||
|
||||
def interact(self):
|
||||
|
||||
evt = ui.interact()
|
||||
rv = False
|
||||
|
||||
# Check the various events, and dispatch them to the methods
|
||||
# that handle them.
|
||||
if evt.type == "drag":
|
||||
if evt.drop_stack in self.tableau:
|
||||
rv = self.tableau_drag(evt)
|
||||
|
||||
elif evt.drop_stack in self.foundations:
|
||||
rv = self.foundation_drag(evt)
|
||||
|
||||
elif evt.type == "click":
|
||||
if evt.stack == self.stock:
|
||||
rv = self.stock_click(evt)
|
||||
|
||||
elif evt.type == "doubleclick":
|
||||
if (evt.stack in self.tableau) or (evt.stack is self.waste):
|
||||
rv = self.tableau_doubleclick(evt)
|
||||
|
||||
# Ensure that the bottom card in each tableau is faceup.
|
||||
for i in range(0, 7):
|
||||
if self.tableau[i]:
|
||||
self.table.set_faceup(self.tableau[i][-1], True)
|
||||
|
||||
# Check to see if any of the foundations has less than
|
||||
# 13 cards in it. If it does, return False. Otherwise,
|
||||
# return True.
|
||||
for i in self.foundations:
|
||||
if len(i) != 13:
|
||||
return rv
|
||||
|
||||
return "win"
|
||||
|
||||
# Sets things as sensitive (or not).
|
||||
def set_sensitive(self, value):
|
||||
self.table.set_sensitive(value)
|
||||
|
||||
# Utility functions.
|
||||
|
||||
# Is it okay to drag the over card onto under, where under is
|
||||
# part of a tableau.
|
||||
def can_hint(self, under, over):
|
||||
usuit, urank = under
|
||||
osuit, orank = over
|
||||
|
||||
if orank == 1:
|
||||
return False
|
||||
|
||||
ublack = (usuit == self.SPADE) or (usuit == self.CLUB)
|
||||
oblack = (osuit == self.SPADE) or (osuit == self.CLUB)
|
||||
|
||||
if (oblack != ublack) and (orank == urank - 1):
|
||||
return True
|
||||
|
||||
# Returns the first faceup card in the stack.
|
||||
def first_faceup(self, s):
|
||||
for c in s:
|
||||
if self.table.get_faceup(c):
|
||||
return c
|
||||
|
||||
# This tries to find a reasonable hint, and returns it as a
|
||||
# pair of cardnames.
|
||||
def hint(self):
|
||||
|
||||
for i in self.tableau:
|
||||
if not i:
|
||||
continue
|
||||
|
||||
over = self.first_faceup(i)
|
||||
|
||||
for j in self.tableau:
|
||||
if not j or i is j:
|
||||
continue
|
||||
|
||||
under = j[-1]
|
||||
|
||||
if self.can_hint(under, over):
|
||||
return (under, over)
|
||||
|
||||
if self.waste:
|
||||
|
||||
over = self.waste[-1]
|
||||
|
||||
for j in self.tableau:
|
||||
if not j:
|
||||
continue
|
||||
|
||||
under = j[-1]
|
||||
|
||||
if self.can_hint(under, over):
|
||||
return (under, over)
|
||||
|
||||
return None, None
|
||||
|
||||
def card_name(self, c):
|
||||
suit, rank = c
|
||||
|
||||
return [
|
||||
"INVALID",
|
||||
"Ace",
|
||||
"Two",
|
||||
"Three",
|
||||
"four",
|
||||
"Five",
|
||||
"Six",
|
||||
"Seven",
|
||||
"Eight",
|
||||
"Nine",
|
||||
"Ten",
|
||||
"Jack",
|
||||
"Queen",
|
||||
"King" ][rank] + " of " + [
|
||||
"Clubs",
|
||||
"Spades",
|
||||
"Hearts",
|
||||
"Diamonds" ][suit]
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 138 KiB |
@@ -1,247 +0,0 @@
|
||||
## 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 Cardgame Demo"
|
||||
|
||||
#########################################
|
||||
# Layouts
|
||||
|
||||
## This enables the use of an in-game menu that is made out of
|
||||
## buttons.
|
||||
|
||||
layout.button_menu()
|
||||
|
||||
#########################################
|
||||
# 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(
|
||||
|
||||
## The color of an idle widget face.
|
||||
widget = "#7AA27B",
|
||||
|
||||
## The color of a focused widget face.
|
||||
widget_hover = "#A3C7A3",
|
||||
|
||||
## The color of the text in a widget.
|
||||
widget_text = "#CDE0CE",
|
||||
|
||||
## The color of the text in a selected widget. (For
|
||||
## example, the current value of a preference.)
|
||||
widget_selected = "#ffffff",
|
||||
|
||||
## The color of a disabled widget face.
|
||||
disabled = "#426143",
|
||||
|
||||
## The color of disabled widget text.
|
||||
disabled_text = "#819981",
|
||||
|
||||
## The color of informational labels.
|
||||
label = "#ffffff",
|
||||
|
||||
## The color of a frame containing widgets.
|
||||
frame = "#245536",
|
||||
|
||||
## If this is True, the in-game window is rounded. If False,
|
||||
## the in-game window is square.
|
||||
rounded_window = False,
|
||||
|
||||
## 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 = "mainmenu.jpg",
|
||||
|
||||
## 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 = "table.jpg",
|
||||
|
||||
## 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.
|
||||
)
|
||||
|
||||
|
||||
#########################################
|
||||
## These settings let you customize the window containing the
|
||||
## dialogue and narration, by replacing it with an image.
|
||||
|
||||
## The background of the window. In a Frame, the two numbers
|
||||
## are the size of the left/right and top/bottom borders,
|
||||
## respectively.
|
||||
|
||||
# style.window.background = Frame("frame.png", 12, 12)
|
||||
|
||||
## Margin is space surrounding the window, where the background
|
||||
## is not drawn.
|
||||
|
||||
# style.window.left_margin = 6
|
||||
# style.window.right_margin = 6
|
||||
# style.window.top_margin = 6
|
||||
# style.window.bottom_margin = 6
|
||||
|
||||
## Padding is space inside the window, where the background is
|
||||
## drawn.
|
||||
|
||||
# style.window.left_padding = 6
|
||||
# style.window.right_padding = 6
|
||||
# style.window.top_padding = 6
|
||||
# style.window.bottom_padding = 6
|
||||
|
||||
## This is the minimum height of the window, including the margins
|
||||
## and padding.
|
||||
|
||||
# style.window.yminimum = 250
|
||||
|
||||
|
||||
#########################################
|
||||
## This lets you change the placement of the main menu.
|
||||
|
||||
## The way placement works is that we find an anchor point
|
||||
## inside a displayable, and a position (pos) point on the
|
||||
## screen. We then place the displayable so the two points are
|
||||
## at the same place.
|
||||
|
||||
## An anchor/pos can be given as an integer or a floating point
|
||||
## number. If an integer, the number is interpreted as a number
|
||||
## of pixels from the upper-left corner. If a floating point,
|
||||
## the number is interpreted as a fraction of the size of the
|
||||
## displayable or screen.
|
||||
|
||||
# style.mm_menu_frame.xpos = 0.5
|
||||
# style.mm_menu_frame.xanchor = 0.5
|
||||
# style.mm_menu_frame.ypos = 0.75
|
||||
# style.mm_menu_frame.yanchor = 0.5
|
||||
|
||||
|
||||
#########################################
|
||||
## These let you customize the default font used for text in Ren'Py.
|
||||
|
||||
## The file containing the default font.
|
||||
|
||||
# style.default.font = "DejaVuSans.ttf"
|
||||
|
||||
## The default size of text.
|
||||
|
||||
# style.default.size = 22
|
||||
|
||||
## Note that these only change the size of some of the text. Other
|
||||
## buttons have their own styles.
|
||||
|
||||
|
||||
#########################################
|
||||
## These settings let you change some of the sounds that are used by
|
||||
## Ren'Py.
|
||||
|
||||
## Set this to False if the game does not have any sound effects.
|
||||
|
||||
config.has_sound = True
|
||||
|
||||
## Set this to False if the game does not have any music.
|
||||
|
||||
config.has_music = True
|
||||
|
||||
## Set this to False if the game does not have voicing.
|
||||
|
||||
config.has_voice = True
|
||||
|
||||
## Sounds that are used when button and imagemaps are clicked.
|
||||
|
||||
# style.button.activate_sound = "click.wav"
|
||||
# style.imagemap.activate_sound = "click.wav"
|
||||
|
||||
## Sounds that are used when entering and exiting the game menu.
|
||||
|
||||
# config.enter_sound = "click.wav"
|
||||
# config.exit_sound = "click.wav"
|
||||
|
||||
## A sample sound that can be played to check the sound volume.
|
||||
|
||||
# config.sample_sound = "click.wav"
|
||||
|
||||
## Music that is played while the user is at the main menu.
|
||||
|
||||
# config.main_menu_music = "main_menu_theme.ogg"
|
||||
|
||||
|
||||
#########################################
|
||||
## Transitions.
|
||||
|
||||
## Used when entering the game menu from the game.
|
||||
|
||||
config.enter_transition = dissolve
|
||||
|
||||
## Used when exiting the game menu to the game.
|
||||
|
||||
config.exit_transition = dissolve
|
||||
|
||||
## Used between screens of the game menu.
|
||||
|
||||
config.intra_transition = dissolve
|
||||
|
||||
## Used when entering the game menu from the main menu.
|
||||
|
||||
config.main_game_transition = dissolve
|
||||
|
||||
## Used when returning to the main menu from the game.
|
||||
|
||||
config.game_main_transition = dissolve
|
||||
|
||||
## Used when entering the main menu from the splashscreen.
|
||||
|
||||
config.end_splash_transition = dissolve
|
||||
|
||||
## Used when entering the main menu after the game has ended.
|
||||
|
||||
config.end_game_transition = fade
|
||||
|
||||
## Used when a game is loaded.
|
||||
|
||||
config.after_load_transition = dissolve
|
||||
|
||||
|
||||
#########################################
|
||||
## 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
|
||||
|
||||
config.save_directory = "cardgame-11754"
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
# You can place the script of your game in this file.
|
||||
|
||||
init:
|
||||
$ e = Character('Eileen', color="#c8ffc8")
|
||||
|
||||
image eileen happy = "eileen_happy.png"
|
||||
image bg table = "table.jpg"
|
||||
image dim = "#0008"
|
||||
|
||||
# Some styles for show text.
|
||||
$ style.centered_text.drop_shadow = (2, 2)
|
||||
$ style.centered_text.drop_shadow_color = "#000b"
|
||||
|
||||
label start:
|
||||
|
||||
scene bg table
|
||||
|
||||
python:
|
||||
k = Klondike(1)
|
||||
k.set_sensitive(False)
|
||||
k.show()
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
e "Welcome to the cardgame demo. Let's play some solitaire!"
|
||||
|
||||
e "I might show up from time to time to give you some advice, but it's up to you if you want to take it."
|
||||
|
||||
e "Good luck!"
|
||||
|
||||
label continue:
|
||||
|
||||
hide dim
|
||||
hide eileen
|
||||
with dissolve
|
||||
|
||||
label quick_continue:
|
||||
|
||||
$ hint_count = renpy.random.randint(10, 20)
|
||||
|
||||
while True:
|
||||
|
||||
python:
|
||||
|
||||
ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
|
||||
k.set_sensitive(True)
|
||||
event = k.interact()
|
||||
|
||||
if event:
|
||||
renpy.checkpoint()
|
||||
|
||||
if event == "win":
|
||||
jump win
|
||||
|
||||
if event == "tableau_drag" or event == "stock_click":
|
||||
$ hint_count -= 1
|
||||
if hint_count <= 0:
|
||||
jump hint
|
||||
|
||||
label win:
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
"Congratulations!"
|
||||
|
||||
jump newgame
|
||||
|
||||
label giveup:
|
||||
|
||||
$ k.set_sensitive(False)
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
menu:
|
||||
e "Are you sure you want to give up?"
|
||||
|
||||
"Yes":
|
||||
|
||||
"Oh well, better luck next time."
|
||||
|
||||
jump newgame
|
||||
|
||||
"No":
|
||||
|
||||
jump continue
|
||||
|
||||
label newgame:
|
||||
|
||||
menu:
|
||||
e "Would you like to try again?"
|
||||
|
||||
"Yes":
|
||||
pass
|
||||
|
||||
"No":
|
||||
e "Well, I hope to see you again soon."
|
||||
return
|
||||
|
||||
e "Okay, here we go!"
|
||||
|
||||
scene bg table
|
||||
|
||||
python:
|
||||
k = Klondike(1)
|
||||
k.sensitive = False
|
||||
k.show()
|
||||
|
||||
jump continue
|
||||
|
||||
|
||||
label hint:
|
||||
|
||||
$ under, over = k.hint()
|
||||
|
||||
$ print under, over
|
||||
|
||||
if under is None:
|
||||
jump quick_continue
|
||||
|
||||
$ under = k.card_name(under)
|
||||
$ over = k.card_name(over)
|
||||
|
||||
$ k.set_sensitive(False)
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
$ hint = renpy.random.randint(0, 2)
|
||||
|
||||
if hint == 0:
|
||||
e "Maybe put the %(over)s on top of the %(under)s."
|
||||
|
||||
elif hint == 1:
|
||||
e "You can try moving the %(over)s to the %(under)s."
|
||||
|
||||
elif hint == 2:
|
||||
e "I think something can go on the %(under)s."
|
||||
|
||||
jump continue
|
||||
|
||||
|
||||
# This has nothing to do with card games.
|
||||
label splashscreen:
|
||||
|
||||
scene bg table
|
||||
$ renpy.pause(1.0)
|
||||
|
||||
show text "According to legend, prospectors in the klondike would carry with them a deck of cards."
|
||||
with dissolve
|
||||
with Pause(5.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "If they were ever lost, they'd start playing a game of solitaire."
|
||||
with dissolve
|
||||
with Pause(4.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "Without fail, help would soon arrive..."
|
||||
with dissolve
|
||||
with Pause(3.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "... saying \"put the Five of Spades on the Six of Hearts.\""
|
||||
|
||||
with dissolve
|
||||
with Pause(4.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
return
|
||||
|
Before Width: | Height: | Size: 116 KiB |
@@ -54,6 +54,9 @@ init 1210 python hide::
|
||||
if compat(6, 2, 0):
|
||||
config.reject_backslash = False
|
||||
|
||||
if compat(6, 9, 0):
|
||||
style.motion.clear()
|
||||
|
||||
if "Fullscreen" in config.translations:
|
||||
fs = _("Fullscreen")
|
||||
config.translations.setdefault("Fullscreen 4:3", fs + " 4:3")
|
||||
|
||||
@@ -62,60 +62,69 @@ init -1110 python:
|
||||
return .5 - math.cos(math.pi * x) / 2.0
|
||||
|
||||
# This defines a family of move transitions.
|
||||
def move_transitions(prefix, delay, time_warp=None, in_time_warp=None, out_time_warp=None, old=False):
|
||||
def move_transitions(prefix, delay, time_warp=None, in_time_warp=None, out_time_warp=None, old=False, layers=[ 'master' ], **kwargs):
|
||||
moves = {
|
||||
"" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs)),
|
||||
|
||||
"inright" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((1.0, None, 0.0, None), time_warp=in_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
enter_factory=MoveIn((1.0, None, 0.0, None), time_warp=in_time_warp, **kwargs)),
|
||||
|
||||
"inleft" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((0.0, None, 1.0, None), time_warp=in_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
enter_factory=MoveIn((0.0, None, 1.0, None), time_warp=in_time_warp, **kwargs)),
|
||||
|
||||
"intop" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((None, 0.0, None, 1.0), time_warp=in_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
enter_factory=MoveIn((None, 0.0, None, 1.0), time_warp=in_time_warp, **kwargs)),
|
||||
|
||||
"inbottom" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((None, 1.0, None, 0.0), time_warp=in_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
enter_factory=MoveIn((None, 1.0, None, 0.0), time_warp=in_time_warp, **kwargs)),
|
||||
|
||||
"outright" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((1.0, None, 0.0, None), time_warp=out_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
leave_factory=MoveOut((1.0, None, 0.0, None), time_warp=out_time_warp, **kwargs)),
|
||||
|
||||
"outleft" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((0.0, None, 1.0, None), time_warp=out_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
leave_factory=MoveOut((0.0, None, 1.0, None), time_warp=out_time_warp, **kwargs)),
|
||||
|
||||
"outtop" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((None, 0.0, None, 1.0), time_warp=out_time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
leave_factory=MoveOut((None, 0.0, None, 1.0), time_warp=out_time_warp, **kwargs)),
|
||||
|
||||
"outbottom" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((None, 1.0, None, 0.0), time_warp=time_warp)),
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp, **kwargs),
|
||||
leave_factory=MoveOut((None, 1.0, None, 0.0), time_warp=time_warp, **kwargs)),
|
||||
}
|
||||
|
||||
for k, v in moves.iteritems():
|
||||
|
||||
@@ -196,6 +196,9 @@ label _style_hierarchy:
|
||||
jump _developer_screen
|
||||
|
||||
|
||||
init -1050 python:
|
||||
config.missing_background = "black"
|
||||
|
||||
init 1050 python:
|
||||
|
||||
if renpy.game.options.remote:
|
||||
@@ -214,4 +217,73 @@ init 1050 python:
|
||||
config.underlay.append(Remote())
|
||||
del Remote
|
||||
|
||||
|
||||
|
||||
if config.developer:
|
||||
|
||||
# This is used to indicate that a scene has just occured,
|
||||
# and so if the next thing is a missing_show, we should
|
||||
# blank the screen.
|
||||
__missing_scene = False
|
||||
|
||||
# This returns the __missing dictionary from the current
|
||||
# context object.
|
||||
def __missing():
|
||||
try:
|
||||
return renpy.context().__missing
|
||||
except AttributeError:
|
||||
rv = dict()
|
||||
renpy.context().__missing = rv
|
||||
return rv
|
||||
|
||||
def __missing_show_callback(name, what, layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
if __missing_scene:
|
||||
renpy.show(name, what=config.missing_background)
|
||||
__missing_scene = False
|
||||
|
||||
what = " ".join(what).replace("{", "{{")
|
||||
__missing()[name[0]] = what
|
||||
return True
|
||||
|
||||
def __missing_hide_callback(name, layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = False
|
||||
|
||||
__missing().pop(name[0], None)
|
||||
return True
|
||||
|
||||
def __missing_scene_callback(layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = True
|
||||
__missing().clear()
|
||||
|
||||
return True
|
||||
|
||||
def __missing_overlay():
|
||||
missing = __missing()
|
||||
|
||||
if not missing:
|
||||
return
|
||||
|
||||
ui.vbox(xalign=0.5, yalign=0.0)
|
||||
ui.text(_("Undefined Images"), xalign=0.5)
|
||||
|
||||
for what in sorted(missing.values()):
|
||||
ui.text(what, xalign=0.5)
|
||||
|
||||
ui.close()
|
||||
|
||||
|
||||
config.missing_scene = __missing_scene_callback
|
||||
config.missing_show = __missing_show_callback
|
||||
config.missing_hide = __missing_hide_callback
|
||||
config.overlay_functions.append(__missing_overlay)
|
||||
|
||||
@@ -18,7 +18,7 @@ init -1105 python:
|
||||
|
||||
# This takes care of actually displaying button menus.
|
||||
def _display_button_menu(menuitems):
|
||||
|
||||
|
||||
narration = [ s for s, i in menuitems if i is None and s ]
|
||||
menuitems = [ (s, i) for s, i in menuitems if i is not None or not s ]
|
||||
|
||||
|
||||
@@ -69,6 +69,12 @@ init -1180 python:
|
||||
|
||||
config.with_callback = _default_with_callback
|
||||
|
||||
|
||||
def _default_empty_window():
|
||||
store.narrator("", interact=False)
|
||||
|
||||
config.empty_window = _default_empty_window
|
||||
|
||||
style.skip_indicator = Style(style.default, heavy=True, help='The skip indicator.')
|
||||
style.skip_indicator.xpos = 10
|
||||
style.skip_indicator.ypos = 10
|
||||
@@ -111,16 +117,35 @@ init -1180 python:
|
||||
renpy.jump("_noisy_return")
|
||||
else:
|
||||
renpy.restart_interaction()
|
||||
|
||||
config.help = None
|
||||
|
||||
def _help():
|
||||
if not config.help:
|
||||
return
|
||||
|
||||
if renpy.has_label(config.help):
|
||||
renpy.call_in_new_context(config.help)
|
||||
return
|
||||
|
||||
_preferences.fullscreen = False
|
||||
|
||||
import webbrowser
|
||||
webbrowser.open_new("file:///" + config.basedir + "/" + config.help)
|
||||
|
||||
|
||||
init -1180 python hide:
|
||||
|
||||
# Called to make a screenshot happen.
|
||||
def screenshot():
|
||||
import os.path
|
||||
import os
|
||||
|
||||
pattern = os.environ.get("RENPY_SCREENSHOT_PATTERN", "screenshot%04d.png")
|
||||
|
||||
i = 1
|
||||
while True:
|
||||
fn = "screenshot%04d.png" % i
|
||||
fn = pattern % i
|
||||
if not os.path.exists(fn):
|
||||
break
|
||||
i += 1
|
||||
@@ -143,7 +168,6 @@ init -1180 python hide:
|
||||
|
||||
toggle_skipping()
|
||||
|
||||
|
||||
def fast_skip():
|
||||
if config.fast_skipping or config.developer:
|
||||
config.skipping = "fast"
|
||||
@@ -163,8 +187,9 @@ init -1180 python hide:
|
||||
|
||||
filename, line = renpy.get_filename_line()
|
||||
renpy.launch_editor([ filename ], line)
|
||||
|
||||
# The default keymap.
|
||||
|
||||
# The default keymap. We might also want to put some of this into
|
||||
# the launcher.
|
||||
km = renpy.Keymap(
|
||||
rollback = renpy.rollback,
|
||||
screenshot = screenshot,
|
||||
@@ -178,6 +203,9 @@ init -1180 python hide:
|
||||
dump_styles = dump_styles,
|
||||
reload_game = reload_game,
|
||||
developer = renpy.curried_call_in_new_context("_developer"),
|
||||
quit = renpy.quit_event,
|
||||
iconify = renpy.iconify,
|
||||
help = _help,
|
||||
)
|
||||
|
||||
config.underlay = [ km ]
|
||||
@@ -262,7 +290,7 @@ label _hide_windows:
|
||||
python:
|
||||
_windows_hidden = True
|
||||
ui.saybehavior(dismiss=['dismiss', 'hide_windows'])
|
||||
ui.interact(suppress_overlay=True)
|
||||
ui.interact(suppress_overlay=True, suppress_window=True)
|
||||
_windows_hidden = False
|
||||
|
||||
return
|
||||
@@ -487,7 +515,7 @@ init 1180 python:
|
||||
|
||||
label _enter_menu:
|
||||
python hide:
|
||||
renpy.movie_stop()
|
||||
renpy.movie_stop(only_fullscreen=True)
|
||||
renpy.take_screenshot((config.thumbnail_width, config.thumbnail_height))
|
||||
|
||||
renpy.context()._menu = True
|
||||
@@ -496,9 +524,11 @@ label _enter_menu:
|
||||
renpy.context().main_menu = False
|
||||
renpy.context_dynamic("main_menu")
|
||||
renpy.context_dynamic("_window_subtitle")
|
||||
|
||||
renpy.context_dynamic("_window")
|
||||
|
||||
store.main_menu = False
|
||||
store._window_subtitle = config.menu_window_subtitle
|
||||
store._window = False
|
||||
|
||||
store.mouse_visible = True
|
||||
store.suppress_overlay = True
|
||||
@@ -577,7 +607,7 @@ label _return:
|
||||
|
||||
if renpy.context().main_menu:
|
||||
$ renpy.transition(config.game_main_transition)
|
||||
jump _main_menu
|
||||
jump _main_menu_screen
|
||||
|
||||
$ renpy.transition(config.exit_transition)
|
||||
|
||||
@@ -652,12 +682,6 @@ label _start:
|
||||
|
||||
$ renpy.block_rollback()
|
||||
|
||||
python hide:
|
||||
for i in range(0, 7):
|
||||
# renpy.music.stop(channel=i)
|
||||
# renpy.sound.stop(channel=i)
|
||||
pass
|
||||
|
||||
if config.main_menu_music:
|
||||
$ renpy.music.play(config.main_menu_music, if_changed=True)
|
||||
else:
|
||||
@@ -673,15 +697,19 @@ label _start:
|
||||
jump expression _restart[1]
|
||||
|
||||
label _invoke_main_menu:
|
||||
|
||||
$ renpy.call_in_new_context("_enter_main_menu")
|
||||
|
||||
if _restart:
|
||||
$ renpy.call_in_new_context(_restart[2])
|
||||
else:
|
||||
$ renpy.call_in_new_context("_main_menu")
|
||||
|
||||
|
||||
# If the main menu returns, then start the game.
|
||||
jump start
|
||||
|
||||
# At this point, we've been switched into a new context. So we
|
||||
# initialize it.
|
||||
label _enter_main_menu:
|
||||
label _main_menu(_main_menu_screen="_main_menu_screen"):
|
||||
|
||||
call _enter_menu from _call__enter_menu_1
|
||||
|
||||
@@ -691,9 +719,11 @@ label _enter_main_menu:
|
||||
|
||||
renpy.context().main_menu = True
|
||||
store.main_menu = True
|
||||
|
||||
jump expression _main_menu_screen
|
||||
|
||||
# This is called to show the main menu to the user.
|
||||
label _main_menu:
|
||||
label _main_menu_screen:
|
||||
|
||||
# Let the user completely override the main menu. (But please note
|
||||
# it still lives in the menu context, rather than the game context.)
|
||||
|
||||
@@ -12,9 +12,10 @@ init -1150 python:
|
||||
|
||||
config.main_menu = [
|
||||
(u"Start Game", "start", "True"),
|
||||
(u"Continue Game", _intra_jumps("load_screen", "main_game_transition"), "True"),
|
||||
(u"Load Game", _intra_jumps("load_screen", "main_game_transition"), "True"),
|
||||
(u"Preferences", _intra_jumps("preferences_screen", "main_game_transition"), "True"),
|
||||
(u"Quit", ui.jumps("_quit"), "True")
|
||||
(u"Help", _help, "True", "config.help"),
|
||||
(u"Quit", ui.jumps("_quit"), "True"),
|
||||
]
|
||||
|
||||
config.game_menu = [
|
||||
@@ -23,10 +24,13 @@ init -1150 python:
|
||||
( "save", u"Save Game", _intra_jumps("save_screen", "intra_transition"), 'not main_menu' ),
|
||||
( "load", u"Load Game", _intra_jumps("load_screen", "intra_transition"), 'True'),
|
||||
( None, u"Main Menu", ui.callsinnewcontext("_main_menu_prompt"), 'not main_menu' ),
|
||||
( "help", u"Help", _help, "True", "config.help"),
|
||||
( None, u"Quit", ui.callsinnewcontext("_quit_prompt"), 'True' ),
|
||||
]
|
||||
|
||||
label _quit_prompt:
|
||||
$ renpy.loadsave.force_autosave()
|
||||
|
||||
if layout.yesno_prompt(None, u"Are you sure you want to quit?"):
|
||||
jump _quit
|
||||
else:
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
# This file contains code that sets up the various mixers, based on how
|
||||
# the user sets config.has_music, .has_sound, and .has_voice.
|
||||
|
||||
init -1130:
|
||||
|
||||
init -1130 python hide:
|
||||
|
||||
# Set to true in the very unlikely event you want to manually init
|
||||
# the sound system.
|
||||
$ config.force_sound = False
|
||||
config.force_sound = False
|
||||
|
||||
# basics: True if the game will have music.
|
||||
$ config.has_music = True
|
||||
config.has_music = True
|
||||
|
||||
# basics: True if the game will have sound effects.
|
||||
$ config.has_sound = True
|
||||
config.has_sound = True
|
||||
|
||||
# Register 8 channels by default, for compatiblity with older version
|
||||
# of Ren'Py.
|
||||
for i in xrange(0, 8):
|
||||
renpy.music.register_channel(i)
|
||||
|
||||
renpy.music.register_channel("movie", "music", False, stop_on_mute=False)
|
||||
|
||||
# Set up default names for some of the channels.
|
||||
renpy.music.alias_channel(0, "sound")
|
||||
renpy.music.alias_channel(7, "music")
|
||||
renpy.music.alias_channel(2, "voice")
|
||||
|
||||
init 1130:
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ init -1100 python:
|
||||
return s
|
||||
|
||||
def nvl_show_core():
|
||||
|
||||
|
||||
if renpy.in_rollback():
|
||||
nvl_window = __s(style.nvl_window)['rollback']
|
||||
nvl_vbox = __s(style.nvl_vbox)['rollback']
|
||||
@@ -99,8 +99,14 @@ init -1100 python:
|
||||
rv = config.nvl_show_display_say(who, what, variant=nvl_variant, **kw)
|
||||
|
||||
ui.close()
|
||||
|
||||
renpy.shown_window()
|
||||
|
||||
return rv
|
||||
|
||||
def nvl_window():
|
||||
nvl_show_core()
|
||||
|
||||
def nvl_show(with_):
|
||||
nvl_show_core()
|
||||
renpy.with_statement(with_)
|
||||
@@ -208,7 +214,6 @@ init -1100 python:
|
||||
kind=adv)
|
||||
|
||||
def nvl_clear():
|
||||
|
||||
store.nvl_list = [ ]
|
||||
|
||||
# Run clear at the start of the game.
|
||||
@@ -219,6 +224,10 @@ init -1100 python:
|
||||
if nvl_list is None:
|
||||
store.nvl_list = [ ]
|
||||
|
||||
ui.layer("transient")
|
||||
ui.clear()
|
||||
ui.close()
|
||||
|
||||
ui.window(style=__s(style.nvl_window))
|
||||
ui.vbox(style=__s(style.nvl_vbox))
|
||||
|
||||
|
||||
@@ -164,7 +164,6 @@ python early hide:
|
||||
|
||||
renpy.music.queue(eval(p["file"]), channel=channel)
|
||||
|
||||
|
||||
renpy.statements.register('queue music',
|
||||
parse=parse_queue_music,
|
||||
execute=execute_queue_music,
|
||||
@@ -254,10 +253,131 @@ python early hide:
|
||||
parse=parse_stop_music,
|
||||
execute=execute_stop_sound)
|
||||
|
||||
|
||||
# Generic play/queue/stop statements. These take a channel name as
|
||||
# the second thing.
|
||||
|
||||
def parse_play_generic(l, parse_play_music=parse_play_music):
|
||||
channel = l.name()
|
||||
|
||||
if channel is None:
|
||||
renpy.error('play requires a channel')
|
||||
|
||||
rv = parse_play_music(l)
|
||||
if rv["channel"] is None:
|
||||
rv["channel"] = repr(channel)
|
||||
|
||||
return rv
|
||||
|
||||
def parse_queue_generic(l, parse_queue_music=parse_queue_music):
|
||||
channel = l.name()
|
||||
|
||||
if channel is None:
|
||||
renpy.error('queue requires a channel')
|
||||
|
||||
rv = parse_queue_music(l)
|
||||
if rv["channel"] is None:
|
||||
rv["channel"] = repr(channel)
|
||||
|
||||
return rv
|
||||
|
||||
def parse_stop_generic(l, parse_stop_music=parse_stop_music):
|
||||
channel = l.name()
|
||||
|
||||
if channel is None:
|
||||
renpy.error('stop requires a channel')
|
||||
|
||||
rv = parse_stop_music(l)
|
||||
if rv["channel"] is None:
|
||||
rv["channel"] = repr(channel)
|
||||
|
||||
return rv
|
||||
|
||||
def lint_play_generic(p, lint_play_music=lint_play_music):
|
||||
channel = eval(p["channel"])
|
||||
|
||||
if not renpy.music.channel_defined(channel):
|
||||
renpy.error("channel %r is not defined" % channel)
|
||||
|
||||
lint_play_music(p)
|
||||
|
||||
def lint_stop_generic(p):
|
||||
channel = eval(p["channel"])
|
||||
|
||||
if not renpy.music.channel_defined(channel):
|
||||
renpy.error("channel %r is not defined" % channel)
|
||||
|
||||
renpy.statements.register('play',
|
||||
parse=parse_play_generic,
|
||||
execute=execute_play_music,
|
||||
predict=predict_play_music,
|
||||
lint=lint_play_generic)
|
||||
|
||||
renpy.statements.register('queue',
|
||||
parse=parse_queue_generic,
|
||||
execute=execute_queue_music,
|
||||
lint=lint_play_generic)
|
||||
|
||||
renpy.statements.register('stop',
|
||||
parse=parse_stop_generic,
|
||||
execute=execute_stop_music,
|
||||
lint=lint_stop_generic)
|
||||
|
||||
|
||||
# The "window show" and "window hide" statements.
|
||||
def parse_window(l):
|
||||
p = l.simple_expression()
|
||||
if not l.eol():
|
||||
renpy.error('expected end of line')
|
||||
|
||||
return p
|
||||
|
||||
def lint_window(p):
|
||||
if p is not None:
|
||||
_try_eval(p, 'window transition')
|
||||
|
||||
def execute_window_show(p):
|
||||
if store._window:
|
||||
return
|
||||
|
||||
if p is not None:
|
||||
trans = eval(p)
|
||||
else:
|
||||
trans = config.window_show_transition
|
||||
|
||||
renpy.with_statement(None)
|
||||
store._window = True
|
||||
renpy.with_statement(trans)
|
||||
|
||||
def execute_window_hide(p):
|
||||
if not _window:
|
||||
return
|
||||
|
||||
if p is not None:
|
||||
trans = eval(p)
|
||||
else:
|
||||
trans = config.window_hide_transition
|
||||
|
||||
renpy.with_statement(None)
|
||||
store._window = False
|
||||
renpy.with_statement(trans)
|
||||
|
||||
renpy.statements.register('window show',
|
||||
parse=parse_window,
|
||||
execute=execute_window_show,
|
||||
lint=lint_window)
|
||||
|
||||
renpy.statements.register('window hide',
|
||||
parse=parse_window,
|
||||
execute=execute_window_hide,
|
||||
lint=lint_window)
|
||||
|
||||
|
||||
init -1200 python:
|
||||
|
||||
config.window_show_transition = None
|
||||
config.window_hide_transition = None
|
||||
|
||||
def _try_eval(e, what):
|
||||
try:
|
||||
return eval(e)
|
||||
|
||||
@@ -33,6 +33,7 @@ init -1200 python hide:
|
||||
style.image_placement = Style(style.default, help='default placement of images on the screen')
|
||||
style.image = Style(style.default, help="default style of images")
|
||||
|
||||
style.motion = Style(style.default, help="default style of motions and zooms.")
|
||||
style.animation = Style(style.default, help="default style of animations.")
|
||||
|
||||
style.say_label = Style(style.default, help='the name of the character speaking dialogue.')
|
||||
@@ -68,6 +69,7 @@ init -1200 python hide:
|
||||
style.hyperlink_text = Style(style.default, help='hyperlinked text')
|
||||
|
||||
style.viewport = Style(style.default, help='default style of viewports')
|
||||
style.transform = Style(style.motion, help='default style of transforms')
|
||||
|
||||
style.list = Style(style.default)
|
||||
style.list_box = Style(style.vbox)
|
||||
@@ -132,8 +134,10 @@ init -1090 python:
|
||||
style.default.strikethrough = False
|
||||
style.default.drop_shadow = None
|
||||
style.default.drop_shadow_color = (0, 0, 0, 255)
|
||||
style.default.outlines = [ ]
|
||||
style.default.minwidth = 0
|
||||
style.default.textalign = 0
|
||||
style.default.text_align = 0
|
||||
style.default.justify = False
|
||||
style.default.text_y_fudge = 0
|
||||
style.default.first_indent = 0
|
||||
style.default.rest_indent = 0
|
||||
@@ -164,7 +168,8 @@ init -1090 python:
|
||||
style.default.ymaximum = None
|
||||
style.default.xoffset = 0
|
||||
style.default.yoffset = 0
|
||||
|
||||
style.default.subpixel = False
|
||||
|
||||
# Sound properties.
|
||||
style.default.sound = None
|
||||
|
||||
@@ -185,6 +190,7 @@ init -1090 python:
|
||||
style.default.left_gutter = 0
|
||||
style.default.right_gutter = 0
|
||||
style.default.thumb_offset = 0
|
||||
style.default.unscrollable = None
|
||||
|
||||
# Misc.
|
||||
style.default.activate_sound = None
|
||||
@@ -194,6 +200,10 @@ init -1090 python:
|
||||
style.hbox.box_layout = 'horizontal'
|
||||
style.vbox.box_layout = 'vertical'
|
||||
|
||||
# Motions, zooms, rotozooms, and transforms.
|
||||
style.motion.xanchor = 0
|
||||
style.motion.yanchor = 0
|
||||
|
||||
# Windows.
|
||||
style.window.background = Solid((0, 0, 0, 192))
|
||||
style.window.xpadding = 6
|
||||
@@ -260,6 +270,9 @@ init -1090 python:
|
||||
# Viewport
|
||||
style.viewport.clipping = True
|
||||
|
||||
# Transform
|
||||
style.transform.subpixel = True
|
||||
|
||||
# Menu windows.
|
||||
style.mm_root.background = "#000"
|
||||
style.mm_root.xfill = True
|
||||
|
||||
@@ -298,13 +298,19 @@ init -1110 python hide:
|
||||
|
||||
# Compat for the old roundrect theme.
|
||||
window = None,
|
||||
button_menu = True,
|
||||
button_menu = None,
|
||||
rounded_window = True,
|
||||
outline_bars = False,
|
||||
|
||||
mm_root = None,
|
||||
gm_root = None):
|
||||
|
||||
if button_menu is None:
|
||||
if (config.script_version is not None) and (config.script_version < (6, 9, 0)):
|
||||
button_menu = True
|
||||
else:
|
||||
button_menu = False
|
||||
|
||||
layout.defaults()
|
||||
|
||||
if config.screen_width <= 640:
|
||||
@@ -480,14 +486,6 @@ init -1110 python hide:
|
||||
style.gm_root.background = "#e9d8bc"
|
||||
|
||||
|
||||
theme.outline_drop_shadow = [
|
||||
(0, -2),
|
||||
(-1, -1), (0, -1), (1, -1),
|
||||
(-2, 0), (-1, 0), (1, 0), (2, 0),
|
||||
(-1, 1), (0, 1), (1, 1),
|
||||
(0, 2)
|
||||
]
|
||||
|
||||
@theme
|
||||
def outline_frames():
|
||||
theme.clear_frames()
|
||||
@@ -507,12 +505,11 @@ init -1110 python hide:
|
||||
|
||||
style.button_text.size = text_size
|
||||
style.button_text.color = inside
|
||||
style.button_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.button_text.drop_shadow_color = idle
|
||||
style.button_text.hover_drop_shadow_color = hover
|
||||
style.button_text.selected_drop_shadow_color = selected
|
||||
style.button_text.selected_hover_drop_shadow_color = hover
|
||||
style.button_text.insensitive_drop_shadow_color = insensitive
|
||||
style.button_text.outlines = [ (2, idle) ]
|
||||
style.button_text.hover_outlines = [ (2, hover) ]
|
||||
style.button_text.selected_outlines = [ (2, selected) ]
|
||||
style.button_text.selected_hover_outlines = [ (2, hover) ]
|
||||
style.button_text.insensitive_outlines = [ (2, insensitive) ]
|
||||
|
||||
|
||||
@theme
|
||||
@@ -534,12 +531,12 @@ init -1110 python hide:
|
||||
|
||||
style.large_button_text.size = text_size
|
||||
style.large_button_text.color = inside
|
||||
style.large_button_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.large_button_text.drop_shadow_color = idle
|
||||
style.large_button_text.hover_drop_shadow_color = hover
|
||||
style.large_button_text.selected_drop_shadow_color = selected
|
||||
style.large_button_text.selected_hover_drop_shadow_color = hover
|
||||
style.large_button_text.insensitive_drop_shadow_color = insensitive
|
||||
|
||||
style.large_button_text.outlines = [ (2, idle) ]
|
||||
style.large_button_text.hover_outlines = [ (2, hover) ]
|
||||
style.large_button_text.selected_outlines = [ (2, selected) ]
|
||||
style.large_button_text.selected_hover_outlines = [ (2, hover) ]
|
||||
style.large_button_text.insensitive_outlines = [ (2, insensitive) ]
|
||||
|
||||
@theme
|
||||
def outline_prompts(
|
||||
@@ -550,8 +547,7 @@ init -1110 python hide:
|
||||
theme.clear_prompts()
|
||||
|
||||
style.prompt_text.color = inside
|
||||
style.prompt_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.prompt_text.drop_shadow_color = prompt
|
||||
style.prompt_text.outlines = [ (2, prompt) ]
|
||||
style.prompt_text.size = text_size
|
||||
|
||||
@theme
|
||||
@@ -563,8 +559,7 @@ init -1110 python hide:
|
||||
theme.clear_labels()
|
||||
|
||||
style.label_text.color = inside
|
||||
style.label_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.label_text.drop_shadow_color = label
|
||||
style.label_text.outlines = [ (2, label) ]
|
||||
style.label_text.size = text_size
|
||||
|
||||
@theme
|
||||
@@ -622,8 +617,6 @@ init -1110 python hide:
|
||||
style.vscrollbar.hover_bottom_bar = Frame(color("vbar", hover), 0, 0)
|
||||
style.vscrollbar.hover_thumb = Frame(color("circle", hover), 0, 7)
|
||||
|
||||
|
||||
|
||||
@theme
|
||||
def outline(
|
||||
inside="#fff",
|
||||
|
||||
@@ -52,7 +52,7 @@ init -1120:
|
||||
# This is called on each interaction, to ensure that the
|
||||
# appropriate voice file is played for the user.
|
||||
def voice_interact():
|
||||
|
||||
|
||||
if not config.has_voice:
|
||||
return
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ init python:
|
||||
style.prefs_column.box_spacing = 5
|
||||
style.prefs_frame.top_margin = 5
|
||||
|
||||
style.prefs_left.xpos = 100
|
||||
style.prefs_left.xpos = 110
|
||||
style.prefs_center.xpos = 320
|
||||
style.prefs_right.xpos = 530
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ init python:
|
||||
|
||||
class _ImageMapper(object):
|
||||
|
||||
def __init__(self, ground, idle, hover, selected_idle, selected_hover, hotspots):
|
||||
def __init__(self, screen, ground, idle, hover, selected_idle, selected_hover, hotspots):
|
||||
|
||||
self.idle = idle
|
||||
self.hover = hover
|
||||
@@ -13,10 +13,29 @@ init python:
|
||||
for (x1, y1, x2, y2, name) in hotspots:
|
||||
self.hotspots[name] = (x1, y1, x2, y2)
|
||||
|
||||
# Display the layout navigation only if there are no
|
||||
# game menu buttons defined.
|
||||
for i in config.game_menu:
|
||||
if i[1] in self.hotspots:
|
||||
break
|
||||
else:
|
||||
layout.navigation(screen)
|
||||
|
||||
ui.fixed(style='imagemap')
|
||||
ui.image(ground)
|
||||
|
||||
# Display any navigation buttons that exist.
|
||||
for e in config.game_menu:
|
||||
screen_ = e[0]
|
||||
name = e[1]
|
||||
act = e[2]
|
||||
enable = e[3]
|
||||
|
||||
if not eval(enable):
|
||||
continue
|
||||
|
||||
self.button(name, act, screen == screen_)
|
||||
|
||||
def button(self, name, clicked, selected):
|
||||
|
||||
if name not in self.hotspots:
|
||||
@@ -32,8 +51,8 @@ init python:
|
||||
hover = self.selected_hover
|
||||
else:
|
||||
idle = self.idle
|
||||
hover = self.selected_hover
|
||||
|
||||
hover = self.hover
|
||||
|
||||
ui.imagebutton(
|
||||
LiveCrop((x1, y1, (x2 - x1), (y2 - y1)), idle),
|
||||
LiveCrop((x1, y1, (x2 - x1), (y2 - y1)), hover),
|
||||
|
||||
@@ -233,10 +233,8 @@ init python:
|
||||
|
||||
__scratch.file_picker_page = fpp
|
||||
|
||||
# Show navigation
|
||||
layout.navigation(screen)
|
||||
|
||||
ime = _ImageMapper(
|
||||
screen,
|
||||
config.load_save_ground,
|
||||
config.load_save_idle,
|
||||
config.load_save_hover,
|
||||
|
||||
@@ -44,9 +44,12 @@ label main_menu_screen:
|
||||
if isinstance(act, basestring):
|
||||
act = ui.jumpsoutofcontext(act)
|
||||
act()
|
||||
|
||||
break
|
||||
else:
|
||||
ui.jumpsoutofcontext(rv)()
|
||||
|
||||
|
||||
jump main_menu_screen
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,9 +39,8 @@ init python:
|
||||
|
||||
def __show_preferences():
|
||||
|
||||
layout.navigation("prefs")
|
||||
|
||||
ime = _ImageMapper(
|
||||
"prefs",
|
||||
config.preferences_ground,
|
||||
config.preferences_idle,
|
||||
config.preferences_hover,
|
||||
|
||||
@@ -17,9 +17,8 @@ init python hide:
|
||||
def yesno_prompt(screen, message):
|
||||
renpy.transition(config.intra_transition)
|
||||
|
||||
layout.navigation(screen)
|
||||
|
||||
ime = _ImageMapper(
|
||||
screen,
|
||||
config.yesno_prompt_ground,
|
||||
config.yesno_prompt_idle,
|
||||
config.yesno_prompt_hover,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist/console.exe
|
||||
@@ -1,25 +0,0 @@
|
||||
# This file contains logic for detecting an editor, and for selecting
|
||||
# the default editor.
|
||||
|
||||
init:
|
||||
python hide:
|
||||
import os
|
||||
import sys
|
||||
|
||||
if not config.editor:
|
||||
|
||||
editor = config.renpy_base + "/jedit/jedit.jar"
|
||||
editor = renpy.shell_escape(editor)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
config.editor = 'javaw.exe -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
config.editor_transient = 'javaw.exe -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
else:
|
||||
config.editor = 'java -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
config.editor_transient = 'java -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
|
||||
|
||||
if config.editor:
|
||||
os.environ['RENPY_EDITOR'] = config.editor
|
||||
if config.editor_transient:
|
||||
os.environ['RENPY_EDITOR_TRANSIENT'] = config.editor_transient
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
init -50:
|
||||
$ config.script_version = (6, 7, 1)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../help.html
|
||||
|
Before Width: | Height: | Size: 19 KiB |
@@ -6,6 +6,8 @@ init:
|
||||
image logo crop = im.Crop("logo.png", 0, 0, 100, 307)
|
||||
|
||||
image logo scale = im.Scale("logo.png", 100, 150)
|
||||
|
||||
image logo factorscale = im.FactorScale("logo.png", 1.5, 1.5)
|
||||
|
||||
image logo composite = im.Composite((200, 407),
|
||||
(0, 0), "logo.png",
|
||||
@@ -101,8 +103,13 @@ label demo_imageops:
|
||||
show logo scale at logopos
|
||||
with dissolve
|
||||
|
||||
e "The im.Scale operation lets us change the size of images."
|
||||
e "The im.Scale operation lets us scale an image to a particular size."
|
||||
|
||||
show logo factorscale at logopos
|
||||
with dissolve
|
||||
|
||||
e "im.FactorScale lets us do the same thing, except to a factor of the original size."
|
||||
|
||||
show logo green at logopos
|
||||
with dissolve
|
||||
|
||||
|
||||
@@ -223,6 +223,8 @@ label demo_minigame:
|
||||
|
||||
e "Now, why don't we play some pong?"
|
||||
|
||||
window hide None
|
||||
|
||||
label demo_minigame_pong:
|
||||
|
||||
# Put up the pong background, in the usual fashion.
|
||||
@@ -232,11 +234,13 @@ label demo_minigame_pong:
|
||||
python:
|
||||
ui.add(PongDisplayable())
|
||||
winner = ui.interact(suppress_overlay=True, suppress_underlay=True)
|
||||
|
||||
|
||||
scene bg washington
|
||||
show eileen vhappy
|
||||
|
||||
|
||||
window show None
|
||||
|
||||
|
||||
if winner == "eileen":
|
||||
|
||||
e "I win!"
|
||||
|
||||
@@ -62,6 +62,15 @@ label demo_movement:
|
||||
|
||||
e "Move can repeat a movement, and even have it bounce back and forth, like I'm doing now."
|
||||
|
||||
|
||||
show eileen happy at Move((.25, 1.0, 0.0, 1.0),
|
||||
(.75, 1.0, 1.0, 1.0),
|
||||
10.0, repeat=True, bounce=True, subpixel=True)
|
||||
|
||||
with dissolve
|
||||
|
||||
e "Our subpixel mode allows slow moves, of less than a few pixels a second, to be very accurate."
|
||||
|
||||
scene bg onememorial at Pan((0, 800), (0, 0), 10.0)
|
||||
with dissolve
|
||||
|
||||
|
||||