Compare commits

...

13 Commits

Author SHA1 Message Date
Tom Rothamel 7fc7453450 Releasing 6.8.1a. 2008-11-23 13:05:47 -05:00
Tom Rothamel 1799971885 Implement RENPY_LESS_UPDATES and RENPY_LESS_MOUSE.
Build iLiad distributions.

Add support for rebuilding distributions.
2008-11-23 11:15:26 -05:00
Tom Rothamel b999911292 Untested support for building iLiad distributions. 2008-11-21 02:59:49 -05:00
Tom Rothamel 29e0f9ad21 Working on iLiad support. 2008-11-21 02:09:54 -05:00
Tom Rothamel d821b7eb8b Fixed a bug that occured when space characters were inserted
immediately after a newline.
2008-11-20 01:32:40 -05:00
Tom Rothamel 272a214304 Modified lint slightly.
Added Alpha.
2008-11-18 01:35:29 -05:00
Tom Rothamel 7f15b351ee Add support for a user-defined default statement.
Speed up parsing a little.
2008-11-17 02:40:55 -05:00
Tom Rothamel 5a6a12a14a Blacklist renpy.display from being reloaded. 2008-11-17 00:05:31 -05:00
Tom Rothamel 01493c7063 Splitting cardgame. 2008-11-10 01:30:01 -05:00
Tom Rothamel 244055fcb7 Modified presplash.py so that it ignores errors forking of a second process. 2008-11-09 15:50:22 -05:00
Tom Rothamel 0415af5f31 Better support for scaling.
The launcher will now may sys.executable point to an existing file.
2008-11-09 15:36:16 -05:00
Tom Rothamel f73372c924 iRex iLiad support. 2008-11-02 16:14:16 -05:00
Tom Rothamel 65cdc24e37 Add staticgray support, for iLiad. 2008-11-02 08:43:53 -05:00
92 changed files with 739 additions and 1610 deletions
+49
View File
@@ -1,3 +1,52 @@
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
-------------------
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 B

