WTS/game/scripts/utility/text_tags.rpy
2024-06-17 19:24:31 +01:00

286 lines
9.6 KiB
Plaintext

# Custom text tags
# https://www.renpy.org/doc/html/custom_text_tags.html
image text_tag_hearts_image = Fixed(love_heart((15, 0), 12, 0.1), love_heart((20, -10), 6, 0.5), love_heart((10, 10), 6, 1), fit_first=True, xsize=32)
init python:
def convert_tags_to_kwargs(contents):
kwargs = {"style": "what"}
for kind, text in contents:
if kind == renpy.TEXT_TAG:
if text.startswith("="):
kwargs["style"] = text.split("=")[1]
if text.startswith("color="):
kwargs["color"] = text.split("=")[1]
if text.startswith("size="):
kwargs["size"] = int(text.split("=")[1])
if text.startswith("outlinecolor="):
kwargs["outlines"] = [(2, text.split("=")[1], 1, 1)]
if text == "b":
kwargs["bold"] = True
if text == "i":
kwargs["italics"] = True
return kwargs
@renpy.pure
def text_tag_icon(tag, argument):
"""Insert a unicode heart symbol. Usage {heart}"""
return [(renpy.TEXT_DISPLAYABLE, Transform(argument, xysize=(32, 32)))]
@renpy.pure
def text_tag_unicode(tag, argument, contents):
"""Render contents using a font that supports all/most Unicode characters. Usage {unicode}☺{/unicode}"""
# DejaVuSans is included by default in Ren'py
return [(renpy.TEXT_TAG, "font=DejaVuSans.ttf")] + contents + [(renpy.TEXT_TAG, "/font")]
@renpy.pure
def text_tag_heart(tag, argument):
"""Insert a unicode heart symbol. Usage {heart}"""
return [(renpy.TEXT_DISPLAYABLE, At(Text("{unicode}❤{/unicode}", style="what", xsize=24, ysize=24), heart_text))]
@renpy.pure
def text_tag_hearts(tag, argument):
"""Insert multiple unicode heart symbols. Usage {hearts}"""
return [(renpy.TEXT_DISPLAYABLE, Transform("text_tag_hearts_image"))]
@renpy.pure
def text_tag_number(tag, argument):
"""Convert a number to words if lower than 100 or a multiple of 100. Usage {number=expression}"""
num = int(renpy.store.eval(argument)) # Can be a function or an expression.
words = num_to_word(num) if num < 100 or num % 100 == 0 else str(num)
return [(renpy.TEXT_TEXT, words)]
@renpy.pure
def text_tag_wave(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
end_pause = len(text)/100.0
for i, letter in enumerate(text):
start_pause = i/100.0
d = At(Text(letter, **kwargs), wave_text(start_pause, end_pause))
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_bounce(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
end_pause = len(text)/100.0
for i, letter in enumerate(text):
start_pause = i/100.0
d = At(Text(letter, **kwargs), bounce_text(start_pause, end_pause))
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_shake(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
for i, letter in enumerate(text):
d = At(Text(letter, **kwargs), shake_text)
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_pulse(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
d = At(Text(text, **kwargs), pulse_text)
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_shudder(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
d = At(Text(text, **kwargs), shudder_text)
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_flip(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
d = Transform(At(Text(text, **kwargs), flip_text), pos=(240, -2))
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
@renpy.pure
def text_tag_rotate(tag, argument, contents):
rv = []
kwargs = convert_tags_to_kwargs(contents)
for kind, text in contents:
if kind == renpy.TEXT_TEXT:
for i, letter in enumerate(text):
d = Transform(At(Text(letter, **kwargs), rotate_text), pos=(240, -2))
rv.append((renpy.TEXT_DISPLAYABLE, d))
else:
rv.append((kind, text))
return rv
def text_love_heart_func(pos, size, trans, st, at):
warper_rotate = _warper.easein(st / 0.5)
warper_alpha = _warper.easein(st / 1.0)
warper_yoffset = _warper.easein(st / 1.0)
warper_xoffset = _warper.easein(st / 0.2)
trans.child = Text("{unicode}❤{/unicode}", style="what", size=size)
trans.rotate = renpy.atl.interpolate(warper_rotate, -10, 10, renpy.atl.PROPERTIES["alpha"])
trans.yoffset = renpy.atl.interpolate(warper_yoffset, 6, -6, renpy.atl.PROPERTIES["yoffset"])
trans.xoffset = renpy.atl.interpolate(warper_xoffset, -1, 1, renpy.atl.PROPERTIES["xoffset"])
trans.alpha = renpy.atl.interpolate(warper_alpha, 1, 0, renpy.atl.PROPERTIES["alpha"])
return 0.01
def text_shake_func(trans, st, at):
trans.xoffset = absolute(renpy.random.randint(-1, 1))
trans.yoffset = absolute(renpy.random.randint(-1, 1))
return 0.02
transform wave_text(start_pause, end_pause):
animation
subpixel True
yoffset 0
pos (240, -2) # Workaround; Xpos seems to not account for text box offset and text outline?
pause start_pause
easein 0.75 yoffset -6
easein 0.75 yoffset 0
pause end_pause
repeat
transform bounce_text(start_pause, end_pause):
animation
subpixel True
yoffset 0
pos (240, -2) # Workaround; Xpos seems to not account for text box offset and text outline?
pause start_pause
easeout_bounce 1 yoffset -6 yzoom 1.1
easein_bounce 1 yoffset 0 yzoom 1.0
pause end_pause
repeat
transform pulse_text:
animation
subpixel True
yzoom 1
pos (240, -2) # Workaround; Xpos seems to not account for text box offset and text outline?
pause 1
easeout 0.5 yzoom 1.15
easein 0.25 yzoom 1.0
easeout 0.5 yzoom 1.15
easein 0.25 yzoom 1.0
repeat
transform shake_text:
animation
subpixel True
pos (240, -2) # Workaround; Xpos seems to not account for text box offset and text outline?
function text_shake_func
transform shudder_text:
animation
subpixel True
pos (240, -2) # Workaround; Xpos seems to not account for text box offset and text outline?
easeout 0.1 xoffset -3
easeout 0.1 xoffset 3
easeout 0.1 xoffset -3
easeout 0.1 xoffset 3
easeout 0.1 xoffset 0
pause 0.5
repeat
transform flip_text:
animation
subpixel True
perspective True
matrixtransform RotateMatrix(0, 0, 0)
pos (0, 0) # Bugs out without explicit pos; We fix the offsets in a parent
easein 1 matrixtransform RotateMatrix(360.0, 0, 0)
pause 1.5
repeat
transform rotate_text:
animation
subpixel True
perspective True
matrixtransform RotateMatrix(0, 0, 0)
pos (0, 0) # Bugs out without explicit pos; We fix the offsets in a parent
easein 1 matrixtransform RotateMatrix(0, 0, 360.0)
pause 1.5
repeat
transform love_heart(pos, size, pause):
animation
subpixel True
anchor (0.5, 0.5)
xpos 240+pos[0] # Workaround; Xpos seems to not account for text box offset and text outline?
ypos -2+pos[1] # Workaround; Xpos seems to not account for text box offset and text outline?
pause pause
function renpy.partial(text_love_heart_func, pos, size)
repeat
transform heart_text:
animation
subpixel True
anchor (0.5, 0.5)
yzoom 1
xzoom 1
pos (256, 14) # Workaround; Xpos seems to not account for text box offset and text outline?
easein 0.25 yzoom 1.05 xzoom 1.05
easein 0.25 yzoom 1.0 xzoom 1.0
easein 0.25 yzoom 1.05 xzoom 1.05
easein 0.25 yzoom 1.0 xzoom 1.0
choice:
pause 0.25
choice:
pause 0.35
choice:
pause 0.45
repeat
define config.custom_text_tags = {
"unicode": text_tag_unicode,
"wave": text_tag_wave,
"bounce": text_tag_bounce,
"shake": text_tag_shake,
"shudder": text_tag_shudder,
"pulse": text_tag_pulse,
"flip": text_tag_flip,
"rotate": text_tag_rotate,
}
define config.self_closing_custom_text_tags = {
"icon": text_tag_icon,
"heart": text_tag_heart,
"hearts": text_tag_hearts,
"number": text_tag_number,
}