renpy/tutorial/game/01example.rpy

638 lines
31 KiB
Plaintext
Raw Normal View History

2023-01-18 22:13:55 +00:00
python early:
# This maps from example name to the text of a fragment.
examples = { }
# The size of the example - large or small.
example_size = "small"
# The location of the example - top or bottom.
example_location = "top"
# The screen in the last example.
example_screen = None
# A transition used with examples
example_transition = None
def reset_example():
"""
Called to reset the example code to the defaults.
"""
global example_size
global example_location
global example_screen
example_size = "small"
example_location = "top"
example_screen = None
def show_example_screen(name):
global example_screen
example_screen = name
renpy.show_screen(name)
def hide_example_screen():
global example_screen
if example_screen is not None:
renpy.hide_screen(example_screen)
example_screen = None
# Keywords that, at the start of an example block, cause it to be
# outdented
OUTDENT_KEYWORDS = { "define", "default", "image", "screen", "init", "transform", "label", "style" }
# This defines the example statement.
#
# The example statement takes:
# * An optional name for the example.
# * An optional hide flag.
# * Optional size flags, large or small.
# * Optional position flags, top or bottom.
#
# The statement defines an example with the name, or an anyonymous name if no
# name is given. When run, the example is displayed if the hide flag is not
# given.
def read_example(name, fn, line, outdent):
"""
This reads an example from an example statement, and places it into
the examples dictionary.
"""
fn = fn.replace("game/", "")
with renpy.notl_file(fn) as f:
data = f.read().decode("utf-8")
rawlines = [ i.rstrip() for i in data.split("\n") ]
lines = [ ]
base_indent = 0
while True:
if line >= len(rawlines):
raise Exception("Example open at end of {}.".format(fn))
l = rawlines[line]
line += 1
if not l:
lines.append(l)
continue
indent = len(l) - len(l.lstrip())
if base_indent == 0:
base_indent = indent
lines.append(l[4:])
elif indent >= base_indent:
lines.append(l[4:])
else:
break
# Determine if the line should be indented.
if outdent == "auto":
for i in lines:
l = i.strip().split()
if not l:
continue
if l[0] in OUTDENT_KEYWORDS:
outdent = True
else:
outdent = False
break
# Strip indentation.
if outdent:
lines = [ i[base_indent - 4:] for i in lines ]
if name in examples:
examples[name].append('')
examples[name].extend(lines)
else:
examples[name] = lines
def parse_example(l):
"""
This parses the example statement.
"""
# The name of the example. A string, or None if we don't know yet.
name = None
# Hide, bottom, and small flags.
hide = False
bottom = False
small = False
top = False
large = False
outdent = "auto"
show_screen = True
hide_screen = True
showtrans = False
while True:
if l.match(':'):
break
elif l.keyword('hide'):
hide = True
elif l.keyword('bottom'):
bottom = True
elif l.keyword('small'):
small = True
elif l.keyword('top'):
top = True
elif l.keyword('large'):
large = True
elif l.keyword('outdent'):
outdent = True
elif l.keyword('nooutindent'):
outdent = False
elif l.keyword("noshow"):
show_screen = False
elif l.keyword("nohide"):
hide_screen = False
elif l.keyword("showtrans"):
showtrans = True
else:
if name:
l.error('an example may have at most one name')
name = l.require(l.name)
l.expect_eol()
if name is None:
name = "example_{}_{}".format(l.filename, l.number)
ll = l.subblock_lexer()
ll.advance()
if ll.keyword('screen'):
screen_name = ll.name()
else:
screen_name = None
return {
"name" : name,
"names" : [ name ],
"hide" : hide,
"bottom" : bottom,
"small" : small,
"filename" : l.filename,
"number" : l.number,
"top" : top,
"large" : large,
"outdent" : outdent,
"screen_name" : screen_name,
"show_screen" : show_screen,
"hide_screen" : hide_screen,
"showtrans" : showtrans,
}
def next_example(data, first):
return first
def execute_example(data):
names = data.get("names", [ ])
hide = data.get("hide", False)
bottom = data.get("bottom", False)
small = data.get("small", False)
top = data.get("top", False)
large = data.get("large", False)
showtrans = data.get("showtrans", False)
global example_location
global example_size
if bottom:
example_location = "bottom"
elif top:
example_location = "top"
if small:
example_size = "small"
elif large:
example_size = "large"
if not hide:
renpy.show_screen("example", names, example_size == "small", example_location == "bottom", showtrans=showtrans)
screen_name = data.get("screen_name", None)
if screen_name is not None:
if data.get("hide_screen", True):
hide_example_screen()
if data.get("show_screen", True):
show_example_screen(screen_name)
renpy.with_statement(example_transition)
def execute_init_example(data):
read_example(data["name"], data["filename"], data["number"], data.get("outdent", "auto"))
renpy.register_statement("example", parse=parse_example, execute=execute_example, execute_init=execute_init_example, next=next_example, block="script")
# The show example statement.
def parse_show_example(l):
names = [ ]
bottom = False
small = False
top = False
large = False
showtrans = False
while not l.eol():
if l.keyword('bottom'):
bottom = True
elif l.keyword('small'):
small = True
elif l.keyword('top'):
top = True
elif l.keyword('large'):
large = True
elif l.keyword('showtrans'):
showtrans = True
else:
names.append(l.require(l.name))
return {
"names" : names,
"hide" : False,
"bottom" : bottom,
"small" : small,
"top" : top,
"large" : large,
"showtrans" : showtrans,
}
renpy.register_statement("show example", parse=parse_show_example, execute=execute_example)
# The hide example statement.
def parse_hide_example(l):
hide_screen = True
while not l.eol():
if l.keyword('nohide'):
hide_screen = False
else:
break
l.expect_eol()
return {
"hide_screen" : hide_screen,
}
def execute_hide_example(data):
renpy.hide_screen("example")
if example_screen and data.get("hide_screen", True) and renpy.get_screen(example_screen):
hide_example_screen()
renpy.with_statement(example_transition)
renpy.register_statement("hide example", parse=parse_hide_example, execute=execute_hide_example)
# A preference that controls if translations are shown.
default persistent.show_translation_marker = False
init python:
dialogue_map = { }
for i in renpy.known_languages():
dialogue_map[i] = renpy.translation.dialogue.create_dialogue_map(i)
import re
import keywords
KEYWORDS = set(keywords.keywords)
PROPERTIES = set(keywords.properties)
regex = r"(?P<word>\b(\$|[_a-zA-Z0-9]+)\b)" + \
r"|(?P<string>\"([^\"]|\\.)*(?<!\\)\")" + \
r"|(?P<comment>#.*)"
regex = re.compile(regex)
def quote(s):
s = s.replace("{", "{{")
s = s.replace("[", "[[")
return s
def translate(m):
if m.group("string"):
s = eval(m.group(0))
if __(s) != s:
s = __(s)
elif _preferences.language:
dm = dialogue_map[_preferences.language]
if s in dm:
s = dm[s]
quote = m.group(0)[0]
s = s.replace("\\", "\\\\")
s = s.replace(quote, "\\" + quote)
s = s.replace("\n", "\\n")
s = quote + s + quote
return s
return m.group(0)
def colorize(m):
if m.group("string"):
return "{color=#060}" + m.group(0) + "{/color}"
word = m.group("word")
if word:
if word in KEYWORDS:
return "{color=#840}" + m.group(0) + "{/color}"
elif word in PROPERTIES:
return "{color=#048}" + m.group(0) + "{/color}"
else:
return m.group(0)
if m.group("comment"):
return "{color=#600}" + m.group(0) + "{/color}"
return m.group(0)
def clean_example(lines):
rv = list(lines)
while rv and not rv[0]:
rv.pop(0)
while rv and not rv[-1]:
rv.pop(-1)
return rv
def example_code(blocks, raw=False, showtrans=False):
if not isinstance(blocks, list):
blocks = [ blocks ]
# Collect the examples we use.
lines1 = [ ]
for i in blocks:
if i not in examples:
lines1.append('Example {} not found.'.format(i))
else:
lines1.extend(clean_example(examples[i]))
lines1.append('')
# Strip off doubled blank lines.
last_blank = False
lines = [ ]
for i in lines1:
if not i and last_blank:
continue
last_blank = not i
i = regex.sub(translate, i)
if not (persistent.show_translation_marker or showtrans):
i = re.sub(r'__?\((".*?")\)', r'\1', i)
i = re.sub(r"__?\(('.*?')\)", r'\1', i)
i = i.replace("!t]", "]")
if not raw:
i = quote(i)
i = regex.sub(colorize, i)
lines.append(i)
while not lines[-1]:
lines.pop()
# Join them into a single string.
return "\n".join(lines) + "\n "
class CopyCode(Action):
def __init__(self, s):
self.s = s
def __call__(self):
import pygame.scrap
pygame.scrap.put(pygame.SCRAP_TEXT, self.s.encode("utf-8"))
renpy.notify(_("Copied the example to the clipboard."))
example_transition = dissolve
import os
SHOW_EXAMPLES = ("RENPY_LESS_EXAMPLES" not in os.environ)
transform example_transform(height, ypos):
ypos ypos
yanchor 1.0
xalign 0.5
on replace:
crop (0, 0, 1280, height)
on show:
crop (0, 0, 1280, 0)
linear .5 crop (0, 0, 1280, height)
on hide:
linear .5 crop (0, 0, 1280, 0)
screen example(blocks, small=False, bottom=False, showtrans=False):
zorder 10
default raw_code = example_code(blocks, raw=True, showtrans=showtrans)
default code = example_code(blocks, showtrans=showtrans)
if small:
$ height = 80
else:
$ height = 160
if bottom:
$ ypos = 720
else:
$ ypos = 540
if SHOW_EXAMPLES:
frame:
style "empty"
background "#fffc"
foreground Solid("#aaac", xsize=1, xpos=178)
xfill True
yfill True
ymaximum height
at example_transform(height, ypos)
viewport:
side_xmaximum 1098
side_xpos 180
child_size (2000, 2000)
ymaximum height
draggable True
mousewheel True
scrollbars "vertical"
vscrollbar_xsize 5
vscrollbar_base_bar "#aaac"
vscrollbar_unscrollable "hide"
text code:
alt ""
size 16
color "#000"
textbutton _("copy"):
style "empty"
text_style "quick_button_text"
text_text_align 0.5
text_minwidth 180
text_size 16
action CopyCode(raw_code)
init python hide:
import os.path
import re
# A list of files we will be scanning.
files = [ ]
for i in renpy.list_files():
if i.endswith(".rpy"):
files.append(i)
for fn in files:
try:
with open(os.path.join(renpy.config.gamedir, fn), "r") as f:
lines = f.readlines()
except:
lines = [ ]
open_examples = set()
for l in lines:
l = l.rstrip()
m = re.match("\s*#begin (\w+)", l)
if m:
example = m.group(1)
if example in examples:
raise Exception("Example %r is defined in two places.", example)
open_examples.add(example)
examples[example] = [ ]
continue
m = re.match("\s*#end (\w+)", l)
if m:
example = m.group(1)
if example not in open_examples:
raise Exception("Example %r is not open.", example)
open_examples.remove(example)
continue
for i in open_examples:
examples[i].append(l)
if open_examples:
raise Exception("Examples %r remain open at the end of %r" % (open_examples, fn))
init python:
def lint_stats_callback():
print("The game contains {} examples.".format(len(examples)))
config.lint_stats_callbacks.append(lint_stats_callback)
import base64
image _finaleimage = im.Data(base64.b64decode("""
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
"""), "finale.png")
image _finale:
"_finaleimage"
yalign 0.3
xanchor 1.0 xpos 0.0
pause 90.0
easein 1.5 xanchor 0.0 xpos .25
pause 3.0
easeout 1.5 xanchor 1.0 xpos 0.0
repeat