-697
View File
@@ -1,697 +0,0 @@
# cardgame.rpy - Cardgame support for Ren'Py
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
#
# This software may be distributed in modified or unmodified form,
# provided:
#
# (1) This complete license notice is retained.
#
# (2) This software and all software and data files distributed
# alongside this software and intended to be loaded in the same
# memory space may be redistributed without requirement for
# payment, notification, or other forms of compensation.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Commercial licensing for this software is available, please
# contact pytom@bishoujo.us for information.
init python:
import pygame
DRAG_NONE = 0
DRAG_CARD = 1
DRAG_ABOVE = 2
DRAG_STACK = 3
DRAG_TOP = 4
# Returns the overlap of the area between the two
# rectangles.
def __rect_overlap_area(r1, r2):
if r1 is None or r2 is None:
return 0
x1, y1, w1, h1 = r1
x2, y2, w2, h2 = r2
maxleft = max(x1, x2)
minright = min(x1 + w1, x2 + w2)
maxtop = max(y1, y2)
minbottom = min(y1 + h1, y2 + h2)
if minright < maxleft:
return 0
if minbottom < maxtop:
return 0
return (minright - maxleft) * (minbottom - maxtop)
def __default_can_drag(table, stack, card):
return table.get_faceup(card)
class Table(renpy.Displayable):
def __init__(self, back=None, base=None, springback=0.1, rotate=0.1, can_drag=__default_can_drag, doubleclick=.33, **kwargs):
renpy.Displayable.__init__(self, **kwargs)
# A map from card value to the card object corresponding to
# that value.
self.cards = { }
# A list of the stacks that have been defined.
self.stacks = [ ]
# The back of cards that don't have a more specific back
# defined.
self.back = renpy.easy.displayable_or_none(back)
# The base of stacks that don't have a more specific base
# defined.
self.base = renpy.easy.displayable_or_none(base)
# The amount of time it takes for cards to springback
# into their rightful place.
self.springback = springback
# The amount of time it takes for cards to rotate into
# their proper orientation.
self.rotate = rotate
# A function that is called to tell if we can drag a
# particular card.
self.can_drag = can_drag
# The time between clicks for the click to be considered a
# double-click.
self.doubleclick = doubleclick
# Are we sensitive to input? [doc]
self.sensitive = True
# The last click event.
self.last_event = CardEvent()
# The card that has been clicked.
self.click_card = None
# The stack that has been clicked.
self.click_stack = None
# The list of cards that are being dragged.
self.drag_cards = [ ]
# Are we dragging the cards?
self.dragging = False
# The position where we clicked.
self.click_x = 0
self.click_y = 0
# The amount of time we've been shown for.
self.st = 0
# This shows the table on the given layer.
def show(self, layer='master'):
for v in self.cards.itervalues():
v.offset = __Fixed(0, 0)
ui.layer(layer)
ui.add(self)
ui.close()
# This hides the table.
def hide(self, layer='master'):
ui.layer(layer)
ui.remove(self)
ui.close()
# This controls sensitivity.
def set_sensitive(self, value):
self.sensitive = value
def get_card(self, value):
if value not in self.cards:
raise Exception("No card has the value %r." % value)
return self.cards[value]
# This sets the faceup status of a card.
def set_faceup(self, card, faceup=True):
self.get_card(card).faceup = faceup
renpy.redraw(self, 0)
def get_faceup(self, card):
return self.get_card(card).faceup
# This sets the rotation of a card.
def set_rotate(self, card, rotation):
__Rotate(self.get_card(card), rotation)
renpy.redraw(self, 0)
def get_rotate(self, card):
return self.get_card(card).rotate.rotate_limit()
def add_marker(self, card, marker):
self.get_card(card).markers.append(marker)
renpy.redraw(self, 0)
def remove_marker(self, card, marker):
self.get_card(card).markers.remove(marker)
renpy.redraw(self, 0)
# Called to create a new card.
def card(self, value, face, back=None):
self.cards[value] = __Card(self, value, face, back)
# Called to create a new stack.
def stack(self, x, y, xoff=0, yoff=0, show=1024, base=None,
click=False, drag=DRAG_NONE, drop=False, hidden=False):
rv = __Stack(self, x, y, xoff, yoff, show, base, click, drag, drop, hidden)
self.stacks.append(rv)
return rv
# Force a redraw on each interaction.
def per_interact(self):
renpy.redraw(self, 0)
def render(self, width, height, st, at):
self.st = st
rv = renpy.Render(width, height)
for s in self.stacks:
if s.hidden:
s.rect = None
for c in s.cards:
c.rect = None
continue
s.render_to(rv, width, height, st, at)
for c in s.cards:
c.render_to(rv, width, height, st, at)
return rv
def event(self, ev, x, y, st):
self.st = st
if not self.sensitive:
return
grabbed = renpy.display.focus.get_grab()
if (grabbed is not None) and (grabbed is not self):
return
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
if self.click_stack:
return
stack = None
card = None
for s in self.stacks:
sx, sy, sw, sh = s.rect
if sx <= x and sy <= y and sx + sw > x and sy + sh > y:
stack = s
for c in s.cards[-s.show:]:
if c.rect is None:
continue
cx, cy, cw, ch = c.rect
if cx <= x and cy <= y and cx + cw > x and cy + ch > y:
card = c
stack = c.stack
if stack is None:
return
# Grab the display.
renpy.display.focus.set_grab(self)
# Don't let the user grab a moving card.
if card is not None:
xoffset, yoffset = card.offset.offset()
if xoffset or yoffset:
return
# Move the stack containing the card to the front.
self.stacks.remove(stack)
self.stacks.append(stack)
if stack.click or stack.drag:
self.click_card = card
self.click_stack = stack
if card is None or not self.can_drag(self, card.stack, card.value):
self.drag_cards = [ ]
elif card.stack.drag == DRAG_CARD:
self.drag_cards = [ card ]
elif card.stack.drag == DRAG_ABOVE:
self.drag_cards = [ ]
for c in card.stack.cards:
if c is card or self.drag_cards:
self.drag_cards.append(c)
elif card.stack.drag == DRAG_STACK:
self.drag_cards = list(card.stack.cards)
elif card.stack.drag == DRAG_TOP:
if card.stack.cards[-1] is card:
self.drag_cards = [ card ]
else:
self.drag_cards = [ ]
for c in self.drag_cards:
c.offset = __Fixed(0, 0)
self.click_x = x
self.click_y = y
self.dragging = False
renpy.redraw(self, 0)
raise renpy.IgnoreEvent()
if ev.type == pygame.MOUSEMOTION or (ev.type == pygame.MOUSEBUTTONUP and ev.button == 1):
if abs(x - self.click_x) > 7 or abs(y - self.click_y) > 7:
self.dragging = True
dx = x - self.click_x
dy = y - self.click_y
for c in self.drag_cards:
xoffset, yoffset = c.offset.offset()
cdx = dx - xoffset
cdy = dy - yoffset
c.offset = __Fixed(dx, dy)
if c.rect:
cx, cy, cw, ch = c.rect
cx += cdx
cy += cdy
c.rect = (cx, cy, cw, ch)
area = 0
dststack = None
dstcard = None
for s in self.stacks:
if not s.drop:
continue
for c in self.drag_cards:
if c.stack == s:
continue
a = __rect_overlap_area(c.rect, s.rect)
if a >= area:
dststack = s
dstcard = None
area = a
for c1 in s.cards:
a = __rect_overlap_area(c.rect, c1.rect)
if a >= area:
dststack = s
dstcard = c1
area = a
if area == 0:
dststack = None
dstcard = None
renpy.redraw(self, 0)
if ev.type == pygame.MOUSEMOTION:
raise renpy.IgnoreEvent()
if ev.type == pygame.MOUSEBUTTONUP and ev.button == 1:
# Ungrab the display.
renpy.display.focus.set_grab(None)
evt = None
if self.dragging:
if dststack is not None and self.drag_cards:
evt = CardEvent()
evt.type = "drag"
evt.table = self
evt.stack = self.click_stack
evt.card = self.click_card.value
evt.drag_cards = [c.value for c in self.drag_cards]
evt.drop_stack = dststack
if dstcard:
evt.drop_card = dstcard.value
evt.time = st
else:
if self.click_stack.click:
evt = CardEvent()
evt.type = "click"
evt.table = self
evt.stack = self.click_stack
if self.click_card:
evt.card = self.click_card.value
else:
evt.card = None
evt.time = st
if (evt.type == self.last_event.type
and evt.stack == self.last_event.stack
and evt.card == self.last_event.card
and evt.time < self.last_event.time + self.doubleclick):
evt.type = "doubleclick"
if evt is not None:
self.last_event = evt
for c in self.drag_cards:
c.springback()
self.click_card = None
self.click_stack = None
self.drag_cards = [ ]
if evt is not None:
return evt
else:
raise renpy.IgnoreEvent()
class CardEvent(object):
def __init__(self):
self.type = None
self.stack = None
self.card = None
self.drag_cards = None
self.drop_stack = None
self.drop_card = None
self.time = 0
# Represents a stack of one or more cards, which can be placed on the
# table.
class __Stack(object):
def __init__(
self, table,
x, y,
xoff, yoff,
show, base,
click, drag, drop,
hidden):
# The table this stack belongs to.
self.table = table
# The x and y coordinates of the center of the top card of
# this stack.
self.x = x
self.y = y
# The offset in the x and y directions of each successive
# card.
self.xoff = xoff
self.yoff = yoff
# The number of cards to show from this stack. (We show the
# last show cards if this is less than the numebr of cards
# in the stack.)
self.show = show
# The image that is shown behind the stack. If None, the
# background is taken from the table.
self.base = base
# Should we report click events on this stack?
self.click = click
# Should we allow dragging this stack? If so, how?
self.drag = drag
# Should we allow dropping to this stack?
self.drop = drop
# Is this stack hidden?
self.hidden = hidden
# The list of cards in this stack.
self.cards = [ ]
# The rectangle for the background of this effect.
self.rect = None
def insert(self, index, card):
card = self.table.get_card(card)
if card.stack:
card.stack.cards.remove(card)
card.stack = self
self.cards.insert(index, card)
self.table.stacks.remove(self)
self.table.stacks.append(self)
card.springback()
def append(self, card):
if card in self.cards:
self.insert(len(self.cards) - 1, card)
else:
self.insert(len(self.cards), card)
def remove(self, card):
card = self.table.get_card(card)
self.cards.remove(card)
card.stack = None
card.rect = None
def deal(self):
if not self.cards:
return None
card = self.cards[-1]
self.remove(card.value)
return card.value
def shuffle(self):
renpy.random.shuffle(self.cards)
renpy.redraw(self.table, 0)
def __len__(self):
return len(self.cards)
def __getitem__(self, idx):
return self.cards[idx].value
def __iter__(self):
for i in self.cards:
yield i.value
def __contains__(self, item):
return self.table.get_card(card) in self.cards
def render_to(self, rv, width, height, st, at):
base = self.base or self.table.base
if base is None:
return
surf = renpy.render(base, width, height, st, at)
cw, ch = surf.get_size()
cx = self.x - cw / 2
cy = self.y - ch / 2
self.rect = (cx, cy, cw, ch)
rv.blit(surf, (cx, cy))
class __Card(object):
def __init__(self, table, value, face, back):
# The table this card belongs to.
self.table = table
# The value of this card.
self.value = value
# The face of this card.
self.face = renpy.easy.displayable(face)
# The back of this card. If None, then the back is taken from
# the table the card belongs to.
self.back = renpy.easy.displayable_or_none(back)
# Is this card faceup (or face down?)
self.faceup = True
# Object that's called to decide how rotated this card should
# be.
self.rotate = None
# A series of highlights that should be drawn over this card.
self.highlights = [ ]
# The stack this card is in.
self.stack = None
# An object that gives the offset of this card relative to
# where it would normally be placed.
self.offset = __Fixed(0, 0)
# The rectangle where this card was last drawn to the screen
# at.
self.rect = None
__Rotate(self, 0)
# Returns the base x and y placement of this card.
def place(self):
s = self.stack
offset = max(len(s.cards) - s.show, 0)
index = max(s.cards.index(self) - offset, 0)
return (s.x + s.xoff * index, s.y + s.yoff * index)
def springback(self):
if self.rect is None:
self.offset = __Fixed(0, 0)
else:
self.offset = __Springback(self)
def render_to(self, rv, width, height, st, at):
x, y = self.place()
xoffset, yoffset = self.offset.offset()
x += xoffset
y += yoffset
if self.faceup:
d = self.face
else:
d = self.back or self.table.back
# TODO: Figure out if we can reuse some of this.
if self.highlights:
d = Fixed(* ([d] + [renpy.easy.displayable(i) for i in self.highlights]))
r = self.rotate.rotate()
if r:
d = RotoZoom(r, r, 0, 1, 1, 0)(d)
surf = renpy.render(d, width, height, st, at)
w, h = surf.get_size()
x -= w / 2
y -= h / 2
self.rect = (x, y, w, h)
rv.blit(surf, (x, y))
def __repr__(self):
return "<__Card %r>" % self.value
class __Springback(object):
def __init__(self, card):
self.card = card
self.table = table = card.table
self.start = table.st
cx, cy, cw, ch = self.card.rect
x = cx + cw / 2
y = cy + ch / 2
self.startx = x
self.starty = y
def offset(self):
t = (self.table.st - self.start) / self.table.springback
t = min(t, 1.0)
if t < 1.0:
renpy.redraw(self.table, 0)
px, py = self.card.place()
return int((self.startx - px) * (1.0 - t)), int((self.starty - py) * (1.0 - t))
class __Fixed(object):
def __init__(self, x, y):
self.x = x
self.y = y
def offset(self):
return self.x, self.y
class __Rotate(object):
def __init__(self, card, amount):
self.table = table = card.table
self.start = table.st
if card.rotate is None:
self.start_rotate = amount
else:
self.start_rotate = card.rotate.rotate()
self.end_rotate = amount
card.rotate = self
def rotate(self):
if self.start_rotate == self.end_rotate:
return self.start_rotate
t = (self.table.st - self.start) / self.table.springback
t = min(t, 1.0)
if t < 1.0:
renpy.redraw(self.table, 0)
return self.start_rotate + (self.end_rotate - self.start_rotate) * t
def rotate_limit(self):
return self.end_rotate
Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

