Compare commits

...

12 Commits

Author SHA1 Message Date
Tom Rothamel 5196a970a0 Channels now have a default tightness. 2009-04-15 12:12:40 -04:00
Tom Rothamel efcbc92e7a Reimplement smoothscale in terms of _renpy.pixellate and _renpy.bilinear. 2009-04-15 01:10:13 -04:00
Tom Rothamel 142fa33548 Changelog updates. 2009-04-13 23:49:39 -04:00
Tom Rothamel 4b6e871ac6 6.9.1d 2009-04-13 23:40:13 -04:00
Tom Rothamel 1fbbad053a Add _rollback. 2009-04-13 23:11:39 -04:00
Tom Rothamel 61aa933d97 Fix rendering of empty image-based fonts. 2009-04-13 19:31:11 -04:00
Tom Rothamel 70c3ea773e Fix conflict between window show and shift+>. 2009-04-13 11:54:40 -04:00
Tom Rothamel a16de04682 The demo now passes with RENPY_SCALE_FACTOR=1.5. This required various fixes.
Prevent blit_lock from being held over a traceback.
2009-04-13 01:27:34 -04:00
Tom Rothamel 0280a12589 In SayBehavior, when a click comes in at the same time as a skip
timeout, favor the click.
2009-04-12 23:53:22 -04:00
Tom Rothamel 4dc8fef9c1 Fix a problems in scaling caused when images of different physical
sizes map to the same virtual size.

