Compare commits

...

55 Commits

Author SHA1 Message Date
Tom Rothamel a305d6e725 6.9.0d 2009-03-08 01:58:50 -05:00
Tom Rothamel 1feff344b8 New clipping code. 2009-03-07 21:23:01 -05:00
Tom Rothamel 4fa4ffae54 Releasing 6.9.0c. 2009-03-06 18:32:31 -05:00
Tom Rothamel 4ecd72de6e Readying 6.9.0b 2009-03-02 22:40:15 -05:00
Tom Rothamel 3ec495c3fc Fix fill problem.
Move only named layers.
Fix focus problem.
2009-03-02 21:50:50 -05:00
Tom Rothamel 5efc437384 Fixed rounding issue in place. 2009-03-02 15:29:55 -05:00
Tom Rothamel a777f4d3b1 Fix negative render size. 2009-03-01 20:06:19 -05:00
Tom Rothamel ff139808ff 6.9.0a 2009-03-01 14:23:58 -05:00
Tom Rothamel 07136f9be8 2009 2009-03-01 13:37:06 -05:00
Tom Rothamel 35fc2295e9 Various fixes. 2009-03-01 13:35:36 -05:00
Tom Rothamel 2b262ccca3 Fix annoying windows bugs. 2009-03-01 03:10:42 -05:00
Tom Rothamel d42aab3dff Movement demo. 2009-02-28 12:20:32 -05:00
Tom Rothamel 612c347498 Add transform demo. 2009-02-28 12:09:06 -05:00
Tom Rothamel 3c4540131a Remove speex.
Images are now allowed outside of init blocks.

Unicode strings are automatically prefixed with u in python code.
2009-02-27 00:45:55 -05:00
Tom Rothamel 43317f6e02 Add config.editor_file_separator 2009-02-24 23:31:42 -05:00
Tom Rothamel 523742d8de Write out launcherinfo.py 2009-02-24 23:11:18 -05:00
Tom Rothamel 9516ee910e The reporting of parse errors involving missing quotes has been
improved.

Added scaling of the subpixel function.
2009-02-24 03:49:55 -05:00
Tom Rothamel 3ea31a3862 Added config.label_callback. 2009-02-23 01:35:07 -05:00
Tom Rothamel 649411a4ef ui.transform and ui.autobar 2009-02-22 02:31:56 -05:00
Tom Rothamel a0e60e5453 Added transform and renpy.Container. 2009-02-21 15:34:16 -05:00
Tom Rothamel e3f1f40a78 Fix it for ppc etc. as well. 2009-02-19 03:43:03 -05:00
Tom Rothamel d0177f4c52 Implemented Transform
Fixed segfault bug in transform32_mmx.
2009-02-19 03:38:25 -05:00
Tom Rothamel 84a3a55a03 Update the changelog. Ensure draw_func draws on an integer pixel boundary. 2009-02-16 03:14:38 -05:00
Tom Rothamel 048075b47a Subpixel blitting works. Transform + alpha blitting is untested. 2009-02-16 02:41:18 -05:00
Tom Rothamel fab097c92a Render rewrite is roughly at parity with previous functionality. 2009-02-14 17:44:08 -05:00
Tom Rothamel 9d26bd8c04 WIP on Render rewrite. 2009-02-10 00:32:51 -05:00
Tom Rothamel 664d243c23 Implemented subpixel rendering in _renpy. 2009-01-29 02:58:48 -05:00
Tom Rothamel 9a0906655d Fix problems with 16 bit platform and config.window_icon. 2009-01-11 20:46:01 -05:00
Tom Rothamel 13d60f2741 Began adding subpixel support. 2009-01-05 01:28:06 -05:00
Tom Rothamel 7d4de64d0b Fixed an issue with imouto-mode that cropped up when a Frame scales something down to nothing. 2008-12-30 15:00:18 -05:00
Tom Rothamel 9ada2d9884 Deal with environment.txt. 2008-12-30 12:37:52 -05:00
Tom Rothamel a5f1951cfb Fixed multiple imouto-mode problems. 2008-12-30 12:27:03 -05:00
Tom Rothamel 98850e4c5c Added im.FactorScale, renpy.game_menu, and ui.gamemenus. 2008-12-29 12:25:29 -05:00
Tom Rothamel 709e1f925d Added renpy.sound.set_pan 2008-12-24 13:45:43 -05:00
Tom Rothamel b11ae331a5 Update renpygame.
Autosave on quit.

Fix memory leak via adjustments.
2008-12-23 00:41:15 -05:00
Tom Rothamel 3ba4b26b99 Transform (Rotozoom) now support subpixel alpha. 2008-12-16 03:29:43 -05:00
Tom Rothamel b864077017 Improved Rotozoom's correctness and speed. 2008-12-15 21:57:27 -05:00
Tom Rothamel d411dff1c0 Overlay behavior change.
Fix divide-by-zero in Alpha.
2008-12-06 01:52:12 -05:00
Tom Rothamel 7fc7453450 Releasing 6.8.1a. 2008-11-23 13:05:47 -05:00
Tom Rothamel 1799971885 Implement RENPY_LESS_UPDATES and RENPY_LESS_MOUSE.
Build iLiad distributions.

Add support for rebuilding distributions.
2008-11-23 11:15:26 -05:00
Tom Rothamel b999911292 Untested support for building iLiad distributions. 2008-11-21 02:59:49 -05:00
Tom Rothamel 29e0f9ad21 Working on iLiad support. 2008-11-21 02:09:54 -05:00
Tom Rothamel d821b7eb8b Fixed a bug that occured when space characters were inserted
immediately after a newline.
2008-11-20 01:32:40 -05:00
Tom Rothamel 272a214304 Modified lint slightly.
Added Alpha.
2008-11-18 01:35:29 -05:00
Tom Rothamel 7f15b351ee Add support for a user-defined default statement.
Speed up parsing a little.
2008-11-17 02:40:55 -05:00
Tom Rothamel 5a6a12a14a Blacklist renpy.display from being reloaded. 2008-11-17 00:05:31 -05:00
Tom Rothamel 01493c7063 Splitting cardgame. 2008-11-10 01:30:01 -05:00
Tom Rothamel 244055fcb7 Modified presplash.py so that it ignores errors forking of a second process. 2008-11-09 15:50:22 -05:00
Tom Rothamel 0415af5f31 Better support for scaling.
The launcher will now may sys.executable point to an existing file.
2008-11-09 15:36:16 -05:00
Tom Rothamel f73372c924 iRex iLiad support. 2008-11-02 16:14:16 -05:00
Tom Rothamel 65cdc24e37 Add staticgray support, for iLiad. 2008-11-02 08:43:53 -05:00
Tom Rothamel 1b2d439651 Releasing 6.8.0 2008-10-25 14:52:49 -04:00
Tom Rothamel b383942c69 Create icon group for loaded icons. (Took a week :-( ) 2008-10-25 01:45:03 -04:00
Tom Rothamel 73bd109abb Another try at fixing icons. 2008-10-17 22:57:18 -04:00
Tom Rothamel 33ffd5dedb Fix for a problem with icons that specify a size and shouldn't. 2008-10-17 20:21:21 -04:00
195 changed files with 4701 additions and 3761 deletions
+1
View File
@@ -28,3 +28,4 @@ launchertrans.rpy
jcc
scite/scite.zip
screenshot*
.ropeproject
+182
View File
@@ -1,3 +1,185 @@
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 has been raised to 100fps. This make
tearing less noticable than on a 60hz screen.
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
-------------------
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2004-2007 PyTom <pytom@bishoujo.us>
Copyright 2004-2009 PyTom <pytom@bishoujo.us>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
+5 -1
View File
@@ -18,7 +18,8 @@ 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") ],
@@ -58,6 +59,9 @@ def main():
if fn in seen:
continue
if fn == "SDL_mixer.dll":
continue
seen[fn] = True
zfnew.writestr(fn, zfold.read(fn))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 B

-697
View File
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

-336
View File
@@ -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]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

-247
View File
@@ -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"
-184
View File
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

