Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fa4ffae54 | |||
| 4ecd72de6e | |||
| 3ec495c3fc | |||
| 5efc437384 | |||
| a777f4d3b1 | |||
| ff139808ff | |||
| 07136f9be8 | |||
| 35fc2295e9 | |||
| 2b262ccca3 | |||
| d42aab3dff | |||
| 612c347498 | |||
| 3c4540131a | |||
| 43317f6e02 | |||
| 523742d8de | |||
| 9516ee910e | |||
| 3ea31a3862 | |||
| 649411a4ef | |||
| a0e60e5453 | |||
| e3f1f40a78 | |||
| d0177f4c52 | |||
| 84a3a55a03 | |||
| 048075b47a | |||
| fab097c92a | |||
| 9d26bd8c04 | |||
| 664d243c23 | |||
| 9a0906655d | |||
| 13d60f2741 | |||
| 7d4de64d0b | |||
| 9ada2d9884 | |||
| a5f1951cfb | |||
| 98850e4c5c | |||
| 709e1f925d | |||
| b11ae331a5 | |||
| 3ba4b26b99 | |||
| b864077017 | |||
| d411dff1c0 | |||
| 7fc7453450 | |||
| 1799971885 | |||
| b999911292 | |||
| 29e0f9ad21 | |||
| d821b7eb8b | |||
| 272a214304 | |||
| 7f15b351ee | |||
| 5a6a12a14a | |||
| 01493c7063 | |||
| 244055fcb7 | |||
| 0415af5f31 | |||
| f73372c924 | |||
| 65cdc24e37 | |||
| 1b2d439651 | |||
| b383942c69 | |||
| 73bd109abb | |||
| 33ffd5dedb |
@@ -28,3 +28,4 @@ launchertrans.rpy
|
||||
jcc
|
||||
scite/scite.zip
|
||||
screenshot*
|
||||
.ropeproject
|
||||
|
||||
@@ -1,3 +1,181 @@
|
||||
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.
|
||||
|
||||
|
||||
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,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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 335 B |
@@ -1,697 +0,0 @@
|
||||
# cardgame.rpy - Cardgame support for Ren'Py
|
||||
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# This software may be distributed in modified or unmodified form,
|
||||
# provided:
|
||||
#
|
||||
# (1) This complete license notice is retained.
|
||||
#
|
||||
# (2) This software and all software and data files distributed
|
||||
# alongside this software and intended to be loaded in the same
|
||||
# memory space may be redistributed without requirement for
|
||||
# payment, notification, or other forms of compensation.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Commercial licensing for this software is available, please
|
||||
# contact pytom@bishoujo.us for information.
|
||||
|
||||
init python:
|
||||
|
||||
import pygame
|
||||
|
||||
DRAG_NONE = 0
|
||||
DRAG_CARD = 1
|
||||
DRAG_ABOVE = 2
|
||||
DRAG_STACK = 3
|
||||
DRAG_TOP = 4
|
||||
|
||||
# Returns the overlap of the area between the two
|
||||
# rectangles.
|
||||
def __rect_overlap_area(r1, r2):
|
||||
if r1 is None or r2 is None:
|
||||
return 0
|
||||
|
||||
x1, y1, w1, h1 = r1
|
||||
x2, y2, w2, h2 = r2
|
||||
|
||||
maxleft = max(x1, x2)
|
||||
minright = min(x1 + w1, x2 + w2)
|
||||
maxtop = max(y1, y2)
|
||||
minbottom = min(y1 + h1, y2 + h2)
|
||||
|
||||
if minright < maxleft:
|
||||
return 0
|
||||
|
||||
if minbottom < maxtop:
|
||||
return 0
|
||||
|
||||
return (minright - maxleft) * (minbottom - maxtop)
|
||||
|
||||
def __default_can_drag(table, stack, card):
|
||||
return table.get_faceup(card)
|
||||
|
||||
class Table(renpy.Displayable):
|
||||
|
||||
def __init__(self, back=None, base=None, springback=0.1, rotate=0.1, can_drag=__default_can_drag, doubleclick=.33, **kwargs):
|
||||
|
||||
renpy.Displayable.__init__(self, **kwargs)
|
||||
|
||||
# A map from card value to the card object corresponding to
|
||||
# that value.
|
||||
self.cards = { }
|
||||
|
||||
# A list of the stacks that have been defined.
|
||||
self.stacks = [ ]
|
||||
|
||||
# The back of cards that don't have a more specific back
|
||||
# defined.
|
||||
self.back = renpy.easy.displayable_or_none(back)
|
||||
|
||||
# The base of stacks that don't have a more specific base
|
||||
# defined.
|
||||
self.base = renpy.easy.displayable_or_none(base)
|
||||
|
||||
# The amount of time it takes for cards to springback
|
||||
# into their rightful place.
|
||||
self.springback = springback
|
||||
|
||||
# The amount of time it takes for cards to rotate into
|
||||
# their proper orientation.
|
||||
self.rotate = rotate
|
||||
|
||||
# A function that is called to tell if we can drag a
|
||||
# particular card.
|
||||
self.can_drag = can_drag
|
||||
|
||||
# The time between clicks for the click to be considered a
|
||||
# double-click.
|
||||
self.doubleclick = doubleclick
|
||||
|
||||
# Are we sensitive to input? [doc]
|
||||
self.sensitive = True
|
||||
|
||||
# The last click event.
|
||||
self.last_event = CardEvent()
|
||||
|
||||
# The card that has been clicked.
|
||||
self.click_card = None
|
||||
|
||||
# The stack that has been clicked.
|
||||
self.click_stack = None
|
||||
|
||||
# The list of cards that are being dragged.
|
||||
self.drag_cards = [ ]
|
||||
|
||||
# Are we dragging the cards?
|
||||
self.dragging = False
|
||||
|
||||
# The position where we clicked.
|
||||
self.click_x = 0
|
||||
self.click_y = 0
|
||||
|
||||
# The amount of time we've been shown for.
|
||||
self.st = 0
|
||||
|
||||
# This shows the table on the given layer.
|
||||
def show(self, layer='master'):
|
||||
|
||||
for v in self.cards.itervalues():
|
||||
v.offset = __Fixed(0, 0)
|
||||
|
||||
ui.layer(layer)
|
||||
ui.add(self)
|
||||
ui.close()
|
||||
|
||||
# This hides the table.
|
||||
def hide(self, layer='master'):
|
||||
ui.layer(layer)
|
||||
ui.remove(self)
|
||||
ui.close()
|
||||
|
||||
# This controls sensitivity.
|
||||
def set_sensitive(self, value):
|
||||
self.sensitive = value
|
||||
|
||||
def get_card(self, value):
|
||||
if value not in self.cards:
|
||||
raise Exception("No card has the value %r." % value)
|
||||
|
||||
return self.cards[value]
|
||||
|
||||
# This sets the faceup status of a card.
|
||||
def set_faceup(self, card, faceup=True):
|
||||
self.get_card(card).faceup = faceup
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def get_faceup(self, card):
|
||||
return self.get_card(card).faceup
|
||||
|
||||
# This sets the rotation of a card.
|
||||
def set_rotate(self, card, rotation):
|
||||
__Rotate(self.get_card(card), rotation)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def get_rotate(self, card):
|
||||
return self.get_card(card).rotate.rotate_limit()
|
||||
|
||||
def add_marker(self, card, marker):
|
||||
self.get_card(card).markers.append(marker)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
def remove_marker(self, card, marker):
|
||||
self.get_card(card).markers.remove(marker)
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
# Called to create a new card.
|
||||
def card(self, value, face, back=None):
|
||||
self.cards[value] = __Card(self, value, face, back)
|
||||
|
||||
# Called to create a new stack.
|
||||
def stack(self, x, y, xoff=0, yoff=0, show=1024, base=None,
|
||||
click=False, drag=DRAG_NONE, drop=False, hidden=False):
|
||||
|
||||
rv = __Stack(self, x, y, xoff, yoff, show, base, click, drag, drop, hidden)
|
||||
|
||||
self.stacks.append(rv)
|
||||
return rv
|
||||
|
||||
# Force a redraw on each interaction.
|
||||
def per_interact(self):
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
self.st = st
|
||||
|
||||
rv = renpy.Render(width, height)
|
||||
|
||||
for s in self.stacks:
|
||||
|
||||
if s.hidden:
|
||||
s.rect = None
|
||||
for c in s.cards:
|
||||
c.rect = None
|
||||
continue
|
||||
|
||||
s.render_to(rv, width, height, st, at)
|
||||
|
||||
for c in s.cards:
|
||||
c.render_to(rv, width, height, st, at)
|
||||
|
||||
return rv
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
self.st = st
|
||||
|
||||
if not self.sensitive:
|
||||
return
|
||||
|
||||
grabbed = renpy.display.focus.get_grab()
|
||||
|
||||
if (grabbed is not None) and (grabbed is not self):
|
||||
return
|
||||
|
||||
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
|
||||
|
||||
if self.click_stack:
|
||||
return
|
||||
|
||||
stack = None
|
||||
card = None
|
||||
|
||||
for s in self.stacks:
|
||||
|
||||
sx, sy, sw, sh = s.rect
|
||||
if sx <= x and sy <= y and sx + sw > x and sy + sh > y:
|
||||
stack = s
|
||||
|
||||
|
||||
for c in s.cards[-s.show:]:
|
||||
if c.rect is None:
|
||||
continue
|
||||
|
||||
cx, cy, cw, ch = c.rect
|
||||
if cx <= x and cy <= y and cx + cw > x and cy + ch > y:
|
||||
card = c
|
||||
stack = c.stack
|
||||
|
||||
if stack is None:
|
||||
return
|
||||
|
||||
# Grab the display.
|
||||
renpy.display.focus.set_grab(self)
|
||||
|
||||
# Don't let the user grab a moving card.
|
||||
if card is not None:
|
||||
xoffset, yoffset = card.offset.offset()
|
||||
if xoffset or yoffset:
|
||||
return
|
||||
|
||||
# Move the stack containing the card to the front.
|
||||
self.stacks.remove(stack)
|
||||
self.stacks.append(stack)
|
||||
|
||||
if stack.click or stack.drag:
|
||||
self.click_card = card
|
||||
self.click_stack = stack
|
||||
|
||||
if card is None or not self.can_drag(self, card.stack, card.value):
|
||||
self.drag_cards = [ ]
|
||||
elif card.stack.drag == DRAG_CARD:
|
||||
self.drag_cards = [ card ]
|
||||
elif card.stack.drag == DRAG_ABOVE:
|
||||
self.drag_cards = [ ]
|
||||
for c in card.stack.cards:
|
||||
if c is card or self.drag_cards:
|
||||
self.drag_cards.append(c)
|
||||
elif card.stack.drag == DRAG_STACK:
|
||||
self.drag_cards = list(card.stack.cards)
|
||||
elif card.stack.drag == DRAG_TOP:
|
||||
if card.stack.cards[-1] is card:
|
||||
self.drag_cards = [ card ]
|
||||
else:
|
||||
self.drag_cards = [ ]
|
||||
|
||||
for c in self.drag_cards:
|
||||
c.offset = __Fixed(0, 0)
|
||||
|
||||
self.click_x = x
|
||||
self.click_y = y
|
||||
self.dragging = False
|
||||
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
if ev.type == pygame.MOUSEMOTION or (ev.type == pygame.MOUSEBUTTONUP and ev.button == 1):
|
||||
|
||||
if abs(x - self.click_x) > 7 or abs(y - self.click_y) > 7:
|
||||
self.dragging = True
|
||||
|
||||
dx = x - self.click_x
|
||||
dy = y - self.click_y
|
||||
|
||||
for c in self.drag_cards:
|
||||
xoffset, yoffset = c.offset.offset()
|
||||
|
||||
cdx = dx - xoffset
|
||||
cdy = dy - yoffset
|
||||
|
||||
c.offset = __Fixed(dx, dy)
|
||||
|
||||
if c.rect:
|
||||
cx, cy, cw, ch = c.rect
|
||||
cx += cdx
|
||||
cy += cdy
|
||||
c.rect = (cx, cy, cw, ch)
|
||||
|
||||
area = 0
|
||||
dststack = None
|
||||
dstcard = None
|
||||
|
||||
for s in self.stacks:
|
||||
if not s.drop:
|
||||
continue
|
||||
|
||||
for c in self.drag_cards:
|
||||
|
||||
if c.stack == s:
|
||||
continue
|
||||
a = __rect_overlap_area(c.rect, s.rect)
|
||||
if a >= area:
|
||||
dststack = s
|
||||
dstcard = None
|
||||
area = a
|
||||
|
||||
for c1 in s.cards:
|
||||
a = __rect_overlap_area(c.rect, c1.rect)
|
||||
if a >= area:
|
||||
dststack = s
|
||||
dstcard = c1
|
||||
area = a
|
||||
|
||||
if area == 0:
|
||||
dststack = None
|
||||
dstcard = None
|
||||
|
||||
renpy.redraw(self, 0)
|
||||
|
||||
if ev.type == pygame.MOUSEMOTION:
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
if ev.type == pygame.MOUSEBUTTONUP and ev.button == 1:
|
||||
|
||||
# Ungrab the display.
|
||||
renpy.display.focus.set_grab(None)
|
||||
|
||||
evt = None
|
||||
|
||||
if self.dragging:
|
||||
if dststack is not None and self.drag_cards:
|
||||
|
||||
evt = CardEvent()
|
||||
evt.type = "drag"
|
||||
evt.table = self
|
||||
evt.stack = self.click_stack
|
||||
evt.card = self.click_card.value
|
||||
evt.drag_cards = [c.value for c in self.drag_cards]
|
||||
evt.drop_stack = dststack
|
||||
if dstcard:
|
||||
evt.drop_card = dstcard.value
|
||||
evt.time = st
|
||||
|
||||
else:
|
||||
|
||||
if self.click_stack.click:
|
||||
|
||||
evt = CardEvent()
|
||||
evt.type = "click"
|
||||
evt.table = self
|
||||
evt.stack = self.click_stack
|
||||
if self.click_card:
|
||||
evt.card = self.click_card.value
|
||||
else:
|
||||
evt.card = None
|
||||
|
||||
evt.time = st
|
||||
|
||||
if (evt.type == self.last_event.type
|
||||
and evt.stack == self.last_event.stack
|
||||
and evt.card == self.last_event.card
|
||||
and evt.time < self.last_event.time + self.doubleclick):
|
||||
|
||||
evt.type = "doubleclick"
|
||||
|
||||
if evt is not None:
|
||||
self.last_event = evt
|
||||
|
||||
for c in self.drag_cards:
|
||||
c.springback()
|
||||
|
||||
self.click_card = None
|
||||
self.click_stack = None
|
||||
self.drag_cards = [ ]
|
||||
|
||||
if evt is not None:
|
||||
return evt
|
||||
else:
|
||||
raise renpy.IgnoreEvent()
|
||||
|
||||
|
||||
class CardEvent(object):
|
||||
|
||||
def __init__(self):
|
||||
self.type = None
|
||||
self.stack = None
|
||||
self.card = None
|
||||
self.drag_cards = None
|
||||
self.drop_stack = None
|
||||
self.drop_card = None
|
||||
self.time = 0
|
||||
|
||||
# Represents a stack of one or more cards, which can be placed on the
|
||||
# table.
|
||||
class __Stack(object):
|
||||
|
||||
def __init__(
|
||||
self, table,
|
||||
x, y,
|
||||
xoff, yoff,
|
||||
show, base,
|
||||
click, drag, drop,
|
||||
hidden):
|
||||
|
||||
|
||||
# The table this stack belongs to.
|
||||
self.table = table
|
||||
|
||||
# The x and y coordinates of the center of the top card of
|
||||
# this stack.
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
# The offset in the x and y directions of each successive
|
||||
# card.
|
||||
self.xoff = xoff
|
||||
self.yoff = yoff
|
||||
|
||||
# The number of cards to show from this stack. (We show the
|
||||
# last show cards if this is less than the numebr of cards
|
||||
# in the stack.)
|
||||
self.show = show
|
||||
|
||||
# The image that is shown behind the stack. If None, the
|
||||
# background is taken from the table.
|
||||
self.base = base
|
||||
|
||||
# Should we report click events on this stack?
|
||||
self.click = click
|
||||
|
||||
# Should we allow dragging this stack? If so, how?
|
||||
self.drag = drag
|
||||
|
||||
# Should we allow dropping to this stack?
|
||||
self.drop = drop
|
||||
|
||||
# Is this stack hidden?
|
||||
self.hidden = hidden
|
||||
|
||||
# The list of cards in this stack.
|
||||
self.cards = [ ]
|
||||
|
||||
# The rectangle for the background of this effect.
|
||||
self.rect = None
|
||||
|
||||
def insert(self, index, card):
|
||||
card = self.table.get_card(card)
|
||||
|
||||
if card.stack:
|
||||
card.stack.cards.remove(card)
|
||||
|
||||
card.stack = self
|
||||
self.cards.insert(index, card)
|
||||
|
||||
self.table.stacks.remove(self)
|
||||
self.table.stacks.append(self)
|
||||
|
||||
card.springback()
|
||||
|
||||
def append(self, card):
|
||||
if card in self.cards:
|
||||
self.insert(len(self.cards) - 1, card)
|
||||
else:
|
||||
self.insert(len(self.cards), card)
|
||||
|
||||
def remove(self, card):
|
||||
card = self.table.get_card(card)
|
||||
self.cards.remove(card)
|
||||
card.stack = None
|
||||
card.rect = None
|
||||
|
||||
def deal(self):
|
||||
if not self.cards:
|
||||
return None
|
||||
|
||||
card = self.cards[-1]
|
||||
self.remove(card.value)
|
||||
return card.value
|
||||
|
||||
def shuffle(self):
|
||||
renpy.random.shuffle(self.cards)
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cards)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.cards[idx].value
|
||||
|
||||
def __iter__(self):
|
||||
for i in self.cards:
|
||||
yield i.value
|
||||
|
||||
def __contains__(self, item):
|
||||
return self.table.get_card(card) in self.cards
|
||||
|
||||
def render_to(self, rv, width, height, st, at):
|
||||
|
||||
base = self.base or self.table.base
|
||||
|
||||
if base is None:
|
||||
return
|
||||
|
||||
surf = renpy.render(base, width, height, st, at)
|
||||
cw, ch = surf.get_size()
|
||||
|
||||
cx = self.x - cw / 2
|
||||
cy = self.y - ch / 2
|
||||
|
||||
self.rect = (cx, cy, cw, ch)
|
||||
rv.blit(surf, (cx, cy))
|
||||
|
||||
class __Card(object):
|
||||
|
||||
def __init__(self, table, value, face, back):
|
||||
|
||||
# The table this card belongs to.
|
||||
self.table = table
|
||||
|
||||
# The value of this card.
|
||||
self.value = value
|
||||
|
||||
# The face of this card.
|
||||
self.face = renpy.easy.displayable(face)
|
||||
|
||||
# The back of this card. If None, then the back is taken from
|
||||
# the table the card belongs to.
|
||||
self.back = renpy.easy.displayable_or_none(back)
|
||||
|
||||
# Is this card faceup (or face down?)
|
||||
self.faceup = True
|
||||
|
||||
# Object that's called to decide how rotated this card should
|
||||
# be.
|
||||
self.rotate = None
|
||||
|
||||
# A series of highlights that should be drawn over this card.
|
||||
self.highlights = [ ]
|
||||
|
||||
# The stack this card is in.
|
||||
self.stack = None
|
||||
|
||||
# An object that gives the offset of this card relative to
|
||||
# where it would normally be placed.
|
||||
self.offset = __Fixed(0, 0)
|
||||
|
||||
# The rectangle where this card was last drawn to the screen
|
||||
# at.
|
||||
self.rect = None
|
||||
|
||||
__Rotate(self, 0)
|
||||
|
||||
# Returns the base x and y placement of this card.
|
||||
def place(self):
|
||||
s = self.stack
|
||||
offset = max(len(s.cards) - s.show, 0)
|
||||
index = max(s.cards.index(self) - offset, 0)
|
||||
|
||||
return (s.x + s.xoff * index, s.y + s.yoff * index)
|
||||
|
||||
def springback(self):
|
||||
if self.rect is None:
|
||||
self.offset = __Fixed(0, 0)
|
||||
else:
|
||||
self.offset = __Springback(self)
|
||||
|
||||
def render_to(self, rv, width, height, st, at):
|
||||
|
||||
x, y = self.place()
|
||||
xoffset, yoffset = self.offset.offset()
|
||||
x += xoffset
|
||||
y += yoffset
|
||||
|
||||
if self.faceup:
|
||||
d = self.face
|
||||
else:
|
||||
d = self.back or self.table.back
|
||||
|
||||
# TODO: Figure out if we can reuse some of this.
|
||||
|
||||
if self.highlights:
|
||||
d = Fixed(* ([d] + [renpy.easy.displayable(i) for i in self.highlights]))
|
||||
|
||||
r = self.rotate.rotate()
|
||||
if r:
|
||||
d = RotoZoom(r, r, 0, 1, 1, 0)(d)
|
||||
|
||||
surf = renpy.render(d, width, height, st, at)
|
||||
w, h = surf.get_size()
|
||||
|
||||
x -= w / 2
|
||||
y -= h / 2
|
||||
|
||||
self.rect = (x, y, w, h)
|
||||
|
||||
rv.blit(surf, (x, y))
|
||||
|
||||
def __repr__(self):
|
||||
return "<__Card %r>" % self.value
|
||||
|
||||
|
||||
class __Springback(object):
|
||||
|
||||
def __init__(self, card):
|
||||
self.card = card
|
||||
self.table = table = card.table
|
||||
|
||||
self.start = table.st
|
||||
|
||||
cx, cy, cw, ch = self.card.rect
|
||||
x = cx + cw / 2
|
||||
y = cy + ch / 2
|
||||
|
||||
self.startx = x
|
||||
self.starty = y
|
||||
|
||||
def offset(self):
|
||||
|
||||
t = (self.table.st - self.start) / self.table.springback
|
||||
t = min(t, 1.0)
|
||||
|
||||
if t < 1.0:
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
px, py = self.card.place()
|
||||
|
||||
return int((self.startx - px) * (1.0 - t)), int((self.starty - py) * (1.0 - t))
|
||||
|
||||
|
||||
class __Fixed(object):
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def offset(self):
|
||||
return self.x, self.y
|
||||
|
||||
|
||||
class __Rotate(object):
|
||||
def __init__(self, card, amount):
|
||||
|
||||
self.table = table = card.table
|
||||
self.start = table.st
|
||||
|
||||
if card.rotate is None:
|
||||
self.start_rotate = amount
|
||||
else:
|
||||
self.start_rotate = card.rotate.rotate()
|
||||
|
||||
self.end_rotate = amount
|
||||
|
||||
card.rotate = self
|
||||
|
||||
|
||||
def rotate(self):
|
||||
|
||||
if self.start_rotate == self.end_rotate:
|
||||
return self.start_rotate
|
||||
|
||||
t = (self.table.st - self.start) / self.table.springback
|
||||
t = min(t, 1.0)
|
||||
|
||||
if t < 1.0:
|
||||
renpy.redraw(self.table, 0)
|
||||
|
||||
return self.start_rotate + (self.end_rotate - self.start_rotate) * t
|
||||
|
||||
def rotate_limit(self):
|
||||
return self.end_rotate
|
||||
|
Before Width: | Height: | Size: 140 KiB |
@@ -1,336 +0,0 @@
|
||||
# klondike.rpy - Klondike Solitaire
|
||||
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# This software may be distributed in modified or unmodified form,
|
||||
# provided:
|
||||
#
|
||||
# (1) This complete license notice is retained.
|
||||
#
|
||||
# (2) This software and all software and data files distributed
|
||||
# alongside this software and intended to be loaded in the same
|
||||
# memory space may be redistributed without requirement for
|
||||
# payment, notification, or other forms of compensation.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Commercial licensing for this software is available, please
|
||||
# contact pytom@bishoujo.us for information.
|
||||
|
||||
init python:
|
||||
|
||||
class Klondike(object):
|
||||
|
||||
# We represent a card as a (suit, rank) tuple. The suit is one of the
|
||||
# following four constants, while the rank is 1 for ace, 2 for 2,
|
||||
# ..., 10 for 10, 11 for jack, 12 for queen, 13 for king.
|
||||
CLUB = 0
|
||||
SPADE = 1
|
||||
HEART = 2
|
||||
DIAMOND = 3
|
||||
|
||||
def __init__(self, deal=3):
|
||||
|
||||
# Constants that let us easily change where the game is
|
||||
# located.
|
||||
LEFT=140
|
||||
TOP=58
|
||||
COL_SPACING = 90
|
||||
ROW_SPACING = 120
|
||||
CARD_XSPACING = 20
|
||||
CARD_YSPACING = 30
|
||||
|
||||
# Store the parameters.
|
||||
self.deal = deal
|
||||
|
||||
# Create the table, stock, and waste.
|
||||
self.table = t = Table(base="card/base.png", back="card/back.png")
|
||||
self.stock = t.stack(LEFT, TOP, xoff=0, yoff=0, click=True)
|
||||
self.waste = t.stack(LEFT + COL_SPACING, TOP, xoff=CARD_XSPACING, drag=DRAG_TOP, show=self.deal, click=True)
|
||||
|
||||
# The 4 foundation stacks.
|
||||
self.foundations = [ ]
|
||||
for i in range(0, 4):
|
||||
s = t.stack(LEFT + COL_SPACING * (i + 3), TOP, xoff=0, yoff=0, drag=DRAG_TOP, drop=True)
|
||||
self.foundations.append(s)
|
||||
|
||||
# The 7 tableau stacks.
|
||||
self.tableau = [ ]
|
||||
for i in range(0, 7):
|
||||
s = t.stack(LEFT + COL_SPACING * i, TOP + ROW_SPACING, xoff=0, yoff=CARD_YSPACING, drag=DRAG_ABOVE, click=True, drop=True)
|
||||
self.tableau.append(s)
|
||||
|
||||
# Create the stock and shuffle it.
|
||||
for rank in range(1, 14):
|
||||
for suit in range(0, 4):
|
||||
value = (suit, rank)
|
||||
t.card(value, "card/%d.png" % self.card_num(suit, rank))
|
||||
t.set_faceup(value, False)
|
||||
self.stock.append(value)
|
||||
|
||||
self.stock.shuffle()
|
||||
|
||||
# Deal out the initial tableau.
|
||||
for i in range(0, 7):
|
||||
for j in range(i, 7):
|
||||
c = self.stock.deal()
|
||||
self.tableau[j].append(c)
|
||||
|
||||
# Ensure that the bottom of each tableau is faceup.
|
||||
for i in range(0, 7):
|
||||
if self.tableau[i]:
|
||||
self.table.set_faceup(self.tableau[i][-1], True)
|
||||
|
||||
|
||||
# This figures out the image filename for a given suit and rank.
|
||||
def card_num(self, suit, rank):
|
||||
ranks = [ None, 1, 49, 45, 41, 37, 33, 29, 25, 21, 17, 13, 9, 5 ]
|
||||
return suit + ranks[rank]
|
||||
|
||||
def show(self):
|
||||
self.table.show()
|
||||
|
||||
def hide(self):
|
||||
self.table.hide()
|
||||
|
||||
def tableau_drag(self, evt):
|
||||
|
||||
card = evt.drag_cards[0]
|
||||
cards = evt.drag_cards
|
||||
stack = evt.drop_stack
|
||||
|
||||
csuit, crank = card
|
||||
|
||||
# If the stack is empty, allow a king to be dragged to it.
|
||||
if not stack:
|
||||
if crank == 13:
|
||||
for i in cards:
|
||||
stack.append(i)
|
||||
|
||||
return "tableau_drag"
|
||||
|
||||
# Otherwise, the stack has a bottom card.
|
||||
bottom = stack[-1]
|
||||
bsuit, brank = bottom
|
||||
|
||||
# Figure out which of the stacks are black.
|
||||
cblack = (csuit == self.SPADE) or (csuit == self.CLUB)
|
||||
bblack = (bsuit == self.SPADE) or (bsuit == self.CLUB)
|
||||
|
||||
# Can we legally place the cards?
|
||||
if (bblack != cblack) and (crank == brank - 1):
|
||||
|
||||
# Place the cards:
|
||||
for i in cards:
|
||||
stack.append(i)
|
||||
|
||||
return "tableau_drag"
|
||||
|
||||
return False
|
||||
|
||||
def foundation_drag(self, evt):
|
||||
|
||||
# We can only drag one card at a time to a foundation.
|
||||
if len(evt.drag_cards) != 1:
|
||||
return False
|
||||
|
||||
suit, rank = evt.drag_cards[0]
|
||||
|
||||
# If there is a card on the foundation already, then
|
||||
# check to see if we're dropping then next one in
|
||||
# sequence.
|
||||
if len(evt.drop_stack):
|
||||
dsuit, drank = evt.drop_stack[-1]
|
||||
if suit == dsuit and rank == drank + 1:
|
||||
evt.drop_stack.append(evt.drag_cards[0])
|
||||
return "foundation_drag"
|
||||
|
||||
# Otherwise, make sure we're dropping an ace.
|
||||
else:
|
||||
if rank == 1:
|
||||
evt.drop_stack.append(evt.drag_cards[0])
|
||||
return "foundation_drag"
|
||||
|
||||
return False
|
||||
|
||||
def tableau_doubleclick(self, evt):
|
||||
|
||||
# Make sure that there's at least one card in the stack.
|
||||
if not evt.stack:
|
||||
return False
|
||||
|
||||
# The bottom card in the stack.
|
||||
card = evt.stack[-1]
|
||||
suit, rank = card
|
||||
|
||||
# If the card is an ace, find an open foundation and put it
|
||||
# there.
|
||||
if rank == 1:
|
||||
for i in self.foundations:
|
||||
if not i:
|
||||
i.append(card)
|
||||
break
|
||||
return "foundation_drag"
|
||||
|
||||
# Otherwise, see if there's a foundation where we can put
|
||||
# the card.
|
||||
for i in self.foundations:
|
||||
if not i:
|
||||
continue
|
||||
|
||||
fsuit, frank = i[-1]
|
||||
if suit == fsuit and rank == frank + 1:
|
||||
i.append(card)
|
||||
return "foundation_drag"
|
||||
|
||||
return False
|
||||
|
||||
def stock_click(self, evt):
|
||||
|
||||
# If there are cards in the stock, dispense up to three3
|
||||
# of them.
|
||||
if self.stock:
|
||||
for i in range(0, self.deal):
|
||||
if self.stock:
|
||||
c = self.stock[-1]
|
||||
self.table.set_faceup(c, True)
|
||||
self.waste.append(c)
|
||||
|
||||
return "stock_click"
|
||||
|
||||
# Otherwise, move the contents of the waste to the stock.
|
||||
else:
|
||||
while self.waste:
|
||||
c = self.waste[-1]
|
||||
self.table.set_faceup(c, False)
|
||||
self.stock.append(c)
|
||||
|
||||
return "stock_click"
|
||||
|
||||
|
||||
def interact(self):
|
||||
|
||||
evt = ui.interact()
|
||||
rv = False
|
||||
|
||||
# Check the various events, and dispatch them to the methods
|
||||
# that handle them.
|
||||
if evt.type == "drag":
|
||||
if evt.drop_stack in self.tableau:
|
||||
rv = self.tableau_drag(evt)
|
||||
|
||||
elif evt.drop_stack in self.foundations:
|
||||
rv = self.foundation_drag(evt)
|
||||
|
||||
elif evt.type == "click":
|
||||
if evt.stack == self.stock:
|
||||
rv = self.stock_click(evt)
|
||||
|
||||
elif evt.type == "doubleclick":
|
||||
if (evt.stack in self.tableau) or (evt.stack is self.waste):
|
||||
rv = self.tableau_doubleclick(evt)
|
||||
|
||||
# Ensure that the bottom card in each tableau is faceup.
|
||||
for i in range(0, 7):
|
||||
if self.tableau[i]:
|
||||
self.table.set_faceup(self.tableau[i][-1], True)
|
||||
|
||||
# Check to see if any of the foundations has less than
|
||||
# 13 cards in it. If it does, return False. Otherwise,
|
||||
# return True.
|
||||
for i in self.foundations:
|
||||
if len(i) != 13:
|
||||
return rv
|
||||
|
||||
return "win"
|
||||
|
||||
# Sets things as sensitive (or not).
|
||||
def set_sensitive(self, value):
|
||||
self.table.set_sensitive(value)
|
||||
|
||||
# Utility functions.
|
||||
|
||||
# Is it okay to drag the over card onto under, where under is
|
||||
# part of a tableau.
|
||||
def can_hint(self, under, over):
|
||||
usuit, urank = under
|
||||
osuit, orank = over
|
||||
|
||||
if orank == 1:
|
||||
return False
|
||||
|
||||
ublack = (usuit == self.SPADE) or (usuit == self.CLUB)
|
||||
oblack = (osuit == self.SPADE) or (osuit == self.CLUB)
|
||||
|
||||
if (oblack != ublack) and (orank == urank - 1):
|
||||
return True
|
||||
|
||||
# Returns the first faceup card in the stack.
|
||||
def first_faceup(self, s):
|
||||
for c in s:
|
||||
if self.table.get_faceup(c):
|
||||
return c
|
||||
|
||||
# This tries to find a reasonable hint, and returns it as a
|
||||
# pair of cardnames.
|
||||
def hint(self):
|
||||
|
||||
for i in self.tableau:
|
||||
if not i:
|
||||
continue
|
||||
|
||||
over = self.first_faceup(i)
|
||||
|
||||
for j in self.tableau:
|
||||
if not j or i is j:
|
||||
continue
|
||||
|
||||
under = j[-1]
|
||||
|
||||
if self.can_hint(under, over):
|
||||
return (under, over)
|
||||
|
||||
if self.waste:
|
||||
|
||||
over = self.waste[-1]
|
||||
|
||||
for j in self.tableau:
|
||||
if not j:
|
||||
continue
|
||||
|
||||
under = j[-1]
|
||||
|
||||
if self.can_hint(under, over):
|
||||
return (under, over)
|
||||
|
||||
return None, None
|
||||
|
||||
def card_name(self, c):
|
||||
suit, rank = c
|
||||
|
||||
return [
|
||||
"INVALID",
|
||||
"Ace",
|
||||
"Two",
|
||||
"Three",
|
||||
"four",
|
||||
"Five",
|
||||
"Six",
|
||||
"Seven",
|
||||
"Eight",
|
||||
"Nine",
|
||||
"Ten",
|
||||
"Jack",
|
||||
"Queen",
|
||||
"King" ][rank] + " of " + [
|
||||
"Clubs",
|
||||
"Spades",
|
||||
"Hearts",
|
||||
"Diamonds" ][suit]
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 138 KiB |
@@ -1,247 +0,0 @@
|
||||
## This file contains some of the options that can be changed to customize
|
||||
## your Ren'Py game. It only contains the most common options... there
|
||||
## is quite a bit more customization you can do.
|
||||
##
|
||||
## Lines beginning with two '#' marks are comments, and you shouldn't
|
||||
## uncomment them. Lines beginning with a single '#' mark are
|
||||
## commented-out code, and you may want to uncomment them when
|
||||
## appropriate.
|
||||
|
||||
init -1 python hide:
|
||||
|
||||
## Should we enable the use of developer tools? This should be
|
||||
## set to False before the game is released, so the user can't
|
||||
## cheat using developer tools.
|
||||
|
||||
config.developer = True
|
||||
|
||||
## These control the width and height of the screen.
|
||||
|
||||
config.screen_width = 800
|
||||
config.screen_height = 600
|
||||
|
||||
## This controls the title of the window, when Ren'Py is
|
||||
## running in a window.
|
||||
|
||||
config.window_title = u"Ren'Py Cardgame Demo"
|
||||
|
||||
#########################################
|
||||
# Layouts
|
||||
|
||||
## This enables the use of an in-game menu that is made out of
|
||||
## buttons.
|
||||
|
||||
layout.button_menu()
|
||||
|
||||
#########################################
|
||||
# Themes
|
||||
|
||||
## We then want to call a theme function. themes.roundrect is
|
||||
## a theme that features the use of rounded rectangles. It's
|
||||
## the only theme we currently support.
|
||||
##
|
||||
## The theme function takes a number of parameters that can
|
||||
## customize the color scheme.
|
||||
|
||||
theme.roundrect(
|
||||
|
||||
## The color of an idle widget face.
|
||||
widget = "#7AA27B",
|
||||
|
||||
## The color of a focused widget face.
|
||||
widget_hover = "#A3C7A3",
|
||||
|
||||
## The color of the text in a widget.
|
||||
widget_text = "#CDE0CE",
|
||||
|
||||
## The color of the text in a selected widget. (For
|
||||
## example, the current value of a preference.)
|
||||
widget_selected = "#ffffff",
|
||||
|
||||
## The color of a disabled widget face.
|
||||
disabled = "#426143",
|
||||
|
||||
## The color of disabled widget text.
|
||||
disabled_text = "#819981",
|
||||
|
||||
## The color of informational labels.
|
||||
label = "#ffffff",
|
||||
|
||||
## The color of a frame containing widgets.
|
||||
frame = "#245536",
|
||||
|
||||
## If this is True, the in-game window is rounded. If False,
|
||||
## the in-game window is square.
|
||||
rounded_window = False,
|
||||
|
||||
## The background of the main menu. This can be a color
|
||||
## beginning with '#', or an image filename. The latter
|
||||
## should take up the full height and width of the screen.
|
||||
mm_root = "mainmenu.jpg",
|
||||
|
||||
## The background of the game menu. This can be a color
|
||||
## beginning with '#', or an image filename. The latter
|
||||
## should take up the full height and width of the screen.
|
||||
gm_root = "table.jpg",
|
||||
|
||||
## And we're done with the theme. The theme will customize
|
||||
## various styles, so if we want to change them, we should
|
||||
## do so below.
|
||||
)
|
||||
|
||||
|
||||
#########################################
|
||||
## These settings let you customize the window containing the
|
||||
## dialogue and narration, by replacing it with an image.
|
||||
|
||||
## The background of the window. In a Frame, the two numbers
|
||||
## are the size of the left/right and top/bottom borders,
|
||||
## respectively.
|
||||
|
||||
# style.window.background = Frame("frame.png", 12, 12)
|
||||
|
||||
## Margin is space surrounding the window, where the background
|
||||
## is not drawn.
|
||||
|
||||
# style.window.left_margin = 6
|
||||
# style.window.right_margin = 6
|
||||
# style.window.top_margin = 6
|
||||
# style.window.bottom_margin = 6
|
||||
|
||||
## Padding is space inside the window, where the background is
|
||||
## drawn.
|
||||
|
||||
# style.window.left_padding = 6
|
||||
# style.window.right_padding = 6
|
||||
# style.window.top_padding = 6
|
||||
# style.window.bottom_padding = 6
|
||||
|
||||
## This is the minimum height of the window, including the margins
|
||||
## and padding.
|
||||
|
||||
# style.window.yminimum = 250
|
||||
|
||||
|
||||
#########################################
|
||||
## This lets you change the placement of the main menu.
|
||||
|
||||
## The way placement works is that we find an anchor point
|
||||
## inside a displayable, and a position (pos) point on the
|
||||
## screen. We then place the displayable so the two points are
|
||||
## at the same place.
|
||||
|
||||
## An anchor/pos can be given as an integer or a floating point
|
||||
## number. If an integer, the number is interpreted as a number
|
||||
## of pixels from the upper-left corner. If a floating point,
|
||||
## the number is interpreted as a fraction of the size of the
|
||||
## displayable or screen.
|
||||
|
||||
# style.mm_menu_frame.xpos = 0.5
|
||||
# style.mm_menu_frame.xanchor = 0.5
|
||||
# style.mm_menu_frame.ypos = 0.75
|
||||
# style.mm_menu_frame.yanchor = 0.5
|
||||
|
||||
|
||||
#########################################
|
||||
## These let you customize the default font used for text in Ren'Py.
|
||||
|
||||
## The file containing the default font.
|
||||
|
||||
# style.default.font = "DejaVuSans.ttf"
|
||||
|
||||
## The default size of text.
|
||||
|
||||
# style.default.size = 22
|
||||
|
||||
## Note that these only change the size of some of the text. Other
|
||||
## buttons have their own styles.
|
||||
|
||||
|
||||
#########################################
|
||||
## These settings let you change some of the sounds that are used by
|
||||
## Ren'Py.
|
||||
|
||||
## Set this to False if the game does not have any sound effects.
|
||||
|
||||
config.has_sound = True
|
||||
|
||||
## Set this to False if the game does not have any music.
|
||||
|
||||
config.has_music = True
|
||||
|
||||
## Set this to False if the game does not have voicing.
|
||||
|
||||
config.has_voice = True
|
||||
|
||||
## Sounds that are used when button and imagemaps are clicked.
|
||||
|
||||
# style.button.activate_sound = "click.wav"
|
||||
# style.imagemap.activate_sound = "click.wav"
|
||||
|
||||
## Sounds that are used when entering and exiting the game menu.
|
||||
|
||||
# config.enter_sound = "click.wav"
|
||||
# config.exit_sound = "click.wav"
|
||||
|
||||
## A sample sound that can be played to check the sound volume.
|
||||
|
||||
# config.sample_sound = "click.wav"
|
||||
|
||||
## Music that is played while the user is at the main menu.
|
||||
|
||||
# config.main_menu_music = "main_menu_theme.ogg"
|
||||
|
||||
|
||||
#########################################
|
||||
## Transitions.
|
||||
|
||||
## Used when entering the game menu from the game.
|
||||
|
||||
config.enter_transition = dissolve
|
||||
|
||||
## Used when exiting the game menu to the game.
|
||||
|
||||
config.exit_transition = dissolve
|
||||
|
||||
## Used between screens of the game menu.
|
||||
|
||||
config.intra_transition = dissolve
|
||||
|
||||
## Used when entering the game menu from the main menu.
|
||||
|
||||
config.main_game_transition = dissolve
|
||||
|
||||
## Used when returning to the main menu from the game.
|
||||
|
||||
config.game_main_transition = dissolve
|
||||
|
||||
## Used when entering the main menu from the splashscreen.
|
||||
|
||||
config.end_splash_transition = dissolve
|
||||
|
||||
## Used when entering the main menu after the game has ended.
|
||||
|
||||
config.end_game_transition = fade
|
||||
|
||||
## Used when a game is loaded.
|
||||
|
||||
config.after_load_transition = dissolve
|
||||
|
||||
|
||||
#########################################
|
||||
## Default values of Preferences.
|
||||
|
||||
## Note: These options are only evaluated the first time a
|
||||
## game is run. To have them run a second time, delete
|
||||
## game/saves/persistent
|
||||
|
||||
## Should we start in fullscreen mode?
|
||||
|
||||
config.default_fullscreen = False
|
||||
|
||||
## The default text speed in characters per second. 0 is infinite.
|
||||
|
||||
config.default_text_cps = 0
|
||||
|
||||
config.save_directory = "cardgame-11754"
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
# You can place the script of your game in this file.
|
||||
|
||||
init:
|
||||
$ e = Character('Eileen', color="#c8ffc8")
|
||||
|
||||
image eileen happy = "eileen_happy.png"
|
||||
image bg table = "table.jpg"
|
||||
image dim = "#0008"
|
||||
|
||||
# Some styles for show text.
|
||||
$ style.centered_text.drop_shadow = (2, 2)
|
||||
$ style.centered_text.drop_shadow_color = "#000b"
|
||||
|
||||
label start:
|
||||
|
||||
scene bg table
|
||||
|
||||
python:
|
||||
k = Klondike(1)
|
||||
k.set_sensitive(False)
|
||||
k.show()
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
e "Welcome to the cardgame demo. Let's play some solitaire!"
|
||||
|
||||
e "I might show up from time to time to give you some advice, but it's up to you if you want to take it."
|
||||
|
||||
e "Good luck!"
|
||||
|
||||
label continue:
|
||||
|
||||
hide dim
|
||||
hide eileen
|
||||
with dissolve
|
||||
|
||||
label quick_continue:
|
||||
|
||||
$ hint_count = renpy.random.randint(10, 20)
|
||||
|
||||
while True:
|
||||
|
||||
python:
|
||||
|
||||
ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
|
||||
k.set_sensitive(True)
|
||||
event = k.interact()
|
||||
|
||||
if event:
|
||||
renpy.checkpoint()
|
||||
|
||||
if event == "win":
|
||||
jump win
|
||||
|
||||
if event == "tableau_drag" or event == "stock_click":
|
||||
$ hint_count -= 1
|
||||
if hint_count <= 0:
|
||||
jump hint
|
||||
|
||||
label win:
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
"Congratulations!"
|
||||
|
||||
jump newgame
|
||||
|
||||
label giveup:
|
||||
|
||||
$ k.set_sensitive(False)
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
menu:
|
||||
e "Are you sure you want to give up?"
|
||||
|
||||
"Yes":
|
||||
|
||||
"Oh well, better luck next time."
|
||||
|
||||
jump newgame
|
||||
|
||||
"No":
|
||||
|
||||
jump continue
|
||||
|
||||
label newgame:
|
||||
|
||||
menu:
|
||||
e "Would you like to try again?"
|
||||
|
||||
"Yes":
|
||||
pass
|
||||
|
||||
"No":
|
||||
e "Well, I hope to see you again soon."
|
||||
return
|
||||
|
||||
e "Okay, here we go!"
|
||||
|
||||
scene bg table
|
||||
|
||||
python:
|
||||
k = Klondike(1)
|
||||
k.sensitive = False
|
||||
k.show()
|
||||
|
||||
jump continue
|
||||
|
||||
|
||||
label hint:
|
||||
|
||||
$ under, over = k.hint()
|
||||
|
||||
$ print under, over
|
||||
|
||||
if under is None:
|
||||
jump quick_continue
|
||||
|
||||
$ under = k.card_name(under)
|
||||
$ over = k.card_name(over)
|
||||
|
||||
$ k.set_sensitive(False)
|
||||
|
||||
show dim
|
||||
show eileen happy
|
||||
with dissolve
|
||||
|
||||
$ hint = renpy.random.randint(0, 2)
|
||||
|
||||
if hint == 0:
|
||||
e "Maybe put the %(over)s on top of the %(under)s."
|
||||
|
||||
elif hint == 1:
|
||||
e "You can try moving the %(over)s to the %(under)s."
|
||||
|
||||
elif hint == 2:
|
||||
e "I think something can go on the %(under)s."
|
||||
|
||||
jump continue
|
||||
|
||||
|
||||
# This has nothing to do with card games.
|
||||
label splashscreen:
|
||||
|
||||
scene bg table
|
||||
$ renpy.pause(1.0)
|
||||
|
||||
show text "According to legend, prospectors in the klondike would carry with them a deck of cards."
|
||||
with dissolve
|
||||
with Pause(5.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "If they were ever lost, they'd start playing a game of solitaire."
|
||||
with dissolve
|
||||
with Pause(4.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "Without fail, help would soon arrive..."
|
||||
with dissolve
|
||||
with Pause(3.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
show text "... saying \"put the Five of Spades on the Six of Hearts.\""
|
||||
|
||||
with dissolve
|
||||
with Pause(4.0)
|
||||
hide text
|
||||
with dissolve
|
||||
with Pause(1.0)
|
||||
|
||||
return
|
||||
|
Before Width: | Height: | Size: 116 KiB |
@@ -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)),
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -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__":
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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__":
|
||||
|
||||
|
||||
@@ -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.0c"
|
||||
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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
@@ -150,6 +150,22 @@ def set_volume(volume, channel=0):
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
def set_pan(pan, delay, channel=0):
|
||||
"""
|
||||
Sets the volume of this channel, as a fraction of the volume of the
|
||||
mixer controlling the channel.
|
||||
|
||||
This volume is not persisted or rolled-back, as are volumes set with
|
||||
renpy.music.set_volume for music channels.
|
||||
"""
|
||||
|
||||
try:
|
||||
c = renpy.audio.audio.get_channel(channel)
|
||||
c.set_pan(pan, delay)
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
def is_playing(channel=0):
|
||||
"""
|
||||
|
||||