Fix a problem with restart.
2009-04-12 23:47:42 -04:00
Tom Rothamel 2c02645ec7 Lint now reports all uses of missing files, rather than just the first. 2009-04-12 15:14:19 -04:00
Tom Rothamel 40bad327fe renpy.full_restart now takes a target parameter, which is a screen on
the main menu to target.
2009-04-12 14:48:26 -04:00
19 changed files with 321 additions and 149 deletions
+8
View File
@@ -97,6 +97,14 @@ Added more verbose diagnostics when illegal statements are run in the
init phase.
Added _rollback, which controls if rollback is enabled.
Added a target parameter to renpy.full_restart, which allows the main
menu screen to be selected after a restart.
Fixed a bug that caused layout.imagemap_main_menu to call a label even
though there was a button with the same name.
+6 -8
View File
@@ -682,12 +682,6 @@ label _start:
$ renpy.block_rollback()
python hide:
for i in range(0, 7):
# renpy.music.stop(channel=i)
# renpy.sound.stop(channel=i)
pass
if config.main_menu_music:
$ renpy.music.play(config.main_menu_music, if_changed=True)
else:
@@ -703,9 +697,13 @@ label _start:
jump expression _restart[1]
label _invoke_main_menu:
$ renpy.call_in_new_context("_main_menu")
if _restart:
$ renpy.call_in_new_context(_restart[2])
else:
$ renpy.call_in_new_context("_main_menu")
# If the main menu returns, then start the game.
jump start
+2
View File
@@ -49,6 +49,8 @@ label start:
e "We look forward to seeing what you can make with this! Good luck!"
window hide
# Returning from the top level quits the game.
return
+1 -1
View File
@@ -1 +1 @@
dist/MSVCR71.dll
dist/msvcr71.dll
+1 -1
View File
@@ -27,7 +27,7 @@
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
# Be sure to change script_version in launcher/script_version.rpy, too!
# Also check to see if we have to update renpy.py.
version = "Ren'Py 6.9.1c"
version = "Ren'Py 6.9.1d"
script_version = 5003000
savegame_suffix = "-LT1.save"
+10 -4
View File
@@ -181,7 +181,7 @@ class Channel(object):
This stores information about the currently-playing music.
"""
def __init__(self, name, default_loop, stop_on_mute):
def __init__(self, name, default_loop, stop_on_mute, tight):
# The name assigned to this channel. This is used to look up
# information about the channel in the MusicContext object.
@@ -237,6 +237,9 @@ class Channel(object):
# Should we stop playing on mute?
self.stop_on_mute = stop_on_mute
# Is this channel tight?
self.tight = tight
if default_loop is None:
# By default, should we loop the music?
@@ -431,7 +434,7 @@ class Channel(object):
pss.fadeout(self.number, int(secs * 1000))
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=False):
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
for filename in filenames:
renpy.game.persistent._seen_audio[filename] = True
@@ -439,6 +442,9 @@ class Channel(object):
if not pcm_ok:
return
if tight is None:
tight = self.tight
for filename in filenames:
qe = QueueEntry(filename, int(fadein * 1000), tight)
self.queue.append(qe)
@@ -496,11 +502,11 @@ all_channels = [ ]
channels = { }
def register_channel(name, mixer=None, loop=None, stop_on_mute=True):
def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False):
if not renpy.game.init_phase:
raise Exception("Can't register channel outside of init phase.")
c = Channel(name, loop, stop_on_mute)
c = Channel(name, loop, stop_on_mute, tight)
c.mixer = mixer
all_channels.append(c)
channels[name] = c
+2 -2
View File
@@ -35,7 +35,7 @@ from renpy.audio.audio import get_channel, get_serial
# Part of the public api:
from renpy.audio.audio import register_channel, alias_channel
def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=False, fadein=0, tight=False, if_changed=False):
def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=False, fadein=0, tight=None, if_changed=False):
"""
This stops the music currently playing on the numbered channel, dequeues
any queued music, and begins playing the specified file or files. If loop
@@ -108,7 +108,7 @@ def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=Fals
raise
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=False):
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=None):
"""
This queues the given filenames on the specified channel. If
clear_queue is True, then the queue is cleared, making these files
+1 -1
View File
@@ -214,7 +214,7 @@ def display_say(show_function,
# If we're in fast skipping mode, don't bother with say
# statements at all.
if renpy.config.skipping == "fast":
if interact and renpy.config.skipping == "fast":
# Clears out transients.
renpy.exports.with_statement(None)
+18 -17
View File
@@ -276,22 +276,6 @@ class SayBehavior(renpy.display.layout.Null):
def event(self, ev, x, y, st):
skip_delay = renpy.config.skip_delay / 1000.0
if renpy.config.allow_skipping and renpy.config.skipping and \
st >= skip_delay:
if renpy.game.preferences.skip_unseen:
return True
elif renpy.config.skipping == "fast":
return True
elif renpy.game.context().seen_current(True):
return True
if renpy.config.allow_skipping and renpy.config.skipping and \
st < skip_delay:
renpy.game.interface.timeout(skip_delay - st)
if self.afm_length and renpy.game.preferences.afm_time and renpy.game.preferences.afm_enable:
afm_delay = ( 1.0 * ( renpy.config.afm_bonus + self.afm_length ) / renpy.config.afm_characters ) * renpy.game.preferences.afm_time
@@ -311,7 +295,7 @@ class SayBehavior(renpy.display.layout.Null):
renpy.game.interface.timeout(afm_delay - st)
for dismiss in self.dismiss:
if map_event(ev, dismiss) and self.is_focused():
if renpy.config.skipping:
@@ -325,6 +309,23 @@ class SayBehavior(renpy.display.layout.Null):
return True
skip_delay = renpy.config.skip_delay / 1000.0
if renpy.config.allow_skipping and renpy.config.skipping and \
st >= skip_delay:
if renpy.game.preferences.skip_unseen:
return True
elif renpy.config.skipping == "fast":
return True
elif renpy.game.context().seen_current(True):
return True
if renpy.config.allow_skipping and renpy.config.skipping and \
st < skip_delay:
renpy.game.interface.timeout(skip_delay - st)
return None
+1 -1
View File
@@ -1024,7 +1024,7 @@ class Display(object):
contents of the window.
"""
surf = renpy.display.module.scale(self.window, scale)
surf = renpy.display.scale.smoothscale(self.window, scale)
sio = cStringIO.StringIO()
renpy.display.module.save_png(surf, sio, 0)
+2 -1
View File
@@ -78,7 +78,8 @@ class ImageFont(object):
def render(self, text, antialias, color, black_color=(0, 0, 0, 255), background=None):
if not text:
return surf
return pygame.Surface((0, self.height), 0,
renpy.game.interface.display.sample_surface)
xoff, _ = self.offsets[text[0]]
x = -xoff
+36 -19
View File
@@ -770,15 +770,20 @@ class Scale(ImageBase):
def load(self):
child = cache.get(self.image)
if self.bilinear:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.smoothscale(cache.get(self.image), (self.width, self.height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = renpy.display.scale.smoothscale(child, (self.width, self.height))
finally:
renpy.display.render.blit_lock.release()
else:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(cache.get(self.image), (self.width, self.height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(child, (self.width, self.height))
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -813,14 +818,18 @@ class FactorScale(ImageBase):
height = int(height * self.height)
if self.bilinear:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.smoothscale(surf, (width, height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = renpy.display.scale.smoothscale(surf, (width, height))
finally:
renpy.display.render.blit_lock.release()
else:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(surf, (width, height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(surf, (width, height))
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -856,9 +865,13 @@ class Flip(ImageBase):
def load(self):
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.flip(cache.get(self.image), self.horizontal, self.vertical)
renpy.display.render.blit_lock.release()
child = cache.get(self.image)
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.flip(child, self.horizontal, self.vertical)
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -893,9 +906,13 @@ class Rotozoom(ImageBase):
def load(self):
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.rotozoom(cache.get(self.image), self.angle, self.zoom)
renpy.display.render.blit_lock.release()
child = cache.get(self.image)
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.rotozoom(child, self.angle, self.zoom)
finally:
renpy.display.render.blit_lock.release()
return rv
+1
View File
@@ -383,6 +383,7 @@ else:
if version >= 6009000:
def subpixel(src, dst, x, y):
shift = renpy.game.interface.display.sample_surface.get_shifts()[3]
_renpy.subpixel(src, dst, x, y, shift)
+89 -65
View File
@@ -27,6 +27,7 @@ import math
import renpy
# We grab the blit lock each time it is necessary to blit
# something. This allows call to the pygame.transform functions to
# disable blitting, should it prove necessary.
@@ -488,10 +489,12 @@ def draw(dest, clip, what, xo, yo, screen):
if clip:
w, h = what.get_size()
dest.blits.append((xo, yo, xo + w, yo + h, clip, what, None))
else:
blit_lock.acquire()
dest.blit(what, (xo, yo))
blit_lock.release()
else:
try:
blit_lock.acquire()
dest.blit(what, (xo, yo))
finally:
blit_lock.release()
# Subpixel blit.
else:
@@ -1346,82 +1349,103 @@ class Canvas(object):
self.surf = surf
def rect(self, color, rect, width=0):
blit_lock.acquire()
pygame.draw.rect(self.surf,
renpy.easy.color(color),
rect,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.rect(self.surf,
renpy.easy.color(color),
rect,
width)
finally:
blit_lock.release()
def polygon(self, color, pointlist, width=0):
blit_lock.acquire()
pygame.draw.polygon(self.surf,
renpy.easy.color(color),
pointlist,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.polygon(self.surf,
renpy.easy.color(color),
pointlist,
width)
finally:
blit_lock.release()
def circle(self, color, pos, radius, width=0):
blit_lock.acquire()
pygame.draw.circle(self.surf,
renpy.easy.color(color),
pos,
radius,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.circle(self.surf,
renpy.easy.color(color),
pos,
radius,
width)
finally:
blit_lock.release()
def ellipse(self, color, rect, width=0):
blit_lock.acquire()
pygame.draw.ellipse(self.surf,
renpy.easy.color(color),
rect,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.ellipse(self.surf,
renpy.easy.color(color),
rect,
width)
finally:
blit_lock.release()
def arc(self, color, rect, start_angle, stop_angle, width=1):
blit_lock.acquire()
pygame.draw.arc(self.surf,
renpy.easy.color(color),
rect,
start_angle,
stop_angle,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.arc(self.surf,
renpy.easy.color(color),
rect,
start_angle,
stop_angle,
width)
finally:
blit_lock.release()
def line(self, color, start_pos, end_pos, width=1):
blit_lock.acquire()
pygame.draw.line(self.surf,
renpy.easy.color(color),
start_pos,
end_pos,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.line(self.surf,
renpy.easy.color(color),
start_pos,
end_pos,
width)
finally:
blit_lock.release()
def lines(self, color, closed, pointlist, width=1):
blit_lock.acquire()
pygame.draw.lines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.lines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
width)
finally:
blit_lock.release()
def aaline(self, color, startpos, endpos, blend=1):
blit_lock.acquire()
pygame.draw.aaline(self.surf,
renpy.easy.color(color),
startpos,
endpos,
blend)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.aaline(self.surf,
renpy.easy.color(color),
startpos,
endpos,
blend)
finally:
blit_lock.release()
def aalines(self, color, closed, pointlist, blend=1):
blit_lock.acquire()
pygame.draw.aalines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
blend)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.aalines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
blend)
finally:
blit_lock.release()
+122 -22
View File
@@ -67,7 +67,6 @@ def real_bilinear(src, size):
def real_transform_scale(surf, size):
global real_transform_scale
real_transform_scale = pygame.transform.scale
return real_transform_scale(surf, size)
# Loads an image, without scaling it.
@@ -88,6 +87,50 @@ def image_save_unscaled(surf, dest):
pygame.image.save(surf, dest)
if _renpy:
real_renpy_pixellate = _renpy.pixellate
real_renpy_bilinear = _renpy.bilinear
def real_smoothscale(src, size, dest=None):
"""
This scales src up or down to size. This uses both the pixellate
and the bilinear operations to handle the scaling.
"""
width, height = size
srcwidth, srcheight = src.get_size()
iwidth, iheight = srcwidth, srcheight
if dest is None:
dest = PygameSurface(size, src.get_flags(), src)
if width == 0 or height == 0:
return dest
xshrink = 1
yshrink = 1
while iwidth >= width * 2:
xshrink *= 2
iwidth /= 2
while iheight >= height * 2:
yshrink *= 2
iheight /= 2
if iwidth != srcwidth or iheight != srcheight:
inter = PygameSurface((iwidth, iheight), src.get_flags(), src)
real_renpy_pixellate(src, inter, xshrink, yshrink, 1, 1)
src = inter
real_renpy_bilinear(src, dest)
return dest
else:
real_smoothscale = pygame.transform.smoothscale
smoothscale = real_smoothscale
def init():
@@ -143,6 +186,29 @@ def load_scaling():
def real(s):
return s.surface
def same_size(*args):
"""
If all the surfaces in args are the same size, return them all
unchanged. Otherwise, compute smallest width and height, and
take subsurfaces of anythign bigger.
"""
w = min(i.get_width() for i in args)
h = min(i.get_height() for i in args)
size = (w, h)
rv = [ ]
for i in args:
if i.get_size() != size:
i = i.subsurface((0, 0) + size)
rv.append(i)
return rv
def scale(n):
if n is None:
return n
@@ -168,7 +234,7 @@ def load_scaling():
if scale_fast:
scaled = old_transform_scale(full, v2p(full.get_size()))
else:
scaled = old_transform_smoothscale(full, v2p(full.get_size()))
scaled = real_smoothscale(full, v2p(full.get_size()))
return Surface(scaled, wh=full.get_size())
@@ -199,6 +265,8 @@ def load_scaling():
func = getattr(PygameSurface, name)
def rv(self, *args, **kwargs):
return func(self.surface, *args, **kwargs)
return rv
class Surface(object):
@@ -217,7 +285,10 @@ def load_scaling():
else:
w, h = what
self.width, self.height = w, h
w = int(w)
h = int(h)
self.width = w
self.height = h
w = int(w * factor)
h = int(h * factor)
@@ -229,8 +300,7 @@ def load_scaling():
sample = sample.surface
self.surface = PygameSurface((w, h), flags, sample)
self.virtx = 0
self.virty = 0
self.physx = 0
@@ -363,7 +433,7 @@ def load_scaling():
prect = self.transform_rect(rect)
surf = self.surface.subsurface(prect)
rv = Surface(surf, wh=rect[2:])
vx, vy, vw, vh = rect
@@ -441,8 +511,15 @@ def load_scaling():
def image_load(*args, **kwargs):
full = old_image_load(*args, **kwargs)
if full.get_masks()[3] == 0:
full = full.convert()
else:
full = full.convert_alpha()
return surface_scale(full)
pygame.image.load = image_load
old_transform_scale = pygame.transform.scale
@@ -460,7 +537,11 @@ def load_scaling():
def transform_smoothscale(surf, size, dest=None):
rv = old_transform_smoothscale(surf.surface, v2p(size), dest.surface)
if dest is not None:
rv = old_transform_smoothscale(surf.surface, v2p(size), dest.surface)
else:
rv = old_transform_smoothscale(surf.surface, v2p(size))
rv = Surface(rv, wh=size)
return rv
@@ -491,7 +572,7 @@ def load_scaling():
# Ignoring scale2x and chop. The former due to a pending api change,
# the latter due to general uselessness.
PygameFont = font_module.Font
class Font(object):
@@ -535,13 +616,9 @@ def load_scaling():
def get_descent(self):
return int(self.font.get_descent() / factor)
# Ignored:
#
# set_at
# Anything involving palettes.
# Anything involving the parents of subsurfaces.
# get_pitch, get_shifts, get_losses
def set_expand(self, value):
self.font.set_expand(value * factor)
font_module.Font = Font
old_image_save = pygame.image.save
@@ -595,7 +672,8 @@ def load_scaling():
old_map = _renpy.map
def map(pysrc, pydst, r, g, b, a):
old_map(pysrc.surface, pydst.surface, r, g, b, a)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_map(pysrc, pydst, r, g, b, a)
_renpy.map = map
@@ -603,7 +681,8 @@ def load_scaling():
old_linmap = _renpy.linmap
def linmap(pysrc, pydst, r, g, b, a):
old_linmap(pysrc.surface, pydst.surface, r, g, b, a)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_linmap(pysrc, pydst, r, g, b, a)
_renpy.linmap = linmap
@@ -645,8 +724,8 @@ def load_scaling():
def alpha_munge(pysrc, pydst, srcchan, dstchan, amap):
old_alpha_munge(pysrc.surface, pydst.surface,
srcchan, dstchan, amap)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_alpha_munge(pysrc, pydst, srcchan, dstchan, amap)
_renpy.alpha_munge = alpha_munge
@@ -674,18 +753,27 @@ def load_scaling():
old_blend = _renpy.blend
def blend(pysrca, pysrcb, pydst, alpha):
old_blend(pysrca.surface, pysrcb.surface, pydst.surface, alpha)
pysrca, pysrcb, pydst = same_size(pysrca.surface, pysrcb.surface, pydst.surface)
old_blend(pysrca, pysrcb, pydst, alpha)
_renpy.blend = blend
old_imageblend = _renpy.imageblend
def imageblend(pysrca, pysrcb, pydst, pyimg, aoff, amap):
old_imageblend(pysrca.surface, pysrcb.surface, pydst.surface,
pyimg.surface, aoff, amap)
pysrca, pysrcb, pydst, pyimg = same_size(pysrca.surface, pysrcb.surface, pydst.surface, pyimg.surface)
old_imageblend(pysrca, pysrcb, pydst, pyimg, aoff, amap)
_renpy.imageblend = imageblend
old_colormatrix = _renpy.colormatrix
def colormatrix(src, dst, *args):
src, dst = same_size(src.surface, dst.surface)
old_colormatrix(src, dst, *args)
_renpy.colormatrix = colormatrix
def draw_scale(o):
if isinstance(o, int):
@@ -721,7 +809,19 @@ def load_scaling():
pygame.draw.aaline = draw_wrap(pygame.draw.aaline)
pygame.draw.aalines = draw_wrap(pygame.draw.aalines)
# Smoothscale:
def smoothscale(surf, size, dest=None):
if dest is not None:
dest = dest.surface
rv = real_smoothscale(surf.surface, v2p(size), dest)
if rv is None:
return rv
else:
return Surface(rv, wh=size)
# Now, put everything from this function's namespace into the
# module namespace.
+7 -3
View File
@@ -67,7 +67,8 @@ def checkpoint(data=None):
statement.
"""
renpy.game.log.checkpoint(data)
if renpy.store._rollback:
renpy.game.log.checkpoint(data)
def block_rollback():
"""
@@ -684,6 +685,9 @@ def rollback():
Rolls the state of the game back to the last checkpoint.
"""
if not renpy.store._rollback:
return
if not renpy.game.context().rollback:
return
@@ -734,7 +738,7 @@ def take_screenshot(scale=None):
renpy.game.interface.take_screenshot(scale)
def full_restart(transition=False, label="_invoke_main_menu"):
def full_restart(transition=False, label="_invoke_main_menu", target="_main_menu"):
"""
This causes a full restart of Ren'Py.
"""
@@ -742,7 +746,7 @@ def full_restart(transition=False, label="_invoke_main_menu"):
if transition is False:
transition = renpy.config.end_game_transition
raise renpy.game.FullRestartException((transition, label))
raise renpy.game.FullRestartException((transition, label, target))
def utter_restart():
"""
+9 -3
View File
@@ -108,15 +108,21 @@ def image_exists(name, expression, tag):
check_file_cache = { }
def check_file(what, fn):
if fn in check_file_cache:
return True
check_file_cache[fn] = True
present = check_file_cache.get(fn, None)
if present is True:
return
if present is False:
report("%s uses file '%s', which is not loadable.", what.capitalize(), fn)
return
if not renpy.loader.loadable(fn):
report("%s uses file '%s', which is not loadable.", what.capitalize(), fn)
check_file_cache[fn] = False
return
check_file_cache[fn] = True
try:
renpy.loader.transfn(fn)
except:
+1 -1
View File
@@ -307,7 +307,7 @@ def main():
try:
run(restart)
finally:
restart = (renpy.config.end_game_transition, "_invoke_main_menu")
restart = (renpy.config.end_game_transition, "_invoke_main_menu", "_main_menu")
save_persistent()
except game.QuitException, e:
+4
View File
@@ -44,9 +44,13 @@ _window = False
# The window subtitle.
_window_subtitle = ''
# Should rollback be allowed?
_rollback = True
# config.
_config = renpy.config
class _Config(object):
def __init__(self, name):