-336
View File
@@ -1,336 +0,0 @@
# klondike.rpy - Klondike Solitaire
# Copyright (C) 2008 PyTom <pytom@bishoujo.us>
#
# This software may be distributed in modified or unmodified form,
# provided:
#
# (1) This complete license notice is retained.
#
# (2) This software and all software and data files distributed
# alongside this software and intended to be loaded in the same
# memory space may be redistributed without requirement for
# payment, notification, or other forms of compensation.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Commercial licensing for this software is available, please
# contact pytom@bishoujo.us for information.
init python:
class Klondike(object):
# We represent a card as a (suit, rank) tuple. The suit is one of the
# following four constants, while the rank is 1 for ace, 2 for 2,
# ..., 10 for 10, 11 for jack, 12 for queen, 13 for king.
CLUB = 0
SPADE = 1
HEART = 2
DIAMOND = 3
def __init__(self, deal=3):
# Constants that let us easily change where the game is
# located.
LEFT=140
TOP=58
COL_SPACING = 90
ROW_SPACING = 120
CARD_XSPACING = 20
CARD_YSPACING = 30
# Store the parameters.
self.deal = deal
# Create the table, stock, and waste.
self.table = t = Table(base="card/base.png", back="card/back.png")
self.stock = t.stack(LEFT, TOP, xoff=0, yoff=0, click=True)
self.waste = t.stack(LEFT + COL_SPACING, TOP, xoff=CARD_XSPACING, drag=DRAG_TOP, show=self.deal, click=True)
# The 4 foundation stacks.
self.foundations = [ ]
for i in range(0, 4):
s = t.stack(LEFT + COL_SPACING * (i + 3), TOP, xoff=0, yoff=0, drag=DRAG_TOP, drop=True)
self.foundations.append(s)
# The 7 tableau stacks.
self.tableau = [ ]
for i in range(0, 7):
s = t.stack(LEFT + COL_SPACING * i, TOP + ROW_SPACING, xoff=0, yoff=CARD_YSPACING, drag=DRAG_ABOVE, click=True, drop=True)
self.tableau.append(s)
# Create the stock and shuffle it.
for rank in range(1, 14):
for suit in range(0, 4):
value = (suit, rank)
t.card(value, "card/%d.png" % self.card_num(suit, rank))
t.set_faceup(value, False)
self.stock.append(value)
self.stock.shuffle()
# Deal out the initial tableau.
for i in range(0, 7):
for j in range(i, 7):
c = self.stock.deal()
self.tableau[j].append(c)
# Ensure that the bottom of each tableau is faceup.
for i in range(0, 7):
if self.tableau[i]:
self.table.set_faceup(self.tableau[i][-1], True)
# This figures out the image filename for a given suit and rank.
def card_num(self, suit, rank):
ranks = [ None, 1, 49, 45, 41, 37, 33, 29, 25, 21, 17, 13, 9, 5 ]
return suit + ranks[rank]
def show(self):
self.table.show()
def hide(self):
self.table.hide()
def tableau_drag(self, evt):
card = evt.drag_cards[0]
cards = evt.drag_cards
stack = evt.drop_stack
csuit, crank = card
# If the stack is empty, allow a king to be dragged to it.
if not stack:
if crank == 13:
for i in cards:
stack.append(i)
return "tableau_drag"
# Otherwise, the stack has a bottom card.
bottom = stack[-1]
bsuit, brank = bottom
# Figure out which of the stacks are black.
cblack = (csuit == self.SPADE) or (csuit == self.CLUB)
bblack = (bsuit == self.SPADE) or (bsuit == self.CLUB)
# Can we legally place the cards?
if (bblack != cblack) and (crank == brank - 1):
# Place the cards:
for i in cards:
stack.append(i)
return "tableau_drag"
return False
def foundation_drag(self, evt):
# We can only drag one card at a time to a foundation.
if len(evt.drag_cards) != 1:
return False
suit, rank = evt.drag_cards[0]
# If there is a card on the foundation already, then
# check to see if we're dropping then next one in
# sequence.
if len(evt.drop_stack):
dsuit, drank = evt.drop_stack[-1]
if suit == dsuit and rank == drank + 1:
evt.drop_stack.append(evt.drag_cards[0])
return "foundation_drag"
# Otherwise, make sure we're dropping an ace.
else:
if rank == 1:
evt.drop_stack.append(evt.drag_cards[0])
return "foundation_drag"
return False
def tableau_doubleclick(self, evt):
# Make sure that there's at least one card in the stack.
if not evt.stack:
return False
# The bottom card in the stack.
card = evt.stack[-1]
suit, rank = card
# If the card is an ace, find an open foundation and put it
# there.
if rank == 1:
for i in self.foundations:
if not i:
i.append(card)
break
return "foundation_drag"
# Otherwise, see if there's a foundation where we can put
# the card.
for i in self.foundations:
if not i:
continue
fsuit, frank = i[-1]
if suit == fsuit and rank == frank + 1:
i.append(card)
return "foundation_drag"
return False
def stock_click(self, evt):
# If there are cards in the stock, dispense up to three3
# of them.
if self.stock:
for i in range(0, self.deal):
if self.stock:
c = self.stock[-1]
self.table.set_faceup(c, True)
self.waste.append(c)
return "stock_click"
# Otherwise, move the contents of the waste to the stock.
else:
while self.waste:
c = self.waste[-1]
self.table.set_faceup(c, False)
self.stock.append(c)
return "stock_click"
def interact(self):
evt = ui.interact()
rv = False
# Check the various events, and dispatch them to the methods
# that handle them.
if evt.type == "drag":
if evt.drop_stack in self.tableau:
rv = self.tableau_drag(evt)
elif evt.drop_stack in self.foundations:
rv = self.foundation_drag(evt)
elif evt.type == "click":
if evt.stack == self.stock:
rv = self.stock_click(evt)
elif evt.type == "doubleclick":
if (evt.stack in self.tableau) or (evt.stack is self.waste):
rv = self.tableau_doubleclick(evt)
# Ensure that the bottom card in each tableau is faceup.
for i in range(0, 7):
if self.tableau[i]:
self.table.set_faceup(self.tableau[i][-1], True)
# Check to see if any of the foundations has less than
# 13 cards in it. If it does, return False. Otherwise,
# return True.
for i in self.foundations:
if len(i) != 13:
return rv
return "win"
# Sets things as sensitive (or not).
def set_sensitive(self, value):
self.table.set_sensitive(value)
# Utility functions.
# Is it okay to drag the over card onto under, where under is
# part of a tableau.
def can_hint(self, under, over):
usuit, urank = under
osuit, orank = over
if orank == 1:
return False
ublack = (usuit == self.SPADE) or (usuit == self.CLUB)
oblack = (osuit == self.SPADE) or (osuit == self.CLUB)
if (oblack != ublack) and (orank == urank - 1):
return True
# Returns the first faceup card in the stack.
def first_faceup(self, s):
for c in s:
if self.table.get_faceup(c):
return c
# This tries to find a reasonable hint, and returns it as a
# pair of cardnames.
def hint(self):
for i in self.tableau:
if not i:
continue
over = self.first_faceup(i)
for j in self.tableau:
if not j or i is j:
continue
under = j[-1]
if self.can_hint(under, over):
return (under, over)
if self.waste:
over = self.waste[-1]
for j in self.tableau:
if not j:
continue
under = j[-1]
if self.can_hint(under, over):
return (under, over)
return None, None
def card_name(self, c):
suit, rank = c
return [
"INVALID",
"Ace",
"Two",
"Three",
"four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
"Jack",
"Queen",
"King" ][rank] + " of " + [
"Clubs",
"Spades",
"Hearts",
"Diamonds" ][suit]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

-247
View File
@@ -1,247 +0,0 @@
## This file contains some of the options that can be changed to customize
## your Ren'Py game. It only contains the most common options... there
## is quite a bit more customization you can do.
##
## Lines beginning with two '#' marks are comments, and you shouldn't
## uncomment them. Lines beginning with a single '#' mark are
## commented-out code, and you may want to uncomment them when
## appropriate.
init -1 python hide:
## Should we enable the use of developer tools? This should be
## set to False before the game is released, so the user can't
## cheat using developer tools.
config.developer = True
## These control the width and height of the screen.
config.screen_width = 800
config.screen_height = 600
## This controls the title of the window, when Ren'Py is
## running in a window.
config.window_title = u"Ren'Py Cardgame Demo"
#########################################
# Layouts
## This enables the use of an in-game menu that is made out of
## buttons.
layout.button_menu()
#########################################
# Themes
## We then want to call a theme function. themes.roundrect is
## a theme that features the use of rounded rectangles. It's
## the only theme we currently support.
##
## The theme function takes a number of parameters that can
## customize the color scheme.
theme.roundrect(
## The color of an idle widget face.
widget = "#7AA27B",
## The color of a focused widget face.
widget_hover = "#A3C7A3",
## The color of the text in a widget.
widget_text = "#CDE0CE",
## The color of the text in a selected widget. (For
## example, the current value of a preference.)
widget_selected = "#ffffff",
## The color of a disabled widget face.
disabled = "#426143",
## The color of disabled widget text.
disabled_text = "#819981",
## The color of informational labels.
label = "#ffffff",
## The color of a frame containing widgets.
frame = "#245536",
## If this is True, the in-game window is rounded. If False,
## the in-game window is square.
rounded_window = False,
## The background of the main menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
mm_root = "mainmenu.jpg",
## The background of the game menu. This can be a color
## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
gm_root = "table.jpg",
## And we're done with the theme. The theme will customize
## various styles, so if we want to change them, we should
## do so below.
)
#########################################
## These settings let you customize the window containing the
## dialogue and narration, by replacing it with an image.
## The background of the window. In a Frame, the two numbers
## are the size of the left/right and top/bottom borders,
## respectively.
# style.window.background = Frame("frame.png", 12, 12)
## Margin is space surrounding the window, where the background
## is not drawn.
# style.window.left_margin = 6
# style.window.right_margin = 6
# style.window.top_margin = 6
# style.window.bottom_margin = 6
## Padding is space inside the window, where the background is
## drawn.
# style.window.left_padding = 6
# style.window.right_padding = 6
# style.window.top_padding = 6
# style.window.bottom_padding = 6
## This is the minimum height of the window, including the margins
## and padding.
# style.window.yminimum = 250
#########################################
## This lets you change the placement of the main menu.
## The way placement works is that we find an anchor point
## inside a displayable, and a position (pos) point on the
## screen. We then place the displayable so the two points are
## at the same place.
## An anchor/pos can be given as an integer or a floating point
## number. If an integer, the number is interpreted as a number
## of pixels from the upper-left corner. If a floating point,
## the number is interpreted as a fraction of the size of the
## displayable or screen.
# style.mm_menu_frame.xpos = 0.5
# style.mm_menu_frame.xanchor = 0.5
# style.mm_menu_frame.ypos = 0.75
# style.mm_menu_frame.yanchor = 0.5
#########################################
## These let you customize the default font used for text in Ren'Py.
## The file containing the default font.
# style.default.font = "DejaVuSans.ttf"
## The default size of text.
# style.default.size = 22
## Note that these only change the size of some of the text. Other
## buttons have their own styles.
#########################################
## These settings let you change some of the sounds that are used by
## Ren'Py.
## Set this to False if the game does not have any sound effects.
config.has_sound = True
## Set this to False if the game does not have any music.
config.has_music = True
## Set this to False if the game does not have voicing.
config.has_voice = True
## Sounds that are used when button and imagemaps are clicked.
# style.button.activate_sound = "click.wav"
# style.imagemap.activate_sound = "click.wav"
## Sounds that are used when entering and exiting the game menu.
# config.enter_sound = "click.wav"
# config.exit_sound = "click.wav"
## A sample sound that can be played to check the sound volume.
# config.sample_sound = "click.wav"
## Music that is played while the user is at the main menu.
# config.main_menu_music = "main_menu_theme.ogg"
#########################################
## Transitions.
## Used when entering the game menu from the game.
config.enter_transition = dissolve
## Used when exiting the game menu to the game.
config.exit_transition = dissolve
## Used between screens of the game menu.
config.intra_transition = dissolve
## Used when entering the game menu from the main menu.
config.main_game_transition = dissolve
## Used when returning to the main menu from the game.
config.game_main_transition = dissolve
## Used when entering the main menu from the splashscreen.
config.end_splash_transition = dissolve
## Used when entering the main menu after the game has ended.
config.end_game_transition = fade
## Used when a game is loaded.
config.after_load_transition = dissolve
#########################################
## Default values of Preferences.
## Note: These options are only evaluated the first time a
## game is run. To have them run a second time, delete
## game/saves/persistent
## Should we start in fullscreen mode?
config.default_fullscreen = False
## The default text speed in characters per second. 0 is infinite.
config.default_text_cps = 0
config.save_directory = "cardgame-11754"
-184
View File
@@ -1,184 +0,0 @@
# You can place the script of your game in this file.
init:
$ e = Character('Eileen', color="#c8ffc8")
image eileen happy = "eileen_happy.png"
image bg table = "table.jpg"
image dim = "#0008"
# Some styles for show text.
$ style.centered_text.drop_shadow = (2, 2)
$ style.centered_text.drop_shadow_color = "#000b"
label start:
scene bg table
python:
k = Klondike(1)
k.set_sensitive(False)
k.show()
show dim
show eileen happy
with dissolve
e "Welcome to the cardgame demo. Let's play some solitaire!"
e "I might show up from time to time to give you some advice, but it's up to you if you want to take it."
e "Good luck!"
label continue:
hide dim
hide eileen
with dissolve
label quick_continue:
$ hint_count = renpy.random.randint(10, 20)
while True:
python:
ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
k.set_sensitive(True)
event = k.interact()
if event:
renpy.checkpoint()
if event == "win":
jump win
if event == "tableau_drag" or event == "stock_click":
$ hint_count -= 1
if hint_count <= 0:
jump hint
label win:
show dim
show eileen happy
with dissolve
"Congratulations!"
jump newgame
label giveup:
$ k.set_sensitive(False)
show dim
show eileen happy
with dissolve
menu:
e "Are you sure you want to give up?"
"Yes":
"Oh well, better luck next time."
jump newgame
"No":
jump continue
label newgame:
menu:
e "Would you like to try again?"
"Yes":
pass
"No":
e "Well, I hope to see you again soon."
return
e "Okay, here we go!"
scene bg table
python:
k = Klondike(1)
k.sensitive = False
k.show()
jump continue
label hint:
$ under, over = k.hint()
$ print under, over
if under is None:
jump quick_continue
$ under = k.card_name(under)
$ over = k.card_name(over)
$ k.set_sensitive(False)
show dim
show eileen happy
with dissolve
$ hint = renpy.random.randint(0, 2)
if hint == 0:
e "Maybe put the %(over)s on top of the %(under)s."
elif hint == 1:
e "You can try moving the %(over)s to the %(under)s."
elif hint == 2:
e "I think something can go on the %(under)s."
jump continue
# This has nothing to do with card games.
label splashscreen:
scene bg table
$ renpy.pause(1.0)
show text "According to legend, prospectors in the klondike would carry with them a deck of cards."
with dissolve
with Pause(5.0)
hide text
with dissolve
with Pause(1.0)
show text "If they were ever lost, they'd start playing a game of solitaire."
with dissolve
with Pause(4.0)
hide text
with dissolve
with Pause(1.0)
show text "Without fail, help would soon arrive..."
with dissolve
with Pause(3.0)
hide text
with dissolve
with Pause(1.0)
show text "... saying \"put the Five of Spades on the Six of Hearts.\""
with dissolve
with Pause(4.0)
hide text
with dissolve
with Pause(1.0)
return
Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

+1
View File
@@ -150,6 +150,7 @@ def main():
# files.extend(tree("extras"))
more_files.extend(tree("lib"))
more_files.extend(tree("lib/linux-x86"))
module_files = [
"lib/pysdlsound/linmixer.py",
+112 -23
View File
@@ -13,15 +13,30 @@ init python:
# Returns true if a file or directory should not be included in
# the distribution
ignored_files = ("thumbs.db",
"launcherinfo.py",
"traceback.txt",
"errors.txt",
"icon.ico",
"icon.icns")
"icon.icns"
)
def ignored(fn):
root_ignored_files = (
"common",
"renpy",
"renpy.code",
"python23.dll",
"python24.dll",
"python25.dll",
"msvcr71.dll",
"lib",
"iliad-icon.png",
"manifest.xml"
)
def ignored(fn, dir, dest):
if fn[0] == ".":
return True
@@ -38,6 +53,13 @@ init python:
if fn == "archived":
return True
if 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,
@@ -55,7 +77,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 +90,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):
return False
return True
@@ -89,7 +111,7 @@ init python:
for fn in files:
if not include(fn):
if not include(fn, destdir, dest):
continue
sfn = srcdir + "/" + fn
@@ -103,7 +125,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 +162,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 +210,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')
@@ -253,20 +283,22 @@ label distribute:
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 +352,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"),
]
@@ -369,6 +401,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 +468,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
-1
View File
@@ -1 +0,0 @@
/home/tom/ab/py4renpy/current
-1
View File
@@ -2,7 +2,6 @@
# platforms as well. It probably won't work on Mac OS X, however.
build:: _renpy.c sound.c nativemidi.c winmixer.c
python setup.py build install_lib -d $(PYTHONPATH)
clean:
-rm *.so pysdlsound/*.so
+11 -1
View File
@@ -80,6 +80,11 @@ 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 *)
void PyErr_Clear()
import pygame
@@ -286,7 +291,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.")
@@ -396,6 +401,11 @@ 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)
# Be sure to update scale.py when adding something new here!
+43
View File
@@ -1555,3 +1555,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;
}
+4
View File
@@ -104,5 +104,9 @@ 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);
#endif
+6 -2
View File
@@ -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.0f"
version = "Ren'Py 6.8.1a"
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
+11 -4
View File
@@ -279,7 +279,8 @@ class SMAnimation(renpy.display.core.Displayable):
im = renpy.display.render.render(self.edge_cache, width, height, t - self.edge_start, at)
renpy.display.render.redraw(self.edge_cache, self.edge.delay - (t - self.edge_start))
if not renpy.game.less_updates:
renpy.display.render.redraw(self.edge_cache, self.edge.delay - (t - self.edge_start))
iw, ih = im.get_size()
@@ -450,7 +451,8 @@ class TransitionAnimation(renpy.display.core.Displayable):
for image, prev, delay, trans in zip(self.images, self.prev_images, self.delays, self.transitions):
if t < delay:
renpy.display.render.redraw(self, delay - t)
if not renpy.game.less_updates:
renpy.display.render.redraw(self, delay - t)
if trans and orig_t >= self.delays[0]:
image = trans(old_widget=prev, new_widget=image)
@@ -562,12 +564,15 @@ class Blink(renpy.display.core.Displayable):
w, h = rend.get_size()
rv = renpy.display.render.Render(w, h)
if renpy.game.less_updates:
alpha = 1.0
if alpha:
oldsurf = rend.pygame_surface()
if not (oldsurf.get_masks()[3]):
oldsurf = oldsurf.convert_alpha()
oldsurf = oldsurf.convert_alpha(renpy.game.interface.display.window)
newsurf = pygame.Surface(oldsurf.get_size(), oldsurf.get_flags(), oldsurf)
@@ -582,7 +587,9 @@ class Blink(renpy.display.core.Displayable):
rv.blit(newsurf, (0, 0))
rv.depends_on(rend)
renpy.display.render.redraw(self, delay)
if not renpy.game.less_updates:
renpy.display.render.redraw(self, delay)
return rv
+7 -4
View File
@@ -671,8 +671,11 @@ class Display(object):
except:
pass
renpy.display.scale.init()
pygame.display.init()
pygame.font.init()
renpy.audio.audio.init()
renpy.display.joystick.init()
@@ -746,8 +749,8 @@ class Display(object):
self.set_window_caption()
# Sample surface that all surfaces are created based on.
sample = pygame.Surface((10, 10))
self.sample_surface = sample.convert_alpha()
sample = pygame.Surface((10, 10), 0, self.window)
self.sample_surface = sample.convert_alpha(self.window)
pygame.event.set_grab(False)
@@ -882,7 +885,7 @@ class Display(object):
if self.mouse_event_time + renpy.config.mouse_hide_time < get_time():
visible = False
else:
visible = renpy.store.mouse_visible
visible = renpy.store.mouse_visible and (not renpy.game.less_mouse)
# Deal with a hardware mouse, the easy way.
if not self.mouse:
@@ -1363,7 +1366,7 @@ class Interface(object):
"""
suppress_overlay = suppress_overlay or renpy.store.suppress_overlay
suppress_transition = renpy.config.skipping
suppress_transition = renpy.config.skipping or renpy.game.less_updates
# The global one.
self.suppress_transition = False
+166
View File
@@ -0,0 +1,166 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# 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.
# This file contains code that helps Ren'Py run on an iRex iLiad.
import os
import renpy
address = os.environ.get("RENPY_ILIAD", None)
if address is not None:
import socket
import pygame
import _renpy
dm_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
dm_socket.connect((address, 50555))
busy_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
busy_socket.connect((address, 50071))
pagebar_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
pagebar_socket.connect((address, 50073))
pygame_Surface = pygame.Surface
pygame_display_set_mode = pygame.display.set_mode
pygame_display_update = pygame.display.update
pygame_display_get_surface = pygame.display.get_surface
pygame_event_wait = pygame.event.wait
window = None
surface = None
# Used for gamma correction, if it proves necessary.
ramp = "".join(chr(i) for i in xrange(256))
def set_mode(size, flags=0, depth=32):
global window
global surface
window = pygame_display_set_mode(size, 0, 8)
surface = pygame_Surface(size, 0, 32)
# ccPbReset
pagebar_socket.send("17,200")
return surface
pygame.display.set_mode = set_mode
def get_surface():
return surface
pygame.display.get_surface = get_surface
def update(rectangle=None):
_renpy.staticgray(surface, window, 44, 127, 84, 0, 8, ramp)
pygame_display_update()
dm_socket.send("!0,3,0")
pygame.display.update = update
def wait():
busy_socket.send("0,0")
return pygame_event_wait()
pygame.event.wait = wait
os.environ["SDL_VIDEO_X11_WMCLASS"] = "sh"
def post_init():
# Pagebar Right - short 281 (K_PAGEDOWN), long 282 (K_F1)
# Pagebar Left - short 280 (K_PAGEUP), long 283 (K_F2)
# Arrow Up - short 273 (K_UP), long 285 (K_F4)
# Arrow Down - short 274 (K_DOWN), long 284 (K_F3)
# Circle - short 13 (K_RETURN), long 287 (K_F6)
# Updir - short 286 (K_F5), long 278 (K_HOME)
renpy.config.keymap = dict(
rollback = [ 'K_PAGEUP' ],
screenshot = [ ],
toggle_fullscreen = [ ],
toggle_music = [ ],
game_menu = [ 'K_HOME', 'K_F6' ],
hide_windows = [ ],
launch_editor = [ ],
dump_styles = [ ],
reload_game = [ ],
inspector = [ ],
developer = [ ],
quit = [ 'K_F5' ],
iconify = [ ],
help = [ ],
# Say.
rollforward = [ ],
dismiss = [ 'mousedown_1', 'K_RETURN', 'K_PAGEDOWN' ],
# Pause.
dismiss_hard_pause = [ ],
# Focus.
focus_left = [ ],
focus_right = [ ],
focus_up = [ 'K_UP', 'joy_up' ],
focus_down = [ 'K_DOWN', 'joy_down' ],
# Button.
button_select = [ 'mouseup_1', 'K_RETURN' ],
# Input.
input_backspace = [ ],
input_enter = [ 'K_RETURN' ],
# Viewport.
viewport_up = [ ],
viewport_down = [ ],
viewport_drag_start = [ 'mousedown_1' ],
viewport_drag_end = [ 'mouseup_1' ],
# These keys control skipping.
skip = [ ],
toggle_skip = [ ],
fast_skip = [ ],
# These control the bar.
bar_activate = [ 'mousedown_1' ],
bar_deactivate = [ 'mouseup_1' ],
bar_decrease = [ ],
bar_increase = [ ],
)
try:
renpy.config.save_directory = None
renpy.config.help = None
except:
pass
try:
renpy.config.has_sound = False
renpy.config.has_voice = False
renpy.config.has_music = False
except:
pass
renpy.game.post_init.append(post_init)
+9 -9
View File
@@ -161,7 +161,7 @@ class Cache(object):
if not image.cache:
surf = image.load()
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
renpy.display.render.mutated_surface(surf)
return surf
@@ -187,7 +187,7 @@ class Cache(object):
surf = image.load()
has_alpha = surf.get_masks()[3]
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
ce = CacheEntry(image, surf)
self.total_cache_size += ce.size
@@ -207,7 +207,7 @@ class Cache(object):
# If we don't know if the image is RLE or not, guess.
# Only do so if the image has an alpha channel.
if rle is None and has_alpha:
if rle is None and has_alpha and not renpy.game.less_memory:
sw, sh = surf.get_size()
for i in range(0, 10):
@@ -219,7 +219,7 @@ class Cache(object):
if rle:
# We must copy the surface, so we have a RLE-specific version.
rle_surf = ce.surf.convert_alpha()
rle_surf = ce.surf.convert_alpha(renpy.game.interface.display.window)
rle_surf.set_alpha(255, RLEACCEL)
rle_cache[id(ce.surf)] = rle_surf
@@ -938,7 +938,7 @@ class Map(ImageBase):
return surf
if self.force_alpha and not (surf.get_masks()[3]):
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
rv = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
@@ -983,7 +983,7 @@ class Twocolor(ImageBase):
return surf
if self.force_alpha and not (surf.get_masks()[3]):
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
rv = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
@@ -1026,7 +1026,7 @@ class Recolor(ImageBase):
return surf
if self.force_alpha and not (surf.get_masks()[3]):
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
rv = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
@@ -1065,7 +1065,7 @@ class MatrixColor(ImageBase):
return surf
if not (surf.get_masks()[3]):
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
rv = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
@@ -1327,7 +1327,7 @@ class AlphaMask(ImageBase):
raise Exception("AlphaMask surfaces must be the same size.")
# Used to copy the surface.
rv = basesurf.convert_alpha()
rv = basesurf.convert_alpha(renpy.game.interface.display.window)
if renpy.display.module.can_munge:
renpy.display.module.alpha_munge(masksurf, rv, identity)
+1 -1
View File
@@ -49,7 +49,7 @@ class UncachedImage(renpy.display.core.Displayable):
super(UncachedImage, self).__init__(style=style, **properties)
self.surf = pygame.image.load(file, hint)
self.surf = self.surf.convert_alpha()
self.surf = self.surf.convert_alpha(renpy.game.interface.display.window)
if scale:
renpy.display.render.blit_lock.acquire()
+93 -9
View File
@@ -839,7 +839,15 @@ class Motion(Container):
else:
t = st
if self.delay and t >= self.delay:
if renpy.game.less_updates:
if self.delay:
t = self.delay
if self.repeat:
t = t % self.period
else:
t = self.period
elif self.delay and t >= self.delay:
t = self.delay
if self.repeat:
t = t % self.period
@@ -1182,6 +1190,9 @@ class Zoom(renpy.display.core.Displayable):
if self.repeat:
done = done % 1.0
if renpy.game.less_updates:
done = 1.0
self.done = done
@@ -1205,7 +1216,7 @@ class Zoom(renpy.display.core.Displayable):
rv = zoom_core(rend, surf, rect, self.size[0], self.size[1], self.bilinear, self.opaque)
if done < 1.0:
if self.done < 1.0:
renpy.display.render.redraw(self, 0)
return rv
@@ -1321,6 +1332,9 @@ class FactorZoom(renpy.display.core.Displayable):
if self.repeat:
done = done % 1.0
if renpy.game.less_updates:
done = 1.0
self.done = done
if self.after_child and done == 1.0:
@@ -1341,10 +1355,8 @@ class FactorZoom(renpy.display.core.Displayable):
rv = zoom_core(rend, surf, (0, 0, oldw, oldh), neww, newh, self.bilinear, self.opaque)
if done < 1.0:
if self.done < 1.0:
renpy.display.render.redraw(self, 0)
self.done = done
return rv
@@ -1405,6 +1417,9 @@ class SizeZoom(renpy.display.core.Displayable):
if self.repeat:
done = done % 1.0
if renpy.game.less_updates:
done = 1.0
self.done = done
if self.after_child and done == 1.0:
@@ -1426,11 +1441,9 @@ class SizeZoom(renpy.display.core.Displayable):
rv = zoom_core(rend, surf, (0, 0, oldw, oldh), neww, newh, self.bilinear, self.opaque)
if done < 1.0:
if self.done < 1.0:
renpy.display.render.redraw(self, 0)
self.done = done
return rv
def event(self, ev, x, y, st):
@@ -1678,12 +1691,16 @@ class RotoZoom(renpy.display.core.Displayable):
zoom_time *= 2
zoom_time = min(zoom_time, 2.0 - zoom_time)
if renpy.game.less_updates:
rot_time = 1.0
zoom_time = 1.0
if rot_time <= 1.0 or zoom_time <= 1.0:
renpy.display.render.redraw(self, 0)
rot_time = min(rot_time, 1.0)
zoom_time = min(zoom_time, 1.0)
if self.rot_time_warp:
rot_time = self.rot_time_warp(rot_time)
@@ -2052,6 +2069,73 @@ class Side(Container):
return rv
class Alpha(renpy.display.core.Displayable):
def __init__(self, start, end, time, child=None, repeat=False, bounce=False,
anim_timebase=False, time_warp=None, **properties):
super(Alpha, self).__init__(**properties)
self.start = start
self.end = end
self.time = time
self.child = renpy.easy.displayable(child)
self.repeat = repeat
self.anim_timebase = anim_timebase
self.time_warp = time_warp
def visit(self):
return [ self.child ]
def render(self, height, width, st, at):
if self.anim_timebase:
t = at
else:
t = st
if self.time:
done = min(t / self.time, 1.0)
else:
done = 1.0
if renpy.game.less_updates:
done = 1.0
elif self.repeat:
done = done % 1.0
renpy.display.render.redraw(self, 0)
elif done != 1.0:
renpy.display.render.redraw(self, 0)
if self.time_warp:
done = self.time_warp(done)
alpha = self.start + done * (self.end - self.start)
rend = renpy.display.render.render(self.child, height, width, st, at)
if not renpy.display.module.can_linmap:
return rend
w, h = rend.get_size()
rv = renpy.display.render.Render(w, h)
oldsurf = rend.pygame_surface()
if not (oldsurf.get_masks()[3]):
oldsurf = oldsurf.convert_alpha(renpy.game.interface.display.window)
newsurf = pygame.Surface(oldsurf.get_size(), oldsurf.get_flags(), oldsurf)
renpy.display.module.linmap(oldsurf, newsurf,
256, 256, 256, int(alpha * 256.0))
renpy.display.render.mutated_surface(newsurf)
rv.blit(newsurf, (0, 0))
rv.depends_on(rend)
return rv
+3 -6
View File
@@ -115,11 +115,8 @@ if version >= 4008002:
dx, dy = size
if s.get_flags() & SRCALPHA:
d = pygame.Surface((dx, dy), SRCALPHA)
else:
d = pygame.Surface((dx, dy), 0)
d = pygame.Surface(size, s.get_flags(), s)
if can_bilinear_scale:
bilinear_scale(s, d)
else:
@@ -353,7 +350,7 @@ if version >= 5006000:
nsw = max(sw / 2, dw)
nsh = max(sh / 2, dh)
nsrc = pygame.Surface((nsw, nsh), src.get_flags())
nsrc = pygame.Surface((nsw, nsh), src.get_flags(), src)
_renpy.bilinear(src, nsrc, sx, sy, sw, sh)
sx = 0
sy = 0
+6 -1
View File
@@ -49,6 +49,11 @@ class Particles(renpy.display.core.Displayable):
def render(self, w, h, st, at):
rv = renpy.display.render.Render(w, h)
if renpy.game.less_updates:
return rv
if st < self.old_st:
self.particles = [ ]
@@ -58,12 +63,12 @@ class Particles(renpy.display.core.Displayable):
if particles is None:
particles = [ ]
newparts = self.factory.create(self.particles, at)
if newparts is not None:
particles.extend(newparts)
rv = renpy.display.render.Render(w, h)
liveparts = [ ]
+16 -7
View File
@@ -31,8 +31,12 @@ proc = None
# user. If it decides to show something to the user, uses subprocess
# to actually handle the showing.
def start(gamedir):
import os
import os.path
if "RENPY_LESS_UPDATES" in os.environ:
return
global proc
filenames = [ "/presplash.png", "/presplash.jpg" ]
@@ -43,14 +47,19 @@ def start(gamedir):
else:
return
import subprocess
import sys
if sys.argv[0].lower().endswith(".exe"):
proc = subprocess.Popen([sys.argv[0], "--presplash", fn], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
else:
proc = subprocess.Popen([sys.executable, sys.argv[0], "--presplash", fn], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
try:
import subprocess
import sys
if sys.argv[0].lower().endswith(".exe"):
proc = subprocess.Popen([sys.argv[0], "--presplash", fn], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
else:
proc = subprocess.Popen([sys.executable, sys.argv[0], "--presplash", fn], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
except:
pass
# Called just before we initialize the display for real, to
# hide the splash, and terminate window centering.
def end():
+1 -1
View File
@@ -1056,7 +1056,7 @@ def is_fullscreen(surf, x, y, wh):
# Check that this surface is on the screen.
if (x > 0) or (y > 0) or (sw + x < w) or (sh + y < h):
return False
if surf.__class__ is pygame.Surface:
if (surf.get_masks()[3] == 0 and
+28 -4
View File
@@ -39,13 +39,18 @@ except ImportError:
factor = 1.0
if 'RENPY_SCALE_FACTOR' in os.environ:
factor = float(os.environ['RENPY_SCALE_FACTOR'])
if ('RENPY_SCALE_FACTOR' in os.environ) or ('RENPY_SCALE_WIDTH' in os.environ):
enable_scaling = True
else:
enable_scaling = False
if factor == 1.0:
if not enable_scaling:
# The public api other modules use.
def init():
return
# Gets the real pygame surface.
def real(s):
return s
@@ -79,7 +84,22 @@ if factor == 1.0:
else:
print "Using scale factor of %f." % factor
def init():
global factor
if 'RENPY_SCALE_FACTOR' in os.environ:
factor = float(os.environ['RENPY_SCALE_FACTOR'])
elif 'RENPY_SCALE_WIDTH' in os.environ:
width = float(os.environ['RENPY_SCALE_WIDTH'])
if width < renpy.config.screen_width:
factor = float(os.environ['RENPY_SCALE_WIDTH']) / renpy.config.screen_width
else:
factor = 1.0
else:
factor = 1.0
print "Using scale factor of %f." % factor
def real(s):
return s.surface
@@ -170,9 +190,13 @@ else:
self.surface.blit(s.surface, v2p(destpos), v2p(sourcerect))
def convert(self, *args):
if args:
args = (args[0].surface,)
return Surface(self.surface.convert(*args), wh=self.get_size())
def convert_alpha(self, *args):
if args:
args = (args[0].surface,)
return Surface(self.surface.convert_alpha(*args), wh=self.get_size())
def copy(self):
+11 -2
View File
@@ -157,7 +157,7 @@ class TextStyle(object):
if a != 255 and renpy.display.module.can_linmap:
if not surf.get_masks()[3]:
surf = surf.convert_alpha()
surf = surf.convert_alpha(renpy.game.interface.display.window)
rv = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
@@ -387,6 +387,8 @@ def greedy_text_layout(triples, width, style):
lines_last = [ ]
target = width - style.first_indent
after_newline = True
for triple in triples:
@@ -398,15 +400,20 @@ def greedy_text_layout(triples, width, style):
line = [ ]
target = width - style.rest_indent
after_newline = True
continue
if type == "space":
if not line and lines:
if not line and not after_newline:
continue
line.append(triple)
continue
else:
after_newline = False
if layout_width(line + [ triple ]) > target:
lines.append(line)
lines_last.append(False)
@@ -1309,6 +1316,8 @@ class Text(renpy.display.core.Displayable):
if speed:
speed *= self.style.slow_cps_multiplier
if renpy.game.less_updates:
speed = None
dslist = self.style.drop_shadow
outlines = self.style.outlines
+30 -14
View File
@@ -62,6 +62,19 @@ class Transition(renpy.display.core.Displayable):
def visit(self):
return [ self.new_widget, self.old_widget ]
def null_render(d, width, height, st, at):
d.events = True
surf = renpy.display.render.render(d.new_widget,
width,
height,
st, at)
rv = renpy.display.render.Render(surf.width, surf.height)
rv.blit(surf, (0, 0))
return rv
class NoTransition(Transition):
"""
This is a transition that doesn't do anything, and simply displays
@@ -78,19 +91,7 @@ class NoTransition(Transition):
self.events = True
def render(self, width, height, st, at):
surf = renpy.display.render.render(self.new_widget,
width,
height,
st, at)
width = min(surf.width, width)
height = min(surf.height, height)
rv = renpy.display.render.Render(width, height)
rv.blit(surf, (0, 0))
return rv
return null_render(self, width, height, st, at)
class MultipleTransition(Transition):
@@ -147,7 +148,10 @@ class MultipleTransition(Transition):
return [ i for i in self.screens if isinstance(i, renpy.display.core.Displayable)] + self.transitions
def render(self, width, height, st, at):
if renpy.game.less_updates:
return null_render(self, width, height, st, at)
while True:
trans = self.transitions[0]
stoff = st - self.time_offset
@@ -263,6 +267,9 @@ class Pixellate(Transition):
def render(self, width, height, st, at):
if renpy.game.less_updates:
return null_render(self, width, height, st, at)
if st >= self.time:
self.events = True
return render(self.new_widget, width, height, st, at)
@@ -328,6 +335,9 @@ class Dissolve(Transition):
def render(self, width, height, st, at):
if renpy.game.less_updates:
return null_render(self, width, height, st, at)
if st >= self.time or not renpy.display.module.can_blend:
self.events = True
@@ -581,6 +591,9 @@ class CropMove(Transition):
def render(self, width, height, st, at):
if renpy.game.less_updates:
return null_render(self, width, height, st, at)
time = 1.0 * st / self.time
# Done rendering.
@@ -1030,6 +1043,9 @@ class ImageDissolve(Transition):
def render(self, width, height, st, at):
if renpy.game.less_updates:
return null_render(self, width, height, st, at)
if st >= self.time or not renpy.display.module.can_imageblend:
self.events = True
return render(self.new_widget, width, height, st, at)
+15 -1
View File
@@ -76,6 +76,9 @@ def movie_start_fullscreen(filename, loops=0):
@param loops: The number of additional times the movie should be looped. -1 to loop it forever.
"""
if renpy.game.less_updates:
return
movie_stop()
renpy.game.context().scene_lists.movie = MovieInfo(filename, loops, True)
@@ -91,10 +94,16 @@ def movie_start_displayable(filename, size, loops=0):
@param loops: The number of additional times the movie should be looped. -1 to loop it forever.
"""
if renpy.game.less_updates:
return
movie_stop()
renpy.game.context().scene_lists.movie = MovieInfo(filename, loops, False, size)
def movie_length(filename):
if renpy.game.less_updates:
return 0
m = pygame.movie.Movie(renpy.loader.load(filename))
return m.get_length()
@@ -106,6 +115,9 @@ def interact():
otherwise.
"""
if renpy.game.less_updates:
return False
try:
global movie
@@ -192,7 +204,9 @@ class Movie(renpy.display.layout.Null):
super(Movie, self).__init__(style=style, **properties)
def render(self, width, height, st, at):
renpy.display.render.redraw(self, self.frame_time - st % self.frame_time)
if not renpy.game.less_updates:
renpy.display.render.redraw(self, self.frame_time - st % self.frame_time)
if surface:
renpy.display.render.mutated_surface(surface)
+13
View File
@@ -79,6 +79,19 @@ seen_ever = { }
# True if we're in the first interaction after a rollback.
after_rollback = False
# Code that's run after the init code.
post_init = [ ]
# Should we attempt to run in a mode that uses less memory?
less_memory = False
# Should we attempt to run in a mode that minimizes the number
# of screen updates?
less_updates = False
# Should we never show the mouse?
less_mouse = False
# The class that's used to hold the persistent data.
class Persistent(object):
+53 -47
View File
@@ -38,10 +38,13 @@ import time
# Hide maybe valid.
# Expressions can compile.
# The node the report will be about:
report_node = None
# Reports a message to the user.
def report(node, msg, *args):
if node:
out = u"%s:%d " % (renpy.parser.unicode_filename(node.filename), node.linenumber)
def report(msg, *args):
if report_node:
out = u"%s:%d " % (renpy.parser.unicode_filename(report_node.filename), report_node.linenumber)
else:
out = ""
@@ -60,28 +63,28 @@ def add(msg):
# Trys to evaluate an expression, announcing an error if it fails.
def try_eval(node, where, expr, additional=None):
def try_eval(where, expr, additional=None):
try:
renpy.python.py_eval(expr)
except:
report(node, "Could not evaluate '%s', in %s.", expr, where)
report( "Could not evaluate '%s', in %s.", expr, where)
if additional:
add(additional)
# Returns True of the expression can be compiled as python, False
# otherwise.
def try_compile(node, where, expr):
def try_compile(where, expr):
try:
renpy.python.py_compile_eval_bytecode(expr)
except:
report(node, "'%s' could not be compiled as a python expression, %s.", expr, where)
report("'%s' could not be compiled as a python expression, %s.", expr, where)
# This reports an error if we're sure that the image with the given name
# does not exist.
def image_exists(node, name, expression, tag):
def image_exists(name, expression, tag):
# Add the tag to the set of known tags.
tag = tag or name[0]
@@ -99,19 +102,19 @@ def image_exists(node, name, expression, tag):
name.pop()
report(node, "The image named '%s' was not declared.", names)
report("The image named '%s' was not declared.", names)
# Only check each file once.
check_file_cache = { }
def check_file(node, what, fn):
def check_file(what, fn):
if fn in check_file_cache:
return True
check_file_cache[fn] = True
if not renpy.loader.loadable(fn):
report(node, "%s uses file '%s', which is not loadable.", what.capitalize(), fn)
report("%s uses file '%s', which is not loadable.", what.capitalize(), fn)
return
try:
@@ -122,11 +125,11 @@ def check_file(node, what, fn):
if renpy.loader.transfn(fn) and \
fn.lower() in filenames and \
fn != filenames[fn.lower()]:
report(node, "Filename case mismatch for %s. '%s' was used in the script, but '%s' was found on disk.", what, fn, filenames[fn.lower()])
report("Filename case mismatch for %s. '%s' was used in the script, but '%s' was found on disk.", what, fn, filenames[fn.lower()])
add("Case mismatches can lead to problems on Mac, Linux/Unix, and when archiving images. To fix them, either rename the file on disk, or the filename use in the script.")
def check_displayable(node, what, d):
def check_displayable(what, d):
files = [ ]
@@ -136,7 +139,7 @@ def check_displayable(node, what, d):
d.predict(files_callback)
for fn in files:
check_file(node, what, fn)
check_file(what, fn)
# Lints ast.Image nodes.
@@ -144,7 +147,7 @@ def check_image(node):
name = " ".join(node.imgname)
check_displayable(node, 'image %s' % name, renpy.exports.images[node.imgname])
check_displayable('image %s' % name, renpy.exports.images[node.imgname])
def imspec(t):
if len(t) == 3:
@@ -165,12 +168,12 @@ def check_show(node):
name, expression, tag, at_list, layer, zorder, behind = imspec(node.imspec)
if layer not in renpy.config.layers and layer not in renpy.config.top_layers:
report(node, "Uses layer '%s', which is not in config.layers.", layer)
report("Uses layer '%s', which is not in config.layers.", layer)
image_exists(node, name, expression, tag)
image_exists(name, expression, tag)
for i in at_list:
try_eval(node, "the at list of a scene or show statment", i, "Perhaps you forgot to declare, or misspelled, a position?")
try_eval("the at list of a scene or show statment", i, "Perhaps you forgot to declare, or misspelled, a position?")
# Lints ast.Hide.
@@ -182,21 +185,21 @@ def check_hide(node):
tag = tag or name[0]
if layer not in renpy.config.layers and layer not in renpy.config.top_layers:
report(node, "Uses layer '%s', which is not in config.layers.", layer)
report("Uses layer '%s', which is not in config.layers.", layer)
if tag not in image_prefixes:
report(node, "The image tag '%s' is not the prefix of a declared image, nor was it used in a show statement before this hide statement.", tag)
report("The image tag '%s' is not the prefix of a declared image, nor was it used in a show statement before this hide statement.", tag)
# for i in at_list:
# try_eval(node, "at list of hide statment", i)
def check_with(node):
try_eval(node, "a with statement or clause", node.expr, "Perhaps you forgot to declare, or misspelled, a transition?")
try_eval("a with statement or clause", node.expr, "Perhaps you forgot to declare, or misspelled, a transition?")
def check_user(node):
def error(msg):
report(node, "%s", msg)
report("%s", msg)
renpy.exports.push_error_handler(error)
try:
@@ -207,12 +210,14 @@ def check_user(node):
try:
node.get_next()
except:
report(node, "Didn't properly report what the next statement should be.")
report("Didn't properly report what the next statement should be.")
check_text_tags = renpy.display.text.check_text_tags
def text_checks(node, s):
def text_checks(s):
msg = renpy.display.text.check_text_tags(s)
if msg:
report(node, "%s (in %s)", msg, repr(s)[1:])
report("%s (in %s)", msg, repr(s)[1:])
if "%" in s:
@@ -239,7 +244,7 @@ def text_checks(node, s):
elif c in "diouxXeEfFgGcrs%":
state = 0
else:
report(node, "Unknown string format code '%s' (in %s)", fmt, repr(s)[1:])
report("Unknown string format code '%s' (in %s)", fmt, repr(s)[1:])
state = 0
# In a mapping key.
@@ -249,35 +254,31 @@ def text_checks(node, s):
state = 1
if state != 0:
report(node, "Unterminated string format code '%s' (in %s)", fmt, repr(s)[1:])
report("Unterminated string format code '%s' (in %s)", fmt, repr(s)[1:])
def check_say(node):
if node.who:
try_eval(node, "the who part of a say statement", node.who, "Perhaps you forgot to declare a character?")
try_eval("the who part of a say statement", node.who, "Perhaps you forgot to declare a character?")
if node.with_:
try_eval(node, "the with clause of a say statement", node.with_, "Perhaps you forgot to declare, or misspelled, a transition?")
try_eval("the with clause of a say statement", node.with_, "Perhaps you forgot to declare, or misspelled, a transition?")
text_checks(node, node.what)
text_checks(node.what)
def check_menu(node):
if node.with_:
try_eval(node, "the with clause of a menu statement", node.with_, "Perhaps you forgot to declare, or misspelled, a transition?")
try_eval("the with clause of a menu statement", node.with_, "Perhaps you forgot to declare, or misspelled, a transition?")
if not [ (l, c, b) for l, c, b in node.items if b ]:
report(node, "The menu does not contain any selectable choices.")
report("The menu does not contain any selectable choices.")
for l, c, b in node.items:
if c:
try_compile(node, "in the if clause of a menuitem", c)
try_compile("in the if clause of a menuitem", c)
text_checks(node, l)
text_checks(l)
def check_jump(node):
@@ -285,7 +286,7 @@ def check_jump(node):
return
if not renpy.game.script.has_label(node.target):
report(node, "The jump is to nonexistent label '%s'.", node.target)
report("The jump is to nonexistent label '%s'.", node.target)
def check_call(node):
@@ -298,15 +299,15 @@ def check_call(node):
return
if not renpy.game.script.has_label(node.label):
report(node, "The call is to nonexistent label '%s'.", node.label)
report("The call is to nonexistent label '%s'.", node.label)
def check_while(node):
try_compile(node, "in the condition of the while statement", node.condition)
try_compile("in the condition of the while statement", node.condition)
def check_if(node):
for condition, block in node.entries:
try_compile(node, "in a condition of the if statement", condition)
try_compile("in a condition of the if statement", condition)
def check_style(name, s):
@@ -321,7 +322,7 @@ def check_style(name, s):
# Treat font specially.
if k.endswith("font"):
check_file(None, name, v)
check_file(name, v)
e = renpy.style.expansions[k]
@@ -332,7 +333,7 @@ def check_style(name, s):
break
if isinstance(v, renpy.display.core.Displayable):
check_displayable(None, kname, v)
check_displayable(kname, v)
def check_styles():
@@ -344,13 +345,12 @@ def lint():
The master lint function, that's responsible for staging all of the
other checks.
"""
renpy.game.lint = True
print codecs.BOM_UTF8
print unicode(renpy.version + " lint report, generated at: " + time.ctime()).encode("utf-8")
# This is used to support the check_image.
global filenames
filenames = { }
@@ -375,9 +375,13 @@ def lint():
say_words = 0
say_count = 0
menu_count = 0
global report_node
for fn, ln, node in all_stmts:
report_node = node
if isinstance(node, renpy.ast.Image):
check_image(node)
@@ -417,6 +421,8 @@ def lint():
elif isinstance(node, renpy.ast.UserStatement):
check_user(node)
report_node = None
check_styles()
for f in renpy.config.lint_hooks:
+9
View File
@@ -258,6 +258,10 @@ def main():
# Save the bytecode in a cache.
renpy.game.script.save_bytecode()
# Run the post init code, if any.
for i in renpy.game.post_init:
i()
# Rebuild the various style caches.
renpy.style.build_styles()
@@ -271,6 +275,11 @@ def main():
# Make a clean copy of the store.
game.clean_store = renpy.store.__dict__.copy()
# Check some environment variables.
renpy.game.less_memory = "RENPY_LESS_MEMORY" in os.environ
renpy.game.less_mouse = "RENPY_LESS_MOUSE" in os.environ
renpy.game.less_updates = "RENPY_LESS_UPDATES" in os.environ
if renpy.game.options.compile:
return
+35 -7
View File
@@ -363,7 +363,8 @@ class Lexer(object):
self.filename, self.number, self.text, self.subblock = self.block[self.line]
self.pos = 0
self.word_cache_pos = -1
return True
def match_regexp(self, regexp):
@@ -409,14 +410,19 @@ class Lexer(object):
return self.match_regexp(regexp)
def keyword(self, regexp):
def keyword(self, word):
"""
Matches a keyword at the current position. A keyword is a word
that is surrounded by things that aren't words, like
whitespace. (This prevents a keyword from matching a prefix.)
"""
return self.match(regexp + r'\b')
oldpos = self.pos
if self.word() == word:
return word
self.pos = oldpos
return ''
def error(self, msg):
@@ -546,8 +552,17 @@ class Lexer(object):
"""
Parses a name, which may be a keyword or not.
"""
if self.pos == self.word_cache_pos:
self.pos = self.word_cache_newpos
return self.word_cache
self.word_cache_pos = self.pos
rv = self.match(ur'[a-zA-Z_\u00a0-\ufffd][0-9a-zA-Z_\u00a0-\ufffd]*')
self.word_cache = rv
self.word_cache_newpos = self.pos
return self.match(ur'[a-zA-Z_\u00a0-\ufffd][0-9a-zA-Z_\u00a0-\ufffd]*')
return rv
def name(self):
@@ -556,8 +571,6 @@ class Lexer(object):
"""
oldpos = self.pos
# rv = self.match(ur'[a-zA-Z_\u00a0-\ufffd][0-9a-zA-Z_\u00a0-\ufffd]*')
rv = self.word()
if rv in self.keywords:
@@ -773,7 +786,8 @@ class Lexer(object):
"""
self.filename, self.number, self.text, self.subblock, self.pos = state
self.word_cache_pos = -1
def get_location(self):
"""
Returns a (filename, line number) tuple representing the current
@@ -1559,6 +1573,20 @@ def parse_statement(l):
l.revert(state)
# Try parsing as the default statement.
if () in renpy.statements.registry:
text = l.text
l.expect_noblock('default statement')
l.advance()
renpy.exports.push_error_handler(l.error)
try:
rv = ast.UserStatement(loc, text)
finally:
renpy.exports.pop_error_handler()
return rv
# The one and two arguement say statements are ambiguous in terms
# of lookahead. So we first try parsing as a one-argument, then a
# two-argument.
+5 -1
View File
@@ -28,7 +28,11 @@ import renpy
registry = { }
def register(name, parse=None, lint=None, execute=None, predict=None, next=None, scry=None):
name = tuple(name.split())
if name == "":
name = ()
else:
name = tuple(name.split())
if registry.get(name) is not None:
renpy.exports.error("The statement '%s' has already been registered." % (" ".join(name)))
+1
View File
@@ -128,6 +128,7 @@ Text = renpy.display.text.Text
ParameterizedText = renpy.display.text.ParameterizedText
# Currying things.
Alpha = renpy.curry.curry(renpy.display.layout.Alpha)
Position = renpy.curry.curry(renpy.display.layout.Position)
Pan = renpy.curry.curry(renpy.display.layout.Pan)
Move = renpy.curry.curry(renpy.display.layout.Move)