+10 -1
View File
@@ -62,58 +62,67 @@ 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' ]):
moves = {
"" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp)),
"inright" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
enter_factory=MoveIn((1.0, None, 0.0, None), time_warp=in_time_warp)),
"inleft" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
enter_factory=MoveIn((0.0, None, 1.0, None), time_warp=in_time_warp)),
"intop" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
enter_factory=MoveIn((None, 0.0, None, 1.0), time_warp=in_time_warp)),
"inbottom" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
enter_factory=MoveIn((None, 1.0, None, 0.0), time_warp=in_time_warp)),
"outright" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
leave_factory=MoveOut((1.0, None, 0.0, None), time_warp=out_time_warp)),
"outleft" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
leave_factory=MoveOut((0.0, None, 1.0, None), time_warp=out_time_warp)),
"outtop" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
leave_factory=MoveOut((None, 0.0, None, 1.0), time_warp=out_time_warp)),
"outbottom" : MoveTransition(
delay,
old=old,
layers=layers,
factory=MoveFactory(time_warp=time_warp),
leave_factory=MoveOut((None, 1.0, None, 0.0), time_warp=time_warp)),
}
+2
View File
@@ -29,6 +29,8 @@ init -1150 python:
]
label _quit_prompt:
$ renpy.loadsave.force_autosave()
if layout.yesno_prompt(None, u"Are you sure you want to quit?"):
jump _quit
else:
+1
View File
@@ -41,6 +41,7 @@ init 1130:
else:
for i, m in enumerate(mixers):
renpy.sound.set_mixer(i, m, default=True)
renpy.sound.set_pan(0, 0, channel=i)
if m == 'music':
renpy.music.set_music(i, True, default=True)
else:
+6 -1
View File
@@ -68,6 +68,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.default, help='default style of transforms')
style.list = Style(style.default)
style.list_box = Style(style.vbox)
@@ -166,7 +167,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
@@ -263,6 +265,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
+7 -1
View File
@@ -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 < (6, 9, 0):
button_menu = True
else:
button_menu = False
layout.defaults()
if config.screen_width <= 640:
+9
View File
@@ -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
+1 -1
View File
@@ -22,7 +22,7 @@ label demo_multimedia:
# This plays a sound effect.
play sound "18005551212.ogg"
e "We can also play up to eight channels of sound effects on top of the music."
e "We can play two channels of sound effects on top of the music."
e "Voice support is included as part of Ren'Py, although we don't yet have a demonstration."
+223
View File
@@ -0,0 +1,223 @@
# This is the code for the logo example.
init python:
# This spins the logo, while at the same time zooming it and decreasing the
# alpha.
def logo_transform(t, st, at):
# Repeat every 10 seconds.
st = st % 7.0
# The move takes 5 seconds.
done = min(st / 5.0, 1.0)
t.xpos = done
t.xanchor = 1.0 - done
t.ypos = .5
t.yanchor = .5
t.rotate = 360 * done
t.alpha = 1.0 - done
t.zoom = 1.0 + done
return 0
# This is the code for the balls example. It's a bit complicated, but most of
# this is the code for ball movement and so on. Only a very little bit of this
# actually deals with Ren'Py.
init python:
import math
class Ball(object):
def __init__(self, filename, x, y, function=None):
self.transform = Transform(child=filename, xpos=x, ypos=y, xanchor=0.5, yanchor=0.5, rotate=0, function=function)
self.x = x
self.y = y
MAX_SPEED = 150
self.dx = renpy.random.uniform(-MAX_SPEED, MAX_SPEED)
self.dy = renpy.random.uniform(-MAX_SPEED, MAX_SPEED)
# Rotation speed.
self.drotate = renpy.random.uniform(0, 180)
# This is called
def balls_collide(p1, p2):
"""
Check to see if any of the balls are colliding. If they are,
then handle the collision.
"""
DOUBLE_RADIUS = 75
x21 = p2.x - p1.x
y21 = p2.y - p1.y
d = math.hypot(x21, y21)
# Return if too far.
if d > DOUBLE_RADIUS:
return
vx21 = p2.dx - p1.dx
vy21 = p2.dy - p1.dy
# Return if not approaching.
if (vx21 * x21 + vy21 * y21) > 0:
return
# Fix divide by zero.
if x21 == 0:
x21 = .00001
# Compute the collision.
a = y21 / x21
dvx2 = -(vx21 + a * vy21) / (1 + a * a)
p2.dx += dvx2
p2.dy += a * dvx2
p1.dx -= dvx2
p2.dy -= a * dvx2
# This is called by the first transform. It updates all of the
# transforms.
def balls_update(pilot, st, at):
global last_time
RADIUS = 75 / 2
LEFT = RADIUS
RIGHT = 800 - RADIUS
TOP = RADIUS
BOTTOM = 600 - RADIUS
# The pilot is the first ball in our list, and he's the one
# that gets last_time updated.
if last_time is None:
dt = 0
else:
dt = st - last_time
last_time = st
# Handle current collisions.
for i in xrange(0, len(balls)):
for j in xrange(i + 1, len(balls)):
balls_collide(balls[i], balls[j])
# Basic movement, and bouncing off the walls.
for i in balls:
i.x += i.dx * dt
i.y += i.dy * dt
if i.x < LEFT:
i.x = LEFT
i.dx = abs(i.dx)
if i.x > RIGHT:
i.x = RIGHT
i.dx = -abs(i.dx)
if i.y < TOP:
i.y = TOP
i.dy = abs(i.dy)
if i.y > BOTTOM:
i.y = BOTTOM
i.dy = -abs(i.dy)
# Update the transforms.
for i in balls:
# This is the code that deals with Ren'Py to update the
# various transforms. Note that we use absolute coordinates
# to position ourselves with subpixel accuracy.
i.transform.xpos = absolute(i.x)
i.transform.ypos = absolute(i.y)
i.transform.rotate = (i.drotate * st) % 360.0
i.transform.update()
return 0
# These are used in the button example:
init python:
def button_transform(t, st, at):
t.rotate = (90 * st) % 360.0
return 0
label demo_transform:
e "The Transform function allows you to rotate, zoom, move, and adjust the alpha of a displayable."
e "It does this under the control of a Python function, making it incredibly flexible at the cost of some complexity."
hide eileen
with dissolve
show logo base at Transform(function=logo_transform)
e "Here's a simple example, showing how we can change an image as it moves around the screen."
e "A nice thing about Transform is that it's \"one price\"."
e "If you use it to do a rotation, you can zoom or adjust alpha at no additional cost."
hide logo base
with dissolve
python:
last_time = None
# Define a list of ball objects.
balls = [
Ball("eileen_orb.png", 200, 150, function=balls_update),
Ball("lucy_orb.png", 400, 150),
Ball("eileen_orb.png", 600, 150),
Ball("lucy_orb.png", 200, 300),
Ball("lucy_orb.png", 600, 300),
Ball("eileen_orb.png", 200, 450),
Ball("lucy_orb.png", 400, 450),
Ball("eileen_orb.png", 600, 450),
]
# Add each ball's transform to the screen.
for i, b in enumerate(balls):
renpy.show("ball%d" % i, what=b.transform)
with dissolve
e "As the python functions get more complicated, more advanced behavior is possible."
e "This can include coordinating more than one Transform."
python:
for i, b in enumerate(balls):
renpy.hide("ball%d" % i)
with dissolve
python hide:
ui.transform(function=button_transform, xalign=0.5, yalign=0.5)
ui.textbutton("A Working Button", clicked=ui.returns(True))
e "Finally, transforms can be applied to buttons, and work even while the button is zoomed."
show eileen happy
with dissolve
e "With a little Python code, transforms let you do a lot of things."
return
+3 -2
View File
@@ -8,14 +8,14 @@ init:
("demo_basics", "Basic Scripting", "5.6.3"),
("demo_experience", "User Experience", "5.6.3"),
("demo_transitions", "Transitions", "5.6.6"),
("demo_movement", "Positions and Movement", "6.7.0"),
("demo_movement", "Positions and Movement", "6.9.0"),
("demo_animation", "Animation", "6.2.0"),
("demo_multimedia", "Music and Sound", "5.6.3"),
("demo_imageops", "Image Operations", "6.5.0"),
("demo_ui", "User Interaction", "6.5.0"),
("demo_text", "Fonts and Text Tags", "6.8.0"),
("demo_character", "Character Objects", "6.2.0"),
("demo_advanced", "Advanced Features", "6.7.0"),
("demo_advanced", "Advanced Features", "6.9.0"),
]
# Update above with this!
@@ -25,6 +25,7 @@ init:
("demo_dynamic", "Dynamic Displayables", "5.6.3"),
("demo_minigame", "Minigames", "6.3.2"),
("demo_persistent", "Persistent Data", "6.7.0"),
("demo_transform", "Transform", "6.9.0"),
]
def demos_show(demos_info, nevermind):
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+2 -1
View File
@@ -150,6 +150,7 @@ def main():
# files.extend(tree("extras"))
more_files.extend(tree("lib"))
more_files.extend(tree("lib/linux-x86"))
module_files = [
"lib/pysdlsound/linmixer.py",
@@ -234,7 +235,7 @@ def main():
print
print "Did you remember to rebuild the exe after the last change?"
print "Did you run me with renpython -O?"
print "Did you run me with renpython -OO?"
print "Was ming using the right crt?"
if __name__ == "__main__":
+1 -1
View File
@@ -63,7 +63,7 @@ init -100 python:
if name:
layout.label(s.name, "stat")
else:
ui.nul()
ui.null()
if value and max:
layout.label("%d/%d" % (v, s.max), "stat_value")
+120 -33
View File
@@ -13,15 +13,30 @@ init python:
# Returns true if a file or directory should not be included in
# the distribution
ignored_files = ("thumbs.db",
"launcherinfo.py",
"traceback.txt",
"errors.txt",
"icon.ico",
"icon.icns")
"icon.icns"
)
def ignored(fn):
root_ignored_files = (
"common",
"renpy",
"renpy.code",
"python23.dll",
"python24.dll",
"python25.dll",
"msvcr71.dll",
"lib",
"iliad-icon.png",
"manifest.xml"
)
def ignored(fn, dir, dest, root):
if fn[0] == ".":
return True
@@ -38,13 +53,21 @@ init python:
if fn == "archived":
return True
if root and dir == dest:
if fn.endswith(".py") or fn.endswith(".sh") or fn.endswith(".app"):
return True
if fn in root_ignored_files:
return True
return False
def tree(src, dest,
exclude_suffix=[ ".pyc", "~", ".bak" ],
exclude_prefix=[ ".", '#' ],
exclude=ignored_files,
exclude_func=None,
exclude_func=ignored,
root=False,
):
# Get rid of trailing slashes.
@@ -55,7 +78,7 @@ init python:
dest = dest[:-1]
# What should we include?
def include(fn):
def include(fn, destdir, dest):
for i in exclude_suffix:
if fn.endswith(i):
return False
@@ -68,7 +91,7 @@ init python:
if i == fn.lower():
return False
if exclude_func and exclude_func(fn):
if exclude_func and exclude_func(fn, destdir, dest, root):
return False
return True
@@ -89,7 +112,7 @@ init python:
for fn in files:
if not include(fn):
if not include(fn, destdir, dest):
continue
sfn = srcdir + "/" + fn
@@ -103,7 +126,7 @@ init python:
rv.append((sfn, dfn))
dirs[:] = [ i for i in dirs if include(i) ]
dirs[:] = [ i for i in dirs if include(i, destdir, dest) ]
return rv
@@ -140,12 +163,17 @@ label distribute:
else:
linux = False
if os.path.exists(config.renpy_base + "/lib/linux-iliad"):
iliad = True
else:
iliad = False
if os.path.exists(config.renpy_base + "/renpy.app"):
mac = True
else:
mac = False
if not (windows or mac or linux):
if not (windows or mac or linux or iliad):
store.error(u"Can't Distribute", u"Ren'Py is missing files required for distribution. Please download the full package from {a=http://www.renpy.org/}www.renpy.org{/a}.", "tools_menu")
lint()
@@ -183,6 +211,9 @@ label distribute:
if linux:
text(u"Linux x86", style='launcher_input')
if iliad:
text(u"iLiad", style='launcher_input')
if mac:
text(u"Mac OS X 10.4+", style='launcher_input')
@@ -202,9 +233,7 @@ label distribute:
if not interact():
renpy.jump("tools")
default_name = project.name
if persistent.build_project == project.name:
default_name = persistent.build_name
default_name = project.info.get('distribution_base', project.name)
name = prompt(u"Building Distributions",
u"Please enter a base name for the directories making up this distribution.",
@@ -222,14 +251,14 @@ label distribute:
except:
store.error(u"Error", u"Distribution names must be ASCII. This is because archive file formats do not support non-ASCII characters in a uniform way.", "tools_menu")
persistent.build_project = project.name
persistent.build_name = name
project.info['distribution_base'] = name
ignore_extensions = persistent.ignore_extensions or "~ .bak"
ignore_extensions = project.info.get('ignore_extensions', "~ .bak")
ignore_extensions = prompt(u"Building Distributions", u"Please enter a space separated list of the file extensions you do not want included in the distribution.", "tools", ignore_extensions)
persistent.ignore_extensions = ignore_extensions
store.ignore_extensions = [ i.strip() for i in ignore_extensions.strip().split() ]
project.info['ignore_extensions'] = ignore_extensions
project.save()
# Figure out the files that will make up the distribution.
@@ -249,24 +278,26 @@ label distribute:
exclude_suffix = [ ],
exclude_prefix = [ ],
exclude=[ ],
exclude_func = project.info["ignored"]))
root=True))
shortgamedir = project.gamedir[len(project.path)+1:]
for i in store.ignore_extensions:
if "script_version.rpy".endswith(i):
break
else:
multi.append((config.gamedir + "/script_version.rpy",
shortgamedir + "/script_version.rpy"))
for i in store.ignore_extensions:
if "script_version.rpyc".endswith(i):
break
else:
multi.append((config.gamedir + "/script_version.rpyc",
shortgamedir + "/script_version.rpyc"))
def add_script_version(fn, multi=multi, shortgamedir=shortgamedir):
for a, b in multi:
if b == shortgamedir + "/" + fn:
return
for i in store.ignore_extensions:
if fn.endswith(i):
return
multi.append((config.gamedir + "/" + fn, shortgamedir + "/" + fn))
add_script_version("script_version.rpy")
add_script_version("script_version.rpyc")
# renpy.py
multi.append((config.renpy_base + "/renpy.py",
project.name + ".py"))
@@ -320,7 +351,7 @@ label distribute:
if linux:
linux_files = [
(config.renpy_base + "/lib", "lib"),
(config.renpy_base + "/lib/linux-x86", "lib/linux-x86"),
(config.renpy_base + "/renpy.sh", project.name + ".sh"),
(config.renpy_base + "/lib/python", "lib/python"),
]
@@ -328,7 +359,6 @@ label distribute:
linux_files.extend(tree(config.renpy_base + "/lib/linux-x86", "lib/linux-x86"))
tf = tarfile.open(name + "-linux-x86.tar.bz2", "w:bz2")
tf.dereference = True
@@ -369,6 +399,59 @@ label distribute:
tf.close()
# iLiad Tar Bz2
if iliad:
iliad_files = [
(config.renpy_base + "/lib", "lib"),
(config.renpy_base + "/renpy-iliad.sh", project.name + ".sh"),
(config.renpy_base + "/lib/python", "lib/python"),
(config.renpy_base + "/manifest.xml", "manifest.xml"),
(config.renpy_base + "/iliad-icon.png", "iliad-icon.png"),
]
iliad_files.extend(tree(config.renpy_base + "/lib/linux-iliad", "lib/linux-iliad"))
iliad_data = { }
manifest = file(config.renpy_base + "/manifest.xml", "r").read()
manifest = manifest.replace("GAMENAME", project.name)
iliad_data["manifest.xml"] = manifest
zf = zipfile.ZipFile(name + "-iLiad.zip", "w", zipfile.ZIP_DEFLATED)
progress_len = len(multi) + len(iliad_files)
store.message = u"We thank Hixbooks for sponsoring iLiad support."
for i, (fn, an) in enumerate(multi + iliad_files):
progress(u"Building iLiad", i, progress_len)
if os.path.isdir(fn):
continue
zi = zipfile.ZipInfo(project.name + "/" + an)
s = os.stat(fn)
zi.date_time = time.gmtime(s.st_mtime)[:6]
zi.compress_type = zipfile.ZIP_DEFLATED
zi.create_system = 3
for ext in [ ".sh", ".so", "python", "python.real" ]:
if fn.endswith(ext):
zi.external_attr = long(0100777) << 16
data = file(fn, "rb").read()
break
else:
zi.external_attr = long(0100666) << 16
data = file(fn, "rb").read()
data = iliad_data.get(an, data)
zf.writestr(zi, data)
zf.close()
if mac:
mac_files = tree(config.renpy_base + "/renpy.app",
@@ -383,6 +466,10 @@ label distribute:
info_plist = file(config.renpy_base + "/renpy.app/Contents/Info.plist", "rb").read().replace("Ren'Py Launcher", quoted_name)
mac_data[project.name + ".app/Contents/Info.plist"] = info_plist
quoted_name = project.name.replace("\"", "\\\"")
launcher_py = file(config.renpy_base + "/renpy.app/Contents/Resources/launcher.py", "rb").read().replace("Ren'Py Launcher", quoted_name)
mac_data[project.name + ".app/Contents/Resources/launcher.py"] = launcher_py
if os.path.exists(project.path + "/icon.icns"):
icon_data = file(project.path + "/icon.icns", "rb").read()
mac_data[project.name + ".app/Contents/Resources/launcher.icns"] = icon_data
+26 -8
View File
@@ -231,7 +231,21 @@ init:
title = re.sub(r'\s+\S', upper, title)
self.title = title
def save(self):
import os
f = file(self.path + "/" + "launcherinfo.py.new", "w")
for k, v in self.info.iteritems():
f.write("%s = %r\n" % (k, v))
f.close()
try:
os.rename(self.path + "/launcherinfo.py.new", self.path + "/launcherinfo.py")
except:
os.unlink(self.path + "/launcherinfo.py")
os.rename(self.path + "/launcherinfo.py.new", self.path + "/launcherinfo.py")
def load_project(dir, name):
import os.path
@@ -251,7 +265,6 @@ init:
info = dict()
info["description"] = desc
info["ignored"] = ignored
if os.path.exists(dir + "/launcherinfo.py"):
source = file(dir + "/launcherinfo.py", "rU").read().decode("utf8")
@@ -261,6 +274,8 @@ init:
exec source in info
del info["__builtins__"]
store.projects.append(Project(name, dir, gamedir, info))
def load_projects():
@@ -516,10 +531,11 @@ label game_directory:
import renpy.subprocess as subprocess
subprocess.Popen([ "open", gamedir ])
else:
store.message = _(u"Opening the game directory is not supported on this platform.\n%s") % gamedir
import renpy.subprocess as subprocess
subprocess.Popen([ "xdg-open", gamedir ])
gamedir = "".join(quote(i) for i in gamedir)
gamedir = "".join(quote(i) for i in gamedir)
store.message = _(u"Opening game directory:\n%s") % gamedir
jump top_menu
@@ -599,21 +615,23 @@ label archive_files:
import renpy.tools.archiver as archiver
extensions = persistent.archive_extensions or "*.png *.gif *.jpg"
extensions = project.info.get('archive_extensions', "*.png *.gif *.jpg")
extensions = prompt(u"Archiving Files", u"Please enter a space separated list of the file patterns you want archived.", "tools", extensions)
if not extensions.strip():
renpy.jumps("tools_menu")
persistent.archive_extensions = extensions
project.info['archive_extensions'] = extensions
extensions = [ i.strip() for i in extensions.strip().split() ]
base = persistent.archive_base or "data"
base = project.info.get('archive_base', "data")
base = prompt(u"Archiving Files", u"Please enter the name of the archive file, without the .rpa extension.", "tools", base)
base = base.strip()
if not base:
renpy.jumps("tools_menu")
persistent.archive_base = base
project.info['archive_base'] = base
project.save()
# Tell the user we're archiving images.
title(u"Archiving Files")
store.message = u"Please wait while we archive files."
+1 -1
View File
@@ -57,7 +57,7 @@ label new:
if d.startswith("."):
dirs.remove(d)
dn = dir + "/" + d
shutil.rmtree(dn)
shutil.rmtree(dn, True)
# Change the save directory.
options = file(name + "/game/options.rpy").read()
+92 -51
View File
@@ -156,58 +156,83 @@ def show_resources(d, prefix):
##############################################################################
# These functions repack the resources into a new resource segment. Here,
# the offset is relative to the start of the resource segment.
class Packer(object):
def pack(self, d):
self.data = ""
self.data_offset = 0
self.entries = ""
self.entries_offset = 0
def repack_name(s):
l = len(s)
s = s.encode("utf-16le")
return struct.pack("<H", l) + s + "\0\0"
head = self.pack_dict(d, 0)
def repack_tuple(o, offset):
codepage, data = o
# print "REPACK OFFSET IS", offset
return struct.pack("<IIII", offset + 16 + RESOURCE_VIRTUAL, len(data), codepage, 0) + data
self.data = ""
self.data_offset = len(head) + len(self.entries)
def repack_dict(o, offset):
name_entries = sorted((a, b) for a, b in o.iteritems() if isinstance(a, unicode))
id_entries = sorted((a, b) for a, b in o.iteritems() if isinstance(a, int))
self.entries = ""
self.entries_offset = len(head)
rv = struct.pack("<IIHHHH", 0, 0, 4, 0, len(name_entries), len(id_entries))
return self.pack_dict(d, 0) + self.entries + self.data
offset += len(rv) + (len(name_entries) + len(id_entries)) * 8
rest = ""
def pack_name(self, s):
rv = self.data_offset + len(self.data)
l = len(s)
s = s.encode("utf-16le")
self.data += struct.pack("<H", l) + s + "\0\0"
return rv
def pack_tuple(self, t):
codepage, data = t
rv = len(self.entries) + self.entries_offset
if len(self.data) % 2:
self.data += "P"
daddr = len(self.data) + self.data_offset
self.entries += struct.pack("<IIII", daddr + RESOURCE_VIRTUAL, len(data), codepage, 0)
self.data += data
# if len(self.data) % 1 == 1:
# self.data += 'P'
return rv
for (name, value) in name_entries + id_entries:
if isinstance(name, unicode):
packed = repack_name(name)
name = 0x80000000 | offset
offset += len(packed)
rest += packed
pad = 8 - (offset % 8)
offset += pad
rest += "RENPYVNE"[:pad]
addr = offset
if isinstance(value, dict):
addr = addr | 0x80000000
rv += struct.pack("<II", name, addr)
if isinstance(value, dict):
packed = repack_dict(value, offset)
elif isinstance(value, tuple):
packed = repack_tuple(value, offset)
offset += len(packed)
rest += packed
if offset % 8:
pad = 8 - (offset % 8)
offset += pad
rest += "RENPYVNE"[:pad]
return rv + rest
def pack_dict(self, d, offset):
name_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, unicode))
id_entries = sorted((a, b) for a, b in d.iteritems() if isinstance(a, int))
rv = struct.pack("<IIHHHH", 0, 0, 4, 0, len(name_entries), len(id_entries))
offset += len(rv) + (len(name_entries) + len(id_entries)) * 8
rest = ""
for (name, value) in name_entries + id_entries:
if isinstance(name, unicode):
name = 0x80000000 | self.pack_name(name)
if isinstance(value, dict):
addr = offset | 0x80000000
packed = self.pack_dict(value, offset)
offset += len(packed)
rest += packed
else:
addr = self.pack_tuple(value)
rv += struct.pack("<II", name, addr)
return rv + rest
##############################################################################
# This loads in an icon file, and returns a dictionary that is suitable for
@@ -221,6 +246,9 @@ def load_icon(fn):
count = f.u16()
rv = { }
rv[3] = { }
group = struct.pack("HHH", 0, 1, count)
for i in range(count):
width = f.u8()
@@ -232,8 +260,21 @@ def load_icon(fn):
size = f.u32()
offset = f.u32()
rv[i + 1] = { 0 : (1252, f.substring(offset, size)) }
addr = f.addr
f.seek(offset + 16)
if not f.u32():
f.set_u32(offset + 20, 0)
rv[3][i + 1] = { 0 : (1252, f.substring(offset, size)) }
group += struct.pack("BBBBHHIH", width, height, colors, reserved,
planes, bpp, size, i + 1)
f.seek(addr)
rv[14] = { 1 : { 0 : (1252, group) } }
return rv
@@ -250,22 +291,22 @@ def change_icons(oldexe, icofn):
raise Exception("RESOURCE_BASE is no longer correct. Please check all relocations.")
resources = parse_directory(0)
# show_resources(resources, "")
resources[3] = load_icon(icofn)
# show_resources(resources, "")
# show_resources(resources, "")
resources.update(load_icon(icofn))
# show_resources(resources, "")
rsrc = repack_dict(resources, 0)
rsrc = Packer().pack(resources)
rsrc_len = len(rsrc)
pe.seek(ALIGNMENT_FIELD)
alignment = pe.u32()
if len(rsrc) % alignment:
pad = alignment - (len(rsrc) % alignment)
padding = "RENPYVNE" * (pad / 8 + 1)
padding = padding[:pad]
rsrc += padding
padded_len = len(rsrc)
for addr in RESOURCE_LENGTH_PATCHES:
-1
View File
@@ -1 +0,0 @@
/home/tom/ab/py4renpy/current
-1
View File
@@ -2,7 +2,6 @@
# platforms as well. It probably won't work on Mac OS X, however.
build:: _renpy.c sound.c nativemidi.c winmixer.c
python setup.py build install_lib -d $(PYTHONPATH)
clean:
-rm *.so pysdlsound/*.so
+27 -5
View File
@@ -69,7 +69,8 @@ cdef extern from "renpy.h":
float, float, float, float)
void transform32_core(object, object,
float, float, float, float, float, float)
float, float, float, float, float, float,
int, float)
void blend32_core(object, object, object, int)
@@ -80,6 +81,13 @@ cdef extern from "renpy.h":
float, float, float, float, float,
float, float, float, float, float,
float, float, float, float, float)
void staticgray_core(object, object,
int, int, int, int, int, char *)
int subpixel32(object, object, float, float, int)
void PyErr_Clear()
import pygame
@@ -88,7 +96,7 @@ PygameSurface = pygame.Surface
# Update this in 00library.rpy as well!
def version():
return 6007001
return 6009000
def save_png(surf, file, compress=-1):
@@ -286,7 +294,7 @@ def bilinear(pysrc, pydst,
if pysrc.get_bitsize() not in (24, 32):
raise Exception("bilinear requires a 24 or 32 bit surface.")
if pydst.get_bitsize() != pysrc.get_bitsize():
raise Exception("bilinear requires both surfaces have the same bitsize.")
@@ -324,7 +332,7 @@ def check(surf):
def transform(pysrc, pydst,
corner_x, corner_y,
xdx, ydx, xdy, ydy):
xdx, ydx, xdy, ydy, a=1.0):
check(pysrc)
check(pydst)
@@ -335,7 +343,8 @@ def transform(pysrc, pydst,
transform32_core(pysrc, pydst,
corner_x, corner_y,
xdx, ydx,
xdy, ydy)
xdy, ydy,
pysrc.get_shifts()[3], a)
# pydst.unlock()
# pysrc.unlock()
@@ -396,6 +405,19 @@ def colormatrix(pysrc, pydst,
# pydst.unlock()
# pysrc.unlock()
def staticgray(pysrc, pydst, rmul, gmul, bmul, amul, shift, vmap):
PyErr_Clear()
staticgray_core(pysrc, pydst, rmul, gmul, bmul, amul, shift, vmap)
def subpixel(pysrc, pydst, xoffset, yoffset, shift):
if subpixel32(pysrc, pydst, xoffset, yoffset, shift):
return
pydst.blit(pysrc, (int(xoffset), int(yoffset)))
# Be sure to update scale.py when adding something new here!
+341 -88
View File
@@ -960,13 +960,16 @@ void scale24_core(PyObject *pysrc, PyObject *pydst,
Py_END_ALLOW_THREADS
}
#define I(a, b, mul) ((((((b - a) * mul)) >> 8) + a) & 0xff00ff)
/****************************************************************************/
/* A similar concept to rotozoom, but implemented differently, so we
can limit the target area. */
void transform32_core(PyObject *pysrc, PyObject *pydst,
float corner_x, float corner_y,
float xdx, float ydx,
float xdy, float ydy) {
void transform32_std(PyObject *pysrc, PyObject *pydst,
float corner_x, float corner_y,
float xdx, float ydx,
float xdy, float ydy,
int ashift, float a) {
SDL_Surface *src;
SDL_Surface *dst;
@@ -986,7 +989,7 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
dst = PySurface_AsSurface(pydst);
Py_BEGIN_ALLOW_THREADS
srcpixels = (unsigned char *) src->pixels;
dstpixels = (unsigned char *) dst->pixels;
srcpitch = src->pitch;
@@ -996,6 +999,8 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
srch = src->h;
dsth = dst->h;
unsigned int amul = (int) (a * 256);
lsx = corner_x * 256;
lsy = corner_y * 256;
@@ -1008,8 +1013,7 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
// Scaled subtracted srcw and srch.
float fsw = (srcw - 2) * 256;
float fsh = (srch - 2) * 256;
for (y = 0; y < dsth; y++, lsx += xdy, lsy += ydy) {
sx = lsx;
@@ -1028,7 +1032,6 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
minx = fmaxf(minx, fminf(d1, d2));
maxx = fminf(maxx, fmaxf(d1, d2));
// printf("ZZZ1 %f %f\n", d1, d2);
} else if ( lsx < 0 || lsx >= fsw) {
continue;
}
@@ -1039,7 +1042,6 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
minx = fmaxf(minx, fminf(d1, d2));
maxx = fminf(maxx, fmaxf(d1, d2));
// printf("ZZZ2 %f %f\n", d1, d2);
} else if ( lsy < 0 || lsy >= fsh) {
continue;
}
@@ -1048,108 +1050,316 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
continue;
}
// printf("CCC %f %f\n", minx, maxx);
minx = ceil(minx);
maxx = floor(maxx);
// printf("CCC2 %f %f\n", minx, maxx);
// printf("XXX %f %f %f %f\n", lsx / 256, xdx / 256, lsy / 256, ydx/256);
// printf("%f %f\n", minx, maxx);
// printf("Minx at: %f %f\n", (lsx + xdx * minx) / 256, (lsy + ydx * minx) / 256);
unsigned char *d = dstpixels + dstpitch * y;
unsigned char *dend = d + 4 * (int) maxx;
d += 4 * (int) minx;
sx += minx * xdx;
sy += minx * ydx;
sx = lsx + minx * xdx;
sy = lsy + minx * ydx;
while (d <= dend) {
int sxi = (int) sx;
int syi = (int) sy;
int xdxi = (int) xdx;
int ydxi = (int) ydx;
int px, py, sxi, syi;
sxi = ((int) sx);
syi = ((int) sy);
while (d <= dend) {
int px, py;
px = sxi >> 8;
py = syi >> 8;
unsigned char *sp = srcpixels + py * srcpitch + px * 4;
int yfrac = syi & 0xff; // ((short) sy) & 0xff;
int xfrac = sxi & 0xff; // ((short) sx) & 0xff;
/* These bounds are checked analytically, hence the if (1)
* { */
unsigned int pal = *(unsigned int *) sp;
unsigned int pbl = *(unsigned int *) (sp + 4);
sp += srcpitch;
unsigned int pcl = *(unsigned int *) sp;
unsigned int pdl = *(unsigned int *) (sp + 4);
unsigned int pah = (pal >> 8) & 0xff00ff;
unsigned int pbh = (pbl >> 8) & 0xff00ff;
unsigned int pch = (pcl >> 8) & 0xff00ff;
unsigned int pdh = (pdl >> 8) & 0xff00ff;
pal &= 0xff00ff;
pbl &= 0xff00ff;
pcl &= 0xff00ff;
pdl &= 0xff00ff;
unsigned int rh = I(I(pah, pch, yfrac), I(pbh, pdh, yfrac), xfrac);
unsigned int rl = I(I(pal, pcl, yfrac), I(pbl, pdl, yfrac), xfrac);
unsigned int alpha = (((rh << 8) | rl) >> ashift) & 0xff;
alpha = (alpha * amul) >> 8;
// if (0 <= px && px < srcw - 1 && 0 <= py && py < srch - 1) {
if (1) {
unsigned char *sp = srcpixels + py * srcpitch + px * 4;
unsigned int dl = * (unsigned int *) d;
unsigned int dh = (dl >> 8) & 0xff00ff;
dl &= 0xff00ff;
// unsigned char *s1p = s0p + srcpitch;
int s1frac = syi & 0xff; // ((short) sy) & 0xff;
int xfrac = sxi & 0xff; // ((short) sx) & 0xff;
#define I(a, b, mul) ((((((b - a) * mul)) >> 8) + a) & 0xff00ff)
unsigned int rl, rh;
unsigned int pal = *(unsigned int *) sp;
unsigned int pbl = *(unsigned int *) (sp + 4);
sp += srcpitch;
unsigned int pcl = *(unsigned int *) sp;
unsigned int pdl = *(unsigned int *) (sp + 4);
unsigned int pah = (pal >> 8) & 0xff00ff;
unsigned int pbh = (pbl >> 8) & 0xff00ff;
unsigned int pch = (pcl >> 8) & 0xff00ff;
unsigned int pdh = (pdl >> 8) & 0xff00ff;
pal &= 0xff00ff;
pbl &= 0xff00ff;
pcl &= 0xff00ff;
pdl &= 0xff00ff;
// if (y == 10)
// printf("%x %x %x %x\n", pah, pbh, pch, pdh);
rh = I(I(pah, pch, s1frac), I(pbh, pdh, s1frac), xfrac);
rl = I(I(pal, pcl, s1frac), I(pbl, pdl, s1frac), xfrac);
// rl = 0;
// if (y == 10)
// printf("%x\n", rh);
* (unsigned int *) d = (rh << 8) | rl;
d += 4;
} else {
// This code can't execute.
printf("Failed x %f (%d, %d)\n", minx, px, py);
*d++ = 0;
*d++ = 0;
*d++ = 0;
*d++ = 0;
}
dl = I(dl, rl, alpha);
dh = I(dh, rh, alpha);
sx += xdx;
sy += ydx;
// minx++;
* (unsigned int *) d = (dh << 8) | dl;
d += 4;
sxi += xdxi;
syi += ydxi;
}
}
Py_END_ALLOW_THREADS
}
#ifdef GCC_MMX
/****************************************************************************/
/* A similar concept to rotozoom, but implemented differently, so we
can limit the target area. */
int transform32_mmx(PyObject *pysrc, PyObject *pydst,
float corner_x, float corner_y,
float xdx, float ydx,
float xdy, float ydy,
int ashift,
float a) {
SDL_Surface *src;
SDL_Surface *dst;
int y;
int srcpitch, dstpitch;
int srcw, srch;
int dstw, dsth;
unsigned char *srcpixels;
unsigned char *dstpixels;
float lsx, lsy; // The position of the current line in the source.
float sx, sy; // The position of the current pixel in the source.
unsigned int px, py;
unsigned int sxi, syi;
unsigned int xdxi, ydxi;
src = PySurface_AsSurface(pysrc);
dst = PySurface_AsSurface(pydst);
Py_BEGIN_ALLOW_THREADS
srcpixels = (unsigned char *) src->pixels;
dstpixels = (unsigned char *) dst->pixels;
srcpitch = src->pitch;
dstpitch = dst->pitch;
srcw = src->w;
dstw = dst->w;
srch = src->h;
dsth = dst->h;
// Due to mmx.
ashift *= 2;
// Compute the coloring multiplier.
unsigned int amul = (unsigned int) (a * 256);
lsx = corner_x * 256;
lsy = corner_y * 256;
xdx *= 256;
ydx *= 256;
xdy *= 256;
ydy *= 256;
// Scaled subtracted srcw and srch.
float fsw = (srcw - 2) * 256;
float fsh = (srch - 2) * 256;
for (y = 0; y < dsth; y++, lsx += xdy, lsy += ydy) {
float minx = 0;
float maxx = dstw - 1;
if (xdx != 0) {
float d1 = -lsx / xdx;
float d2 = (fsw - lsx) / xdx;
minx = fmaxf(minx, fminf(d1, d2));
maxx = fminf(maxx, fmaxf(d1, d2));
} else if ( lsx < 0 || lsx >= fsw) {
continue;
}
if (ydx != 0) {
float d1 = -lsy / ydx;
float d2 = (fsh - lsy) / ydx;
minx = fmaxf(minx, fminf(d1, d2));
maxx = fminf(maxx, fmaxf(d1, d2));
} else if ( lsy < 0 || lsy >= fsh) {
continue;
}
if (minx > maxx) {
continue;
}
minx = ceil(minx);
maxx = floor(maxx);
unsigned char *d = dstpixels + dstpitch * y;
unsigned char *dend = d + 4 * (int) maxx;
d += 4 * (int) minx;
sx = (lsx + minx * xdx);
sy = (lsy + minx * ydx);
sxi = (unsigned int) sx;
syi = (unsigned int) sy;
xdxi = (int) xdx;
ydxi = (int) ydx;
// No floating point allowed between here and the end of the
// while loop.
// 0 -> mm7
pxor_r2r(mm7, mm7);
// ashift -> mm0
movd_m2r(ashift, mm0);
// amul -> mm4
movd_m2r(amul, mm4);
while (d <= dend) {
px = sxi >> 8;
py = syi >> 8;
unsigned char *sp = srcpixels + py * srcpitch + px * 4;
unsigned int yfrac = syi & 0xff; // ((short) sy) & 0xff;
unsigned int xfrac = sxi & 0xff; // ((short) sx) & 0xff;
// Put xfrac in mm5, yfrac in m6
pxor_r2r(mm5, mm5);
pxor_r2r(mm6, mm6);
movd_m2r(xfrac, mm5);
movd_m2r(yfrac, mm6);
punpcklwd_r2r(mm5, mm5);
punpcklwd_r2r(mm6, mm6);
punpckldq_r2r(mm5, mm5); /* 0X0X0X0X -> mm5 */
punpckldq_r2r(mm6, mm6); /* 0Y0Y0Y0Y -> mm6 */
// Load in the 4 bytes.
movd_m2r(*(unsigned int *) sp, mm1);
movd_m2r(*(unsigned int *) (sp + 4), mm2);
punpcklbw_r2r(mm7, mm1);
punpcklbw_r2r(mm7, mm2);
// Interpolate between a and b.
psubw_r2r(mm1, mm2);
pmullw_r2r(mm5, mm2);
psrlw_i2r(8, mm2);
paddb_r2r(mm2, mm1); /* mm1 contains I(a, b, xfrac); */
sp += srcpitch;
movd_m2r(*(unsigned int *) sp, mm3);
movd_m2r(*(unsigned int *) (sp + 4), mm2);
punpcklbw_r2r(mm7, mm3);
punpcklbw_r2r(mm7, mm2);
// Interpolate between c and d.
psubw_r2r(mm3, mm2);
pmullw_r2r(mm5, mm2);
psrlw_i2r(8, mm2);
paddb_r2r(mm2, mm3); /* mm3 contains I(c, d, xfrac); */
// Interpolate between ab and cd.
psubw_r2r(mm1, mm3);
pmullw_r2r(mm6, mm3);
psrlw_i2r(8, mm3);
paddb_r2r(mm3, mm1); /* mm1 contains I(ab, cd, yfrac) */
// Store the result.
// packuswb_r2r(mm7, mm1);
// movd_r2m(mm1, *(unsigned int *)d);
// Alpha blend with dest.
movq_r2r(mm1, mm3);
psrlq_r2r(mm0, mm3); /* 000000AA -> m3 */
pmullw_r2r(mm4, mm3); // Alpha adjustment.
psrlw_i2r(8, mm3);
punpcklwd_r2r(mm3, mm3); /* 0000AAAA -> m3 */
movd_m2r(*(unsigned int *)d, mm2);
punpcklwd_r2r(mm3, mm3); /* AAAAAAAA -> m3 */
punpcklbw_r2r(mm7, mm2); /* a -> m2 */
psubw_r2r(mm2, mm1); /* b - a -> m1 */
pmullw_r2r(mm3, mm1);
psrlw_i2r(8, mm1); /* alpha * (b-a) -> m1 */
paddb_r2r(mm2, mm1); /* a + alpha*(b-a) -> mm1 */
// Store the result.
packuswb_r2r(mm7, mm1);
movd_r2m(mm1, *(unsigned int *)d);
d += 4;
sxi += xdxi;
syi += ydxi;
}
emms();
}
Py_END_ALLOW_THREADS
// This is bogus, and only serves to ensure that the FPU
// computes these variables at the right times.
return sxi + syi + xdxi + ydxi;
}
#endif
void transform32_core(PyObject *pysrc, PyObject *pydst,
float corner_x, float corner_y,
float xdx, float ydx,
float xdy, float ydy,
int ashift,
float a) {
#ifdef GCC_MMX
static int checked_mmx = 0;
static int has_mmx = 0;
if (! checked_mmx) {
has_mmx = SDL_HasMMX();
checked_mmx = 1;
}
if (has_mmx) {
transform32_mmx(pysrc, pydst, corner_x, corner_y,
xdx, ydx, xdy, ydy, ashift, a);
return;
}
#endif
transform32_std(pysrc, pydst, corner_x, corner_y,
xdx, ydx, xdy, ydy, ashift, a);
}
void blend32_core_std(PyObject *pysrca, PyObject *pysrcb, PyObject *pydst,
int alpha) {
@@ -1555,3 +1765,46 @@ void colormatrix32_core(PyObject *pysrc, PyObject *pydst,
Py_END_ALLOW_THREADS
}
void staticgray_core(PyObject *pysrc, PyObject *pydst,
int rmul, int gmul, int bmul, int amul, int shift, char *vmap) {
SDL_Surface *src;
SDL_Surface *dst;
int srcpitch, dstpitch;
unsigned short dstw, dsth;
unsigned short x, y;
unsigned char *srcpixels;
unsigned char *dstpixels;
src = PySurface_AsSurface(pysrc);
dst = PySurface_AsSurface(pydst);
Py_BEGIN_ALLOW_THREADS;
srcpixels = (unsigned char *) src->pixels;
dstpixels = (unsigned char *) dst->pixels;
srcpitch = src->pitch;
dstpitch = dst->pitch;
dstw = dst->w;
dsth = dst->h;
for (y = 0; y < dsth; y++) {
unsigned char *s = &srcpixels[y * srcpitch];
unsigned char *d = &dstpixels[y * dstpitch];
for (x = 0; x < dstw; x++) {
int sum = 0;
sum += *s++ * rmul;
sum += *s++ * gmul;
sum += *s++ * bmul;
sum += *s++ * amul;
*d++ = (unsigned char) vmap[sum >> shift];
}
}
Py_END_ALLOW_THREADS;
}
+105 -1
View File
@@ -145,6 +145,15 @@ struct Channel {
/* The event posted to the queue when we finish a track. */
int event;
/* The pan being applied to the current channel. */
float pan_start;
float pan_end;
/* The length of the current pan, in samples. */
unsigned int pan_length;
/* The number of samples we've finished in the current pan. */
unsigned int pan_done;
};
/*
@@ -158,6 +167,23 @@ struct Channel channels[NUM_CHANNELS];
SDL_AudioSpec audio_spec;
static float interpolate_pan(struct Channel *c) {
float done;
if (c->pan_done > c->pan_length) {
c->pan_length = 0;
}
if (c->pan_length == 0) {
return c->pan_end;
}
done = 1.0 * c->pan_done / c->pan_length;
return c->pan_start + done * (c->pan_end - c->pan_start);
}
static int ms_to_bytes(int ms) {
return ((long long) ms) * audio_spec.freq * audio_spec.channels * 2 / 1000;
}
@@ -235,6 +261,7 @@ static void mixaudio(Uint8 *dst, Uint8 *src, int length, int volume) {
}
}
// Mixes the audio, while performing fading.
static void fade_mixaudio(struct Channel *c,
Uint8 *dst, Uint8 *src, int length) {
@@ -290,6 +317,48 @@ static void post_event(struct Channel *c) {
SDL_PushEvent(&e);
}
static void pan_audio(struct Channel *c, Uint8 *stream, int length) {
int i;
short *sample = (short *) stream;
length /= 4;
float pan;
int left = 256;
int right = 256;
for (i = 0; i < length; i++) {
if ((i & 0x1f) == 0) {
pan = interpolate_pan(c);
// If the pan is even, skip 32 samples and call it a day.
if (pan == 0.0) {
i += 31;
c->pan_done += 32;
continue;
}
if (pan < 0) {
left = 256;
right = (int) (256 * (1.0 + pan));
} else {
left = (int) (256 * (1.0 - pan));
right = 256;
}
}
*sample = (short) ((*sample * left) >> 8);
sample++;
*sample = (short) ((*sample * right) >> 8);
sample++;
c->pan_done += 1;
}
}
static void callback(void *userdata, Uint8 *stream, int length) {
int channel = 0;
@@ -316,7 +385,10 @@ static void callback(void *userdata, Uint8 *stream, int length) {
if (c->stop_bytes != -1)
bytes = min(c->stop_bytes, bytes);
pan_audio(c, &( ((Uint8*) c->playing->buffer) [c->last]),
bytes);
fade_mixaudio(c, &stream[mixed],
&( ((Uint8*) c->playing->buffer) [c->last]),
bytes);
@@ -805,6 +877,7 @@ void PSS_set_volume(int channel, float volume) {
}
float PSS_get_volume(int channel) {
float rv;
@@ -828,6 +901,32 @@ float PSS_get_volume(int channel) {
return rv;
}
/*
* This sets the pan of the channel... independent volumes for the
* left and right channels.
*/
void PSS_set_pan(int channel, float pan, float delay) {
struct Channel *c;
BEGIN();
if (check_channel(channel)) {
return;
}
c = &channels[channel];
ENTER();
c->pan_start = interpolate_pan(c);
c->pan_end = pan;
c->pan_length = (int) (audio_spec.freq * delay);
c->pan_done = 0;
EXIT();
error(SUCCESS);
}
/*
* Initializes the sound to the given frequencies, channels, and
@@ -886,6 +985,11 @@ void PSS_init(int freq, int stereo, int samples) {
channels[i].volume = SDL_MIX_MAXVOLUME;
channels[i].paused = 1;
channels[i].event = 0;
channels[i].pan_start = 0.0;
channels[i].pan_end = 0.0;
channels[i].pan_length = 0;
channels[i].pan_done = 0;
}
SDL_PauseAudio(0);
+1
View File
@@ -43,6 +43,7 @@ void PSS_set_endevent(int channel, int event);
int PSS_get_pos(int channel);
void PSS_set_volume(int channel, float volume);
float PSS_get_volume(int channel);
void PSS_set_pan(int channel, float pan, float delay);
void PSS_init(int freq, int stereo, int samples);
void PSS_quit(void);
const char *PSS_get_error(void);
+11 -1
View File
@@ -86,7 +86,8 @@ void transform32_core(PyObject *pysrc,
PyObject *pydst,
float, float,
float, float,
float, float);
float, float,
int, float);
void blend32_core(PyObject *pysrca,
PyObject *pysrcb,
@@ -104,5 +105,14 @@ void colormatrix32_core(PyObject *pysrc, PyObject *pydst,
float c20, float c21, float c22, float c23, float c24,
float c30, float c31, float c32, float c33, float c34);
void staticgray_core(
PyObject *pysrc, PyObject *pydst,
int rmul, int gmul, int bmul, int amul, int shift,
char *vmap);
int subpixel32(
PyObject *pysrc, PyObject *pydst,
float xoffset, float yoffset, int ashift);
#endif
+4 -3
View File
@@ -30,11 +30,12 @@ if not os.path.isdir(install):
# Default compile arguements for everybody.
include_dirs = [ install + "/include", install + "/include/SDL", install + "/include/freetype2", install + "/include/pygame"]
library_dirs = [ install + "/lib" ]
extra_compile_args = [ "-O3", "-funroll-loops", "-ffast-math" ]
# Fast math breaks on windows. :-(
extra_compile_args = [ "-O3", "-funroll-loops" ] # , "-ffast-math" ]
extra_link_args = [ ]
png_libraries = [ 'png', "z" ]
sdl_libraries = [ 'SDL' ]
sound_libraries = [ 'SDL_sound', 'smpeg', 'vorbisfile', 'vorbis', 'ogg', 'modplug', 'speex', 'stdc++', ]
sound_libraries = [ 'SDL_sound', 'smpeg', 'vorbisfile', 'vorbis', 'ogg', 'modplug', 'stdc++', ]
# The following turn on optional modules.
nativemidi = None
@@ -65,7 +66,7 @@ py_modules = [ 'pysdlsound.__init__' ]
rpe = distutils.core.Extension(
"_renpy",
[ "IMG_savepng.c", "core.c", "rwobject.c", "_renpy.c" ],
[ "IMG_savepng.c", "core.c", "rwobject.c", "_renpy.c", "subpixel.c" ],
include_dirs=include_dirs,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
+5
View File
@@ -39,6 +39,7 @@ cdef extern from "pss.h":
void PSS_set_endevent(int channel, int event)
void PSS_set_volume(int channel, float volume)
float PSS_get_volume(int channel)
void PSS_set_pan(int channel, float left, float right)
void PSS_init(int freq, int stereo, int samples)
void PSS_quit()
char *PSS_get_error()
@@ -130,6 +131,10 @@ def set_volume(channel, volume):
PSS_set_volume(channel, 10 ** volume / 10 )
check_error()
def set_pan(channel, pan, delay):
PSS_set_pan(channel, pan, delay)
check_error()
def set_end_event(channel, event):
PSS_set_endevent(channel, event)
check_error()
+416
View File
@@ -0,0 +1,416 @@
/* subpixel.c - Ren'Py subpixel blitter code.
* Copyright 2009 Tom Rothamel <pytom@bishoujo.us>
*
* This allows one to blit an image at a fractional pixel position. It
* requires MMX to operate. On non-mmx platforms, a traditional blit
* is used instead.
*/
#include "renpy.h"
#include <pygame/pygame.h>
#include <stdio.h>
#include <math.h>
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#define GCC_MMX 1
#include "mmx.h"
#endif
/* MMX Register assignments (between applications of the blitter core).
*
* mm0 - new row 0
* mm1 - new row 1
* mm2 - destination
* mm3 - alpha shift.
* mm4 - old row 0
* mm5 - old row 1
* mm6 - (256 - xfrac)
* mm7 - (256 - yfrac) (or alpha-multiply)
*/
/*************************************************************************
* This is the basic algorithm that does the subpixel blit
* interpolation.
*************************************************************************/
/* mm2 = destination; */
/* unpack mm0; */
/* unpack mm1; */
/* unpack mm2; */
/* // Horizontal */
/* mm4 -= mm0; */
/* mm5 -= mm1; */
/* mm4 *= xfrac; */
/* mm5 *= xfrac; */
/* mm4 >>= 8; */
/* mm5 >>= 8; */
/* mm4 += mm0; */
/* mm5 += mm1; */
/* // Vertical */
/* mm4 -= mm5; */
/* mm4 *= yfrac; */
/* mm4 >>= 8; */
/* mm4 += mm5; */
/* // Alpha blend, */
/* mm5 = mm4; */
/* mm5 >>= mm3; */
/* unpack mm5; */
/* mm4 -= mm2; */
/* unpack mm5; */
/* mm4 *= mm5; */
/* mm4 >>= 8; */
/* mm4 += mm2; */
/* // Store and repeat */
/* pack mm4 */
/* destination = mm4; */
/* mm4 = mm0; */
/* mm5 = mm1; */
#ifdef GCC_MMX
#define dp(s, r) \
movq_r2m(r, scratch); \
printf(s, scratch);
// This expands registers 4 and 5, which are initialized below.
#define MMX_EXPAND() \
pxor_r2r(mm2, mm2); \
punpcklbw_r2r(mm2, mm4); \
punpcklbw_r2r(mm2, mm5);
// This expects the two old pixels to be arranged like:
// mm4 mm0
// mm5 mm1
// alpha shift in mm3
// (256 - xfrac) in mm6
// (256 - yfrac) in mm7
// It does the bilinear interpolation, and leaves the result
// in mm4.
#define MMX_INTERP(dest) \
pxor_r2r(mm2, mm2); \
punpcklbw_r2r(mm2, mm0); \
punpcklbw_r2r(mm2, mm1); \
\
psubw_r2r(mm0, mm4); \
psubw_r2r(mm1, mm5); \
pmullw_r2r(mm6, mm4); \
pmullw_r2r(mm6, mm5); \
psrlw_i2r(8, mm4); \
psrlw_i2r(8, mm5); \
paddb_r2r(mm0, mm4); \
paddb_r2r(mm1, mm5); \
/* p0 in mm4, p1 in mm5 */ \
\
psubw_r2r(mm5, mm4); \
pmullw_r2r(mm7, mm4); \
psrlw_i2r(8, mm4); \
paddb_r2r(mm5, mm4); \
/* p in mm4 */ \
\
pxor_r2r(mm5, mm5); \
movd_m2r((dest), mm2); \
punpcklbw_r2r(mm5, mm2); \
\
movq_r2r(mm4, mm5); \
psrlq_r2r(mm3, mm5); \
punpcklwd_r2r(mm5, mm5); \
punpcklwd_r2r(mm5, mm5); \
psubw_r2r(mm2, mm4); \
pmullw_r2r(mm5, mm4); \
psrlw_i2r(8, mm4); \
paddb_r2r(mm2, mm4); \
packuswb_r2r(mm4, mm4); \
movd_r2m(mm4, (dest)); \
movq_r2r(mm0, mm4); \
movq_r2r(mm1, mm5);
#define min(x, y) ( ((x) < (y)) ? (x) : (y) )
/* This blits pysrc into pydst such that the upper-right corner of
pysrc is at xo, yo relative to pydst. */
int subpixel32(PyObject *pysrc, PyObject *pydst,
float xoffset, float yoffset, int ashift) {
SDL_Surface *src;
SDL_Surface *dst;
int srcpitch, dstpitch;
int srcw, srch;
int dstw, dsth;
unsigned char *srcpixels;
unsigned char *dstpixels;
int xfrac, yfrac;
int xo, yo;
int sx, sy;
int draw_finalx;
int normal_pixels;
int inverted_alpha_mask;
unsigned int pixel;
unsigned int blankpixel;
unsigned char *s0;
unsigned char *s1;
unsigned char *d;
unsigned char *dend;
long long scratch;
if (!SDL_HasMMX()) {
return 0;
}
src = PySurface_AsSurface(pysrc);
dst = PySurface_AsSurface(pydst);
Py_BEGIN_ALLOW_THREADS
srcpixels = (unsigned char *) src->pixels;
dstpixels = (unsigned char *) dst->pixels;
srcpitch = src->pitch;
dstpitch = dst->pitch;
srcw = src->w;
dstw = dst->w;
srch = src->h;
dsth = dst->h;
inverted_alpha_mask = ~(0xff << ashift);
// Due to mmx.
ashift *= 2;
xo = (int) floor(xoffset);
yo = (int) floor(yoffset);
xfrac = (int) ((xoffset - xo) * 255);
yfrac = (int) ((yoffset - yo) * 255);
// Due to the way the interpolator works.
// xfrac = 256 - xfrac;
// yfrac = 256 - yfrac;
if (xo < 0) {
sx = -xo - 1;
xo = 0;
} else {
sx = -1;
}
if (yo < 0) {
sy = -yo - 1;
yo = 0;
} else {
sy = -1;
}
// Figure out how many pixels we need to draw on each line.
normal_pixels = min(srcw - sx - 1, dstw - xo);
if (normal_pixels < dstw - xo) {
draw_finalx = 1;
} else {
draw_finalx = 0;
}
// Load up the mmx registers.
movd_m2r(xfrac, mm6);
punpcklwd_r2r(mm6, mm6);
punpckldq_r2r(mm6, mm6);
movd_m2r(yfrac, mm7);
punpcklwd_r2r(mm7, mm7);
punpckldq_r2r(mm7, mm7);
movd_m2r(ashift, mm3);
if (xo >= dstw) {
goto done;
}
// Draw the first line, when sy == -1.
if (sy == -1) {
if (yo >= dsth) {
goto done;
}
s1 = srcpixels + sx * 4;
if (sx < 0) {
pixel = (* (unsigned int *) (s1 + 4)) & inverted_alpha_mask;
} else {
pixel = * (unsigned int *) s1;
}
blankpixel = pixel & inverted_alpha_mask;
movd_m2r(blankpixel, mm4);
movd_m2r(pixel, mm5);
MMX_EXPAND();
s1 += 4;
d = dstpixels + xo * 4 + yo * dstpitch;
dend = d + normal_pixels * 4;
while (d != dend) {
pixel = * (unsigned int *) s1;
blankpixel = pixel & inverted_alpha_mask;
movd_m2r(blankpixel, mm0);
movd_m2r(pixel, mm1);
MMX_INTERP(* (unsigned int *) d);
d += 4;
s1 += 4;
}
if (draw_finalx) {
s1 -= 4;
movd_m2r(blankpixel, mm0);
movd_m2r(blankpixel, mm1);
MMX_INTERP(* (unsigned int *) d);
}
sy += 1;
yo += 1;
}
// Draw the second and later lines..
while (sy < srch - 1) {
if (yo >= dsth) {
goto done;
}
s0 = srcpixels + sx * 4 + (srcpitch * sy);
s1 = srcpixels + sx * 4 + (srcpitch * (sy + 1));
if (sx < 0) {
blankpixel = (* (unsigned int *) (s0 + 4)) & inverted_alpha_mask;
movd_m2r(blankpixel, mm4);
blankpixel = (* (unsigned int *) (s1 + 4)) & inverted_alpha_mask;
movd_m2r(blankpixel, mm5);
} else {
movd_m2r(* (unsigned int *) s0, mm4);
movd_m2r(* (unsigned int *) s1, mm5);
}
MMX_EXPAND();
s0 += 4;
s1 += 4;
d = dstpixels + xo * 4 + yo * dstpitch;
dend = d + normal_pixels * 4;
unsigned char *dp = d;
while (d != dend) {
movd_m2r(* (unsigned int *) s0, mm0);
movd_m2r(* (unsigned int *) s1, mm1);
MMX_INTERP(* (unsigned int *) d);
d += 4;
s0 += 4;
s1 += 4;
}
if (draw_finalx) {
s0 -= 4;
s1 -= 4;
blankpixel = (* (unsigned int *) s0) & inverted_alpha_mask;
movd_m2r(blankpixel, mm0);
blankpixel = (* (unsigned int *) s1) & inverted_alpha_mask;
movd_m2r(blankpixel, mm1);
MMX_INTERP(* (unsigned int *) d);
}
yo += 1;
sy += 1;
}
// The final part, where we handle the bottom line of the source surface.
if (yo >= dsth) {
goto done;
}
s0 = srcpixels + sx * 4 + (srcpitch * sy);
if (sx < 0) {
pixel = * (unsigned int *) (s0 + 4);
blankpixel = pixel & inverted_alpha_mask;
movd_m2r(blankpixel, mm4);
movd_m2r(blankpixel, mm5);
} else {
pixel = * (unsigned int *) s0;
blankpixel = pixel & inverted_alpha_mask;
movd_m2r(pixel, mm4);
movd_m2r(blankpixel, mm5);
}
MMX_EXPAND();
s0 += 4;
d = dstpixels + xo * 4 + yo * dstpitch;
dend = d + normal_pixels * 4;
while (d != dend) {
pixel = * (unsigned int *) s0;
blankpixel = pixel & inverted_alpha_mask;
movd_m2r(pixel, mm0);
movd_m2r(blankpixel, mm1);
MMX_INTERP(* (unsigned int *) d);
d += 4;
s0 += 4;
}
if (draw_finalx) {
movd_m2r(blankpixel, mm0);
movd_m2r(blankpixel, mm1);
MMX_INTERP(* (unsigned int *) d);
}
done:
// Reset the MMX unit and call it a night.
emms();
Py_END_ALLOW_THREADS
return 1;
}
#else
/* On a non-mmx platform, return 0 to let the pyrex code handle it. */
int subpixel32(PyObject *pysrc, PyObject *pydst,
float xoffset, float yoffset, int ashift) {
return 0;
}
#endif
+3 -3
View File
@@ -48,7 +48,7 @@ def path_to_saves(gamedir):
if 'APPDATA' in os.environ:
return os.environ['APPDATA'] + "/RenPy/" + renpy.config.save_directory
else:
rv = "/RenPy/" + renpy.config.save_directory
rv = "~/RenPy/" + renpy.config.save_directory
return os.path.expanduser(rv)
else:
rv = "~/.renpy/" + renpy.config.save_directory
@@ -68,8 +68,8 @@ def path_to_renpy_base():
##############################################################################
# The version of the Mac Launcher and py4renpy that we use.
macos_version = (6, 8, 0)
linux_version = (6, 8, 0)
macos_version = (6, 9, 0)
linux_version = (6, 9, 0)
if __name__ == "__main__":
+7 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2009 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -27,7 +27,7 @@
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
# Be sure to change script_version in launcher/script_version.rpy, too!
# Also check to see if we have to update renpy.py.
version = "Ren'Py 6.8.0d"
version = "Ren'Py 6.9.0d"
script_version = 5003000
savegame_suffix = "-LT1.save"
@@ -55,6 +55,7 @@ def import_all():
import renpy.display
import renpy.display.presplash
import renpy.display.iliad # Must be before scale.
import renpy.display.scale # Must be before module.
import renpy.display.module
import renpy.display.render # Most display stuff depends on this.
@@ -107,8 +108,11 @@ def reload_all():
import sys
sys.meta_path.pop()
blacklist = [ "renpy", "renpy.bootstrap", "renpy.display", "renpy.display.iliad", "renpy.display.scale" ]
for i in sys.modules.keys():
if i.startswith("renpy") and i != "renpy" and i != "renpy.bootstrap":
if i.startswith("renpy") and i not in blacklist:
del sys.modules[i]
import gc
+12 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2009 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -464,6 +464,9 @@ class Label(Node):
if (args is not None) or (kwargs is not None):
raise Exception("Arguments supplied, but label does not take parameters.")
else:
if renpy.config.label_callback:
renpy.config.label_callback(self.name, renpy.game.context().last_abnormal)
return self.next
else:
if args is None:
@@ -522,6 +525,9 @@ class Label(Node):
renpy.store._args = None
renpy.store._kwargs = None
if renpy.config.label_callback:
renpy.config.label_callback(self.name, renpy.game.context().last_abnormal)
return self.next
class Python(Node):
@@ -936,8 +942,9 @@ class Call(Node):
renpy.store._args = tuple(args)
renpy.store._kwargs = kwargs
rv = renpy.game.context().call(label, return_site=self.next.name)
renpy.game.context().abnormal = True
return rv
@@ -1110,7 +1117,9 @@ class Jump(Node):
if self.expression:
target = renpy.python.py_eval(target)
return renpy.game.script.lookup(target)
rv = renpy.game.script.lookup(target)
renpy.game.context().abnormal = True
return rv
def predict(self, callback):
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2009 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+51 -6
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2009 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -27,6 +27,7 @@
import renpy
import os
import atexit
import time
# Import the appropriate modules, or set them to None if we cannot.
@@ -205,6 +206,28 @@ class Midi(object):
# A singleton Midi object that manages hardware midi playback.
midi = Midi()
# This is a dictionary that accesses attributes of the info object.
class AttrDict(object):
def __init__(self, attr):
self.attr = attr
def __getitem__(self, item):
info = renpy.game.context().info
return getattr(info, self.attr + str(item))
def __setitem__(self, item, value):
info = renpy.game.context().info
setattr(info, self.attr + str(item), value)
def get(self, item, default=None):
info = renpy.game.context().info
return getattr(info, self.attr + str(item), default)
_pan_time = AttrDict("_pan_time")
_pan = AttrDict("_pan")
class QueueEntry(object):
"""
A queue entry object.
@@ -263,6 +286,12 @@ class Channel(object):
# The callback that is called if the queue becomes empty.
self.callback = None
# The time this channel was last panned.
self.pan_time = None
# The delay the next pan should have.
self.pan_delay = 0
def periodic(self):
"""
This is the periodic call that causes this channel to load new stuff
@@ -416,10 +445,15 @@ class Channel(object):
def interact(self):
"""
Called (mostly) once per interaction. Calls the queue callback
if it's becoming empty.
Called (mostly) once per interaction.
"""
if pcm_ok and self.pan_time != _pan_time.get(self.number):
self.pan_time = _pan_time.get(self.number)
pss.set_pan(self.number, _pan.get(self.number, 0.0), self.pan_delay)
self.pan_delay = 0
if not self.queue and self.callback:
self.callback()
@@ -453,6 +487,9 @@ class Channel(object):
qe = QueueEntry(filename, int(fadein * 1000), tight)
self.queue.append(qe)
# Only fade the first thing in.
fadein = 0
if loop:
self.loop = list(filenames)
else:
@@ -484,7 +521,16 @@ class Channel(object):
else:
return pss.get_pos(self.number)
def set_pan(self, pan, delay):
now = time.time()
_pan_time[self.number] = now
_pan[self.number] = pan
if pcm_ok:
self.pan_delay = delay
# The number of channels we support.
NUM_CHANNELS = 8
@@ -642,7 +688,6 @@ def periodic():
if vol != 0:
anything_playing = True
if not anything_playing:
disable_mixer()
return
@@ -699,7 +744,7 @@ def periodic():
except:
if renpy.config.debug_sound:
raise
def interact():
"""
Called at least once per interaction.
+2 -16
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2009 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -33,22 +33,8 @@ music_set = [ ]
unique = time.time()
serial = 0
class AttrDict(object):
def __init__(self, attr):
self.attr = attr
def __getitem__(self, item):
info = renpy.game.context().info
return getattr(info, self.attr + str(item))
def __setitem__(self, item, value):
info = renpy.game.context().info
setattr(info, self.attr + str(item), value)
def get(self, item, default=None):
info = renpy.game.context().info
return getattr(info, self.attr + str(item), default)
AttrDict = renpy.audio.audio.AttrDict
_music_last_filenames = AttrDict('_music_last_filenames')
_music_last_tight = AttrDict('_music_last_tight')

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