Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fc7453450 | |||
| 1799971885 | |||
| b999911292 | |||
| 29e0f9ad21 | |||
| d821b7eb8b | |||
| 272a214304 | |||
| 7f15b351ee | |||
| 5a6a12a14a | |||
| 01493c7063 | |||
| 244055fcb7 | |||
| 0415af5f31 | |||
| f73372c924 | |||
| 65cdc24e37 |
@@ -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
|
||||
-------------------
|
||||
|
||||
|
||||
|
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 |
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = [ ]
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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)
|
||||
|
||||