Complete lyra game

This commit is contained in:
2022-08-05 19:50:51 -05:00
parent 6ef7becac7
commit 7a473693b8
17 changed files with 831 additions and 1604 deletions
-353
View File
@@ -1,353 +0,0 @@
"""
ATL Text Tags Ren'Py Module
2021 Daniel Westfall <SoDaRa2595@gmail.com>
http://twitter.com/sodara9
I'd appreciate being given credit if you do end up using it! :D Would really
make my day to know I helped some people out!
Really hope this can help the community create some really neat ways to spice
up their dialogue!
http://opensource.org/licenses/mit-license.php
Forum Post: https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=60527&sid=75b4eb1aa5212a33cbfe9b0354e5376b
Github: https://github.com/SoDaRa/Kinetic-Text-Tags
itch.io: https://wattson.itch.io/kinetic-text-tags
"""
# 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.
# General Notes:
# I have not tested every transform property and such some may not work as indended
# Most common ones work fine such as pos and offset.
# I can't imagine this being an issue for most of them. However I imagine that
# anchor, xanchor, yanchor, fit and events may not have the indended effect.
# Tranforms used for ATLText must take up time if they repeat
# The following will cause an error:
# transform random_pos(range):
# xpos (random.random() * range)
# ypos (random.random() * range)
# # If there were a pause 0.01 here, it'd be fine. w/o it, renpy flags this as an infinite loop.
# repeat
# Sadly, repeating a section a limited number of times does not work.
# As an example:
# transform text_rotate_3d(time=1.5):
# matrixanchor (0.5,0.5)
# matrixtransform RotateMatrix(0,0,0) * OffsetMatrix(0,0,100)
# linear time matrixtransform RotateMatrix(180,0,180) * OffsetMatrix(0,0,100)
# linear time matrixtransform RotateMatrix(360,0,360) * OffsetMatrix(0,0,100)
# matrixtransform RotateMatrix(0,0,0) * OffsetMatrix(0,0,100)
# repeat 3
# matrixtransform RotateMatrix(0,0,0) * OffsetMatrix(0,0,100)
# linear time matrixtransform RotateMatrix(180,0,180) * OffsetMatrix(0,0,50)
# linear time matrixtransform RotateMatrix(360,0,360) * OffsetMatrix(0,0,0)
# The 'repeat 3' will be skipped and instead just fall through into the next section.
# Thus, repeated sections must be included manually. Which sucks but idk a way
# around it right now.
# Thankfully, infinite repeats work without issue.
# Using matrixtransform and zpos is possible. However, standard text is applied on
# the screens layer. Using:
# camera screens:
# perspective True
# Will enable that layer to use the 3D stage.
# HOWEVER!!!
# Doing so will prevent the user from being able to interact with any buttons
# on that layer. Therefore, it is advised that if you want to use the 3D stage
# for text transforms, you have it be handled on a layer.
# Below is an example of how to implement this.
# While making this I frequently had the source code up for things
# Relevant bits to look over were:
# defaultstore.rpy for how At() works
# display/motion.py for how various kinda of movement are handled
# display/transform.py for the TransformState, Tranform and ATLTransform classes
# atl.py for ATLTransformBase class, which handles a lot of functions for ATLTransform
# display/accelerator.pyx for how Tranform handles rendering.
transform bounce:
ease 0.5 yoffset 10 matrixcolor TintMatrix("#f00")
ease 0.5 yoffset -10 matrixcolor TintMatrix("#00f")
repeat
transform bounce_text(yoff):
ease 0.5 ypos yoff
ease 0.5 ypos -yoff
repeat
transform rotate_text(speed):
linear speed rotate 180
linear speed rotate 360
rotate 0
repeat
transform drop_text(letter, time):
contains:
letter
contains:
letter
yoffset 0 alpha 1
easeout_circ time yoffset 50 alpha 0
letter
repeat
transform fade_in_text(time=0.5, distance=20):
alpha 0 xoffset distance
ease time alpha 1 xoffset 0
# Doing the following will help with using 3D stage transforms on say screen text
# Defining the new layer below the screens layer to allow it to go behind anything on the screens layer
# define config.layers = [ 'master', 'transient', 'threeD_text', 'screens', 'overlay' ]
# Tell the character to use our new layer to display the screen.
# define e_3d = Character("Eileen3D", show_layer="threeD_text")
# And before using the character, be sure to do:
# camera threeD_text:
# perspective True
# And the 3D stage things should work.
# You can also make this layer the default for showing the say screen by doing.
# define config.say_layer = "threeD_text"
# Also remember you can override elements of a character for a line, such as with:
# "Here's a narration line with an override to {atl=-0.1, text_rotate_3d}allow for 3D Text.{/atl}" (show_layer="threeD_text")
transform text_rotate_3d(time=1.5):
matrixanchor (0.5,0.5)
matrixtransform RotateMatrix(0,0,0) * OffsetMatrix(0,0,100)
linear time matrixtransform RotateMatrix(180,0,0) * OffsetMatrix(0,0,100)
linear time matrixtransform RotateMatrix(360,0,0) * OffsetMatrix(0,0,100)
matrixtransform RotateMatrix(0,0,0) * OffsetMatrix(0,0,100)
repeat
init python:
class ATLText(renpy.Displayable):
def __init__(self, child, transforms, offset=0, hold=False,**kwargs):
super(ATLText, self).__init__(**kwargs)
self.child = At(child, *transforms)
self.offset = offset
self.hold = hold
# If your ATL uses 2+ contains for a character to be used twice, then
# a fixed is made to contain them. During rendering, this can lead
# to a render that is far larger than the actual character's render.
# To combat this, I'm having it check the original Text's render size
# so we can use that instead. This shouldn't have many consequences,
# but if you observe something weird, maybe try removing the below and
# using the child render's size in the render function
child_render = renpy.render(child, 0, 0, 0, 0)
self.width, self.height = child_render.get_size()
# Because of how renpy handles transforms on screens in 7.4.7, we
# have to update the internals of the transform to get the appropriate
# time on it. Otherwise our offset won't have the correct effect.
# If you're using Renpy 7.4.6 or below and this causes issues, you
# can remove this bit.
if config.atl_start_on_show:
renpy.render(self.child, 0, 0, 0, 0)
def render(self, width, height, st, at):
# Apply the time offset.
st = st + self.offset
at = at + self.offset
if self.hold:
st = max(st, 0)
at = max(at, 0)
# Get child render and our output render
child_render = renpy.render(self.child, width, height, st, at)
# self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
# Next section is to figure out the offset applied to the blit
# Get_Placement returns a tuple containing:
# xpos, ypos, xanchor, yanchor, xoffset, yoffset, subpixel
child_pos = self.child.state.get_placement()
# Sometimes the output of get_placement has some None values in there.
# So use this to get safe output.
def none_to_float(param):
if param is None:
return 0.0
return param
child_xpos = none_to_float(child_pos[0]) + none_to_float(child_pos[4])
child_ypos = none_to_float(child_pos[1]) + none_to_float(child_pos[5])
render.blit(child_render, (child_xpos,child_ypos))
renpy.redraw(self, 0)
return render
def visit(self):
return [ self.child ]
# Allows one to use one or more ATL transforms to define a movement for text.
# Arguments are separated by ',' and transform parameters are separated by '~'
# The offset and hold arguments are optional.
# Arguments:
# offset: (float/'#'/'-#') The time offset between two characters (in seconds).
# If #, then it use's the user's cps setting as the offset
# If -#, does the above but treats it as negative.
# See Notes for details on negative offsets
# hold: ('#') Tells the displayable to hold the value at 0 if time is negative.
# Is ignored if offset is positive.
# See Notes on negative offsets for more details.
# transform_name: (string) The name of a defined transform.
# Will throw an error if doesn't exist
# param: (float/string/'#') A parameter for the transform. Must be ordered by position.
# All numbers will be interpreted as floats. Strings should evaluate to a displayable, a global variable OR
# optionally, can be left as '#' in order to use the current character as a displayable parameter.
# (No current support for keyword args)
# Notes:
# - Transforms are applied using an At() displayable and are added in the same order.
#
# - If a negative offset is supplied, we have to be careful of what time
# we supply to the ATL's render function. If we give it a negtive number, it
# will treat that value as it's new 0 seconds. So if we feed it -2 seconds
# to start, then when it reaches -1.8 seconds, it'll treat that as 0.2 seconds.
# This has the effect of syncronizing every letter, which isn't what we want.
#
# - To combat this, if a negative offset is given I instead push the first
# letter forward in time. That way each subsequent character can approach
# zero with the negative offset.
# So, for example, if we have 6 characters and the offset is to be -0.2 seconds,
# then the 1st character will start at 1.0 seconds, 2nd will start at 0.8,
# and so on until the 6th character starts at 0 seconds.
#
# - However, this may not always be the ideal setup for all transforms,
# such as fades. An alternative is then to hold the time at 0 until it becomes
# positive. Which is what the 'hold' argument applies.
# Re-using the example from before, every character starts at 0 seconds,
# The 1st character will start to move immediately, but the 2nd character
# will wait 0.2 seconds before starting. The 3rd waits 0.4, 4th waits 0.6,
# until the 6th character waits 1.0 seconds before starting.
#
# Examples:
# {atl=[offset],[hold],[transform_name]~[param]~...),...}Text{/atl}
# {atl=0.1, rotate_text~0.5, bounce_text~10}Text{/atl}
# {atl=drop_text~#~0.5}Text{/atl}
# {atl=-#,#,fade_in_text~1.0~-100}Text{/atl}
def atl_tag(tag, argument, contents):
new_list = []
# Split the argument into a list of transforms and their parameters
arg_list = argument.split(',')
atl_list = []
time_offset = 0
hold = False
# Check for an offset
# See if we want to use the current cps settings
if arg_list[0] == "#" or arg_list[0] == "-#":
if preferences.text_cps is not 0:
time_offset = (1.0 / preferences.text_cps)
if arg_list[0] == "-#":
time_offset = time_offset * -1.0
arg_list.pop(0)
# Attempt checking if the first parameter is a float.
else:
try:
time_offset = float(arg_list[0])
arg_list.pop(0)
except:
time_offset = 0
if arg_list[0] == "#":
hold = True
arg_list.pop(0)
# Go through the arguments for transforms.
# Returns False if it finds a "#" in the params without text set
# Otherwise returns a list of transforms
def arg_handler(arg_list, text=None):
return_list = []
for arg in arg_list:
if '~' in arg:
txt_param_list = arg.split('~')
arg = txt_param_list[0].strip()
# Remove the name of the transform from the parameters list
txt_param_list.pop(0)
param_list = []
for i in range(len(txt_param_list)):
param = None
txt_param_list[i] = txt_param_list[i].strip()
# If a #, then we'll have to do some special stuff later
if txt_param_list[i] == "#":
if text == None: # If we weren't supplied a way to handle this, return
return False
param_list.append(text)
continue
# Attempt a float
try:
param = float(txt_param_list[i])
except ValueError:
param = None
# Attempt a global variable
if param == None and txt_param_list[i] in globals():
param = globals()[txt_param_list[i]]
# Attempt a displayable
elif param == None:
param = renpy.displayable(txt_param_list[i])
param_list.append(param)
return_list.append(globals()[arg](*param_list))
else:
arg = arg.strip()
return_list.append(globals()[arg])
return return_list
# Setup char_index
char_index = 0
count_back = False # Used to know if we count forwards or backwards
# If offset is negative and we aren't holding time at zero, count
# the number of characters so char_index can count down to 0.
if time_offset < 0 and not hold:
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
char_index += len(text)
# Handles adding images into text. Remove if you don't want this behavior
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
char_index += 1
time_offset = time_offset * -1.0
count_back = True
atl_list = arg_handler(arg_list) # Attempt to get a list of atl functions
# Usual kinetic-text-tag text handling
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_text = Text(my_style.apply_style(char))
if atl_list == False:
# If we got a false earlier, then we know we want to call
# one of the transforms with the text character as a parameter
# so we generate the atl_list necessary for each character.
new_atl_list = arg_handler(arg_list, char_text)
char_disp = ATLText(char_text, new_atl_list, char_index * time_offset, hold)
else:
char_disp = ATLText(char_text, atl_list, char_index * time_offset, hold)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
if count_back:
char_index -= 1
else:
char_index += 1
elif kind == renpy.TEXT_TAG:
# Handles adding images into text. Remove if you don't want this behavior
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
if atl_list == False:
new_atl_list = arg_handler(arg_list, my_img)
img_disp = ATLText(my_img, new_atl_list, char_index * time_offset, hold)
else:
img_disp = ATLText(my_img, atl_list, char_index * time_offset, hold)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
if count_back:
char_index -= 1
else:
char_index += 1
elif not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
config.custom_text_tags["atl"] = atl_tag
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

-841
View File
@@ -1,841 +0,0 @@
"""
Kinetic Text Tags Ren'Py Module
2021 Daniel Westfall <SoDaRa2595@gmail.com>
http://twitter.com/sodara9
I'd appreciate being given credit if you do end up using it! :D Would really
make my day to know I helped some people out!
Really hope this can help the community create some really neat ways to spice
up their dialogue!
http://opensource.org/licenses/mit-license.php
Github: https://github.com/SoDaRa/Kinetic-Text-Tags
itch.io: https://wattson.itch.io/kinetic-text-tags
Forum Post: https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=60527&sid=75b4eb1aa5212a33cbfe9b0354e5376b
"""
# 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.
### UPDATE ###
# With the new ATL text tag, a handful of effects I've made have become redundant.
# Namely the bounce (bt), fadein (fi) and rotation (rotat) effects.
# However, I'll leave them in here for posterity and in case someone would like
# to reuse some of the code for whatever purpose.
# Plus the bounce and fadein may be faster to type for some. And I'd probably
# break some code if I did. Though feel free to remove them if you find them
# to be clutter.
##### Our preference to disable the chaos text #####
default preferences.chaos_on = False # You can change this to be gui.chaos_text or persistent.chaos_text if you'd prefer.
init python:
import random
import math
# This will maintain what styles we want to apply and help us apply them
class DispTextStyle():
# Notes:
# - "" denotes a style tag. Since it's usually {=user_style} and we partition
# it over the '=', it ends up being an empty string
# - If you want to add your own tags to the list, I recommend adding them
# before the ""
# - Self-closing tags should not be added here and should be handled
# in the text tag function.
custom_tags = ["omega", "bt", "fi", "sc", "rotat", "chaos", "move"]
accepted_tags = ["", "b", "s", "u", "i", "color", "alpha", "font", "size", "outlinecolor", "plain", 'cps']
custom_cancel_tags = ["/" + tag for tag in custom_tags]
cancel_tags = ["/" + tag for tag in accepted_tags]
def __init__(self):
self.tags = {}
# For setting style properties. Returns false if it accepted none of the tags
def add_tags(self, char):
tag, _, value = char.partition("=") # Separate the tag and its info
# Add tag to dictionary if we accept it
if tag in self.accepted_tags or tag in self.custom_tags:
if value == "":
self.tags[tag] = True
else:
self.tags[tag] = value
return True
# Remove mark tag as cleared if should no longer apply it
if tag in self.cancel_tags or tag in self.custom_cancel_tags:
tag = tag.replace("/", "")
self.tags.pop(tag)
return True
return False # If we got any other tag, tell the function to let it pass
# Applies all style properties to the string
def apply_style(self, char):
new_string = ""
# Go through and apply all the tags
new_string += self.start_tags()
# Add the character in the middle
new_string += char
# Now close all the tags we opened
new_string += self.end_tags()
return new_string
# Spits out start tags. Primarily used for SwapText
def start_tags(self):
new_string = ""
# Go through the custom tags
for tag in self.custom_tags:
if tag in self.tags:
if self.tags[tag] == True:
new_string += "{" + tag + "}"
else:
new_string += "{" + tag + "=" +self.tags[tag] + "}"
# Go through the standard tags
for tag in self.accepted_tags:
if tag in self.tags:
if self.tags[tag] == True:
new_string += "{" + tag + "}"
else:
new_string += "{" + tag + "=" +self.tags[tag] + "}"
return new_string
# Spits out ending tags. Primarily used for SwapText
def end_tags(self):
new_string = ""
# The only tags we are required to end are any custom text tags.
# And should also end them in the reverse order they were applied.
reversed_cancels = [tag for tag in self.custom_cancel_tags]
reversed_cancels.reverse()
for tag in reversed_cancels:
temp = tag.replace("/", "")
if temp in self.tags:
new_string += "{" + tag + "}"
return new_string
### TEXT WRAPPER CLASSES ###
# Basic text displacement demonstration
class BounceText(renpy.Displayable):
def __init__(self, child, char_offset, amp=20, period=4.0, speed = 1.0, **kwargs):
# Pass additional properties on to the renpy.Displayable
# constructor.
super(BounceText, self).__init__(**kwargs) # REMEMBER TO RENAME HERE TO YOUR CLASS
# For all of my classes, I assume I am being passed a displayable
# of class Text. If you might not, I recommend going with the default of
# self.child = renpy.displayable(child)
self.child = child
self.amp = amp # The amplitude of the sine wave
self.char_offset = char_offset # The offset into the sine wave
self.period = period # Affects the distance between peaks in the wave.
self.speed = speed # Affects how fast our wave moves as a function of time.
def render(self, width, height, st, at):
# Where the current offset is calculated
# (self.char_offset * -.1) makes it look like the left side is leading
# We use st to allow this to change over time
curr_height = math.sin(self.period*((st * self.speed)+(float(self.char_offset) * -.1))) * float(self.amp)
#### A Transform can be used for several effects ####
# t = Transform(child=self.child, alpha = curr_height)
# Create a render from the child.
# Replace self.child with t to include an alpha or zoom transform
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
# This will position our child's render. Replacing our need for an offset Transform
render.subpixel_blit(child_render, (0, curr_height))
renpy.redraw(self, 0) # This lets it know to redraw this indefinitely
return render
def event(self, ev, x, y, st):
return self.child.event(ev, x, y, st)
def visit(self):
return [ self.child ]
# Simple fade in. Helps show some ideas for timing
# May want to modify to allow it to skip to the end if the user clicks.
# Otherwise plays for the full time given.
class FadeInText(renpy.Displayable):
def __init__(self, child, char_num, fade_time, slide_distance=100, **kwargs):
super(FadeInText, self).__init__(**kwargs)
# The child.
self.child = child
self.fade_time = fade_time
self.display_time = .01
self.slide_distance = slide_distance
# This is to get seconds per character on screen for later
# Allowing this effect to scale with the player's desired text speed
cps = 0.0
if preferences.text_cps is not 0: # Avoid division by 0.0
cps = (1.0 / preferences.text_cps)
self.time_offset = char_num * cps # How long to wait before doing things
def render(self, width, height, st, at):
curr_alpha = 0.0
xoff = 5.0
if st > self.time_offset:
adjust_st = st - self.time_offset # Adjust for time delay
curr_alpha = adjust_st/self.fade_time
xoff = max(self.slide_distance - ((adjust_st/self.fade_time) * self.slide_distance), 0)
# Example of using transform to adjust alpha
t = Transform(child=self.child, alpha = curr_alpha)
child_render = renpy.render(t, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
render.subpixel_blit(child_render, (xoff, 0))
# Stop redrawing when the animation is finished.
if st <= self.fade_time + self.time_offset:
renpy.redraw(self, 0)
return render
def visit(self):
return [ self.child ]
# Simple random motion effect
class ScareText(renpy.Displayable):
def __init__(self, child, square=2, **kwargs):
super(ScareText, self).__init__(**kwargs)
self.child = child
self.square = square # The size of the square it will wobble within.
# Include more variables if you'd like to have more control over the positioning.
def render(self, width, height, st, at):
# Randomly move the offset of the text's render.
xoff = (random.random()-.5) * float(self.square)
yoff = (random.random()-.5) * float(self.square)
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
render.subpixel_blit(child_render, (xoff, yoff))
renpy.redraw(self, 0)
return render
def visit(self):
return [ self.child ]
# Demonstration of changing text styles on the fly
# Could also predefine some styles and swap between those as well!
# Also for this effect in particular, I ---HIGHLY--- advise building in some way to disable it
# as it can be pretty harsh on the eyes.
# An example of how you can make this a preference option is included below.
class ChaosText(renpy.Displayable):
# Some may want to have this list be more of a global variable than baked into the class.
font_list = ["FOT-PopJoyStd-B.otf", "GrenzeGotisch-VariableFont_wght.ttf", "Pacifico-Regular.ttf", "RobotoSlab-ExtraBold.ttf",\
"RobotoSlab-Medium.ttf", "SyneTactile-Regular.ttf", "TurretRoad-Bold.ttf", "TurretRoad-ExtraBold.ttf", "TurretRoad-ExtraLight.ttf", \
"TurretRoad-Light.ttf", "TurretRoad-Medium.ttf", "TurretRoad-Regular.ttf"]
#Just a list so we can pull any hex value randomly
color_choice = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
def __init__(self, orig_text, **kwargs):
super(ChaosText, self).__init__(**kwargs) #REMEMBER TO RENAME HERE TO YOUR CLASS
# Create our child
self.child = renpy.text.text.Text(orig_text)
self.orig_text = orig_text
self.last_style = None # This will be used for renders if the user wants to stop chaos text
def render(self, width, height, st, at):
if not preferences.chaos_on: # This preference is defined near the top of this file. And can be set in the preferences screen (see line 783-787 in screens.rpy)
if self.last_style is not None: # If this is our first render, then should do that first
# Rest of this is just a repeat of what's below.
self.child.set_text(self.last_style.apply_style(self.orig_text))
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
render.subpixel_blit(child_render, (0, 0))
return render
# We'll create a new text style for this render
new_style = DispTextStyle()
new_color = ""
# Create a random color using hex values
for i in range(0,6):
new_color += renpy.random.choice(self.color_choice)
new_color = "#" + new_color
new_style.add_tags("color=" + str(new_color))
# Random size
rand_size = renpy.random.randint(0,50)
new_style.add_tags("size="+str(rand_size))
# Random font
rand_font = renpy.random.choice(self.font_list)
new_style.add_tags("font="+rand_font)
#Apply our style to our Text child
self.child.set_text(new_style.apply_style(self.orig_text))
# Create a render from the child.
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
render.subpixel_blit(child_render, (0, 0))
renpy.redraw(self,0)
self.last_style = new_style # Save the current style for if the user wishes to turn off the Chaos tag
return render
def visit(self):
return [ self.child ]
# Demonstration of using a Transform on the text and applying rotation
class RotateText(renpy.Displayable):
def __init__(self, child, speed=300, **kwargs):
super(RotateText, self).__init__(**kwargs)
self.child = child
self.speed = speed # The speed of our rotation
def render(self, width, height, st, at):
theta = math.radians(st * float(self.speed))
t = Transform(child=self.child, rotate=st*float(self.speed))
child_render = renpy.render(t, width, height/2, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height/2)
# Problem with using a Transform though is that each character will be padded
# Because the rotation may make it wider or taller depending on the character and angle.
# How best to tackle this though may vary depending on how you'd like to implement it.
render.blit(child_render, (0,0))
renpy.redraw(self, 0)
return render
def visit(self):
return [ self.child ]
# The following is an alternative version of rotate that allows for rotation in the x and y axis
# Functionally equivalent to using a Transform and flipping it using ATL xzoom and yzoom constrained between 0 and 1
# Using a Transform might be better in some cases, but I'll leave this here for anyone who'd prefer to work with angles
# for this kind of effect.
# Other matrix functions of note include
# renpy.display.matrix.perspective(w,h,n,p,f)
# renpy.display.matrix.screen_projection(w,h) < Renpy space to OpenGL viewport
# renpy.display.matrix.texture_projection(w,h) < Renpy space to OpenGL render-to-texture
# You can look up more about them in the renpy\display\matrix_functions.pyx file
# Credit to the FancyText module creator yukinogatari for the idea.
# FancyText module can be found at https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=59587
"""
class RotateText(renpy.Displayable):
def __init__(self, child, speed=100, **kwargs):
super(RotateText, self).__init__(**kwargs)
self.child = child
self.speed = speed # The speed of our rotation
def render(self, width, height, st, at):
angle = st * self.speed
# Which parameter you put the 'angle' into will affect which axis the render rotates on.
# Try moving it around and seeing what happens.
rotation_m = renpy.display.matrix.rotate(angle,0,0)
child_render = renpy.render(self.child, width, height, st, at)
c_width, c_height = child_render.get_size()
# This applies the rotation to our child's render.
child_render.reverse = rotation_m
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
# Math nerds might realize I'm not offsetting the transform.
# While renpy.display.matrix.offset(x,y,z) is a thing, it won't change much
# The real place to apply the offset is in your final blit. Which is what we'll calculate here
# Rotations on x axis
theta2 = math.radians(st * float(self.speed) + 180)
c = math.cos(theta2) + 1.0
xoff = 0
yoff = c * self.height
if yoff > self.height:
yoff = self.height
render.subpixel_blit(child_render, (xoff,yoff))
renpy.redraw(self, 0)
return render
def visit(self):
return [ self.child ]
"""
# Simple text swap effect
# It can be prone to having letters out of place when part of a larger string
# I recommended you pass it the entire line to avoid this issue.
# Can also just define every line it'll need in advance and just tell it which
# ones to swap to to be extra sneaky. Then the text won't be in your script at all!
class SwapText(renpy.Displayable):
def __init__(self, start_tags, text1, text2, end_tags, swap_time, **kwargs):
super(SwapText, self).__init__(**kwargs)
#Style tags we'll need as well as the text
self.start_tags = start_tags
self.text1 = text1
self.text2 = text2
self.end_tags = end_tags
# How long between swapping text
self.s_time = swap_time
# An internal timer to keep track of when to swap
self.timer = 0.0
# Determines if we swap to text1 or text2 next
self.swap_to_1 = False
self.child = Text(start_tags + text1 + end_tags)
self.st = 0.0
def render(self, width, height, st, at):
delta = st - self.st # How long since last update
self.timer += delta
if self.timer > self.s_time:
# If time to swap, determine which one to swap to.
if self.swap_to_1:
self.child.set_text(self.start_tags + self.text1 + self.end_tags)
self.swap_to_1 = False
self.timer = 0.0
else:
self.child.set_text(self.start_tags + self.text2 + self.end_tags)
self.swap_to_1 = True
self.timer = 0.0
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
render.subpixel_blit(child_render, (0,0))
renpy.redraw(self, 0)
self.st = st # So we can check how long since last update
return render
def visit(self):
return [ self.child ]
# An example of text that moves and reacts to the mouse.
# Sidenote: The position the mouse is distorted if the screen is resized.
# I did try to find a way to counteract this, but didn't have much luck.
# Seems to only happen on the x component though. No clue why.
# If anyone can pinpoint the issue, please let me know and I'll be happy to fix it.
class MoveText(renpy.Displayable):
def __init__(self, child, **kwargs):
super(MoveText, self).__init__(**kwargs)
self.affect_distance = 150
self.child = child
self.mouse_pos = (1000,1000)
self.pos = (0,0)
def render(self, width, height, st, at):
child_render = renpy.render(self.child, width, height, st, at)
self.width, self.height = child_render.get_size()
render = renpy.Render(self.width, self.height)
# x and y we get in the event function are relative to the top left corner of the displayable initially.
# So we'll want to update it to reflect the actual position of our text
trans_x = self.mouse_pos[0] - self.pos[0] - (self.width / 2)
trans_y = self.mouse_pos[1] - self.pos[1] - (self.height / 2)
vl = math.hypot(trans_x,trans_y)
xpos, ypos = self.pos
# Can skip calculation if vector length is further than our specified effect distance
if vl < self.affect_distance:
distance = 3.0 * (self.affect_distance-vl) / self.affect_distance
xpos -= distance * trans_x / vl
ypos -= distance * trans_y / vl
self.pos = (xpos, ypos) # Preserve the new pos
# Use our child's position as determined by the event function
render.subpixel_blit(child_render, (xpos, ypos))
renpy.redraw(self, 0)
return render
def event(self, ev, x, y, st):
self.mouse_pos = (x,y)
# Pass the event to our child.
return self.child.event(ev, x, y, st)
def visit(self):
return [ self.child ]
### CUSTOM TAG FUNCTIONS ###
# Letters move in a sine wave.
# Arguments are separated by dashes.
# Arguments:
# 'a': (int) The amplitude (height) of the text's sine wave motion. How high and low it'll go from it's default position in pixels.
# 'p': (float) The period of the wave. Distance between peaks in the wave.
# 's': (float) The speed of the wave. How fast it moves with time.
# Example: {bt=[height]}Text{/bt}
# Example: {bt=h5-p2.0-s0.5}Text{/bt}
# If a lone number is given, it is treated as the amplitude only to ensure backwards compatibility
# Example: {bt=10}Text{/bt}
def bounce_tag(tag, argument, contents):
new_list = [ ] # The list we will be appending our displayables into
amp, period, speed = 20, 4.0, 1.0
if argument == "": # If the argument received is blank, insert a default value
amp = 20
else:
argument = argument.split('-')
if len(argument) == 1 and argument[0][0].isdigit(): # Default behavior to ensure backward compatibility
amp = int(argument[0])
else:
for arg in argument:
if arg[0] == 'a':
amp = int(arg[1:])
elif arg[0] == 'p':
period = float(arg[1:])
elif arg[0] == 's':
speed = float(arg[1:])
char_offset = 0 # Since we want our text to move in a wave,
# we want to let each character know where it is in the wave.
# So they move in harmony. Otherwise they rise and fall all together.
my_style = DispTextStyle() # This will keep track of what tags and styling to add to each letter
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text: # Extract every character from the string
char_text = Text(my_style.apply_style(char)) # Create a Text displayable with our styles applied
char_disp = BounceText(char_text, char_offset, amp=amp, period=period, speed=speed) # Put the Text into the Wrapper
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp)) # Add it back in as a displayable
char_offset += 1
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
img_disp = BounceText(my_img, char_offset, amp=amp, period=period, speed=speed)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
char_offset += 1
elif not my_style.add_tags(text):
new_list.append((kind, text))
# I honestly never got around to testing this. Not often the text
# already has a displayable in it. Let me know if it breaks though.
elif kind == renpy.TEXT_DISPLAYABLE:
char_disp = BounceText(text, char_offset, amp=amp, period=period, speed=speed)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
char_offset += 1
else: # Don't touch any other type of content
new_list.append((kind,text))
return new_list
# Letters will start off to the right & invisible. And will then move left while increasing their opacity. Good for meditation and calm text.
# offset: (int) Offset within the line. Needed to help time start of fade-in with other slow text characters.
# time: (float) How long in seconds the animation lasts.
# distance: (int) How many pixels the fade in occurs across
# Example: {fi=[offset]-[time]-[distance]}Text{/fi}
def fade_in_tag(tag, argument, contents):
new_list = [ ]
my_index, fade_time, slide_distance = 0, 5.0, 100
if argument != "":
argument = argument.split('-')
if len(argument) > 0:
my_index = int(argument[0])
if len(argument) > 1:
fade_time = float(argument[1])
if len(argument) > 2:
slide_distance = int(argument[2])
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
if char == ' ':
new_list.append((renpy.TEXT_TEXT, ' ')) # Skips blank space since looks weird counting it
continue
char_text = Text(my_style.apply_style(char))
char_disp = FadeInText(char_text, my_index, fade_time, slide_distance)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
my_index += 1
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
img_disp = FadeInText(my_img, my_index, fade_time, slide_distance)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
my_index += 1
elif not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Letters change position every frame randomly. Good for very angry or quivering dialogue.
# range: (int) Letters are confined to a square around their default location. Range determines length of the sides of that square.
# Higher values will make it very chaotic while smaller values will make it quite minimal.
# Example: {sc=[range]}Text{/sc}
def scare_tag(tag, argument, contents):
new_list = [ ]
if argument == "":
argument = 5
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_text = Text(my_style.apply_style(char))
char_disp = ScareText(char_text, argument)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
img_disp = ScareText(my_img, argument)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
elif not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Letters change their font, color and size every frame.
# Example: {chaos}Text{/chaos}
# Honestly more a demonstration of what can be done than useful in it's own right.
# If you create tags this chaotic, please include a way to turn it off for people with epilepsy.
def chaos_tag(tag, argument, contents):
new_list = [ ]
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_disp = ChaosText(my_style.apply_style(char))
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Letters rotate in place. Good for stylized intros or UI
# Speed: (int) How fast the rotation will be.
# Example: {rotat=[speed]}Text{/rotat}
def rotate_tag(tag, argument, contents):
new_list = [ ]
# Argument here will reprsent the desired speed of the rotation.
if argument == "":
argument = 400
else:
argument = int(argument)
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_text = Text(my_style.apply_style(char))
char_disp = RotateText(char_text, argument)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
img_disp = RotateText(my_img, argument)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
elif not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Causes letters to change between two strings every couple of seconds.
# text1: (String) First set of characters to display. Should be equal to the length of the characters we're replacing
# text2: (String) Second set of characters to display. Should be equal to the length of text1
# swap_time: (int) Length of time between character swap
# Arguments are separated by '@'. Length of strings should not exceed length of text they are replacing.
# Example: {swap=Text@Four@0.5}Text{}
# This is a pretty static way of doing it mostly made to demonstrate the concept.
# Included for others to build upon for their needs.
def swap_tag(tag, argument, contents):
new_list = [ ]
if argument == "":
return contents
text1, _, argument = argument.partition("@")
text2, _, argument = argument.partition("@")
if len(text1) != len(text2):
new_list.append((renpy.TEXT_TEXT, "ERROR!"))
swap_time = float(argument)
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
# This one replaces the whole text rather than extracting over letters
# That way it can take up this whole block with its own Text displayable
char_disp = SwapText(my_style.start_tags(), text1, text2, my_style.end_tags(), swap_time)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Makes it so the text within moves away from the mouse. More example of what can be done than useful
# Example: {move}Text{/move}
def move_tag(tag, argument, contents):
new_list = [ ]
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_text = Text(my_style.apply_style(char))
char_disp = MoveText(char_text)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if text.find("image") != -1:
tag, _, value = text.partition("=")
my_img = renpy.displayable(value)
img_disp = MoveText(my_img)
new_list.append((renpy.TEXT_DISPLAYABLE, img_disp))
elif not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
# Some text effects won't allow for a paragraph break if applied to a whole line
# Which can cause your text to just continue straight off the screen.
# To amend this, you can insert the {para} tag.
# This will let the Text displayable holding us know when to wrap.
# Can also use \n in most cases. But leaving this for people who may already be using it
# or for cases where \n doesn't work.
def paragraph_tag(tag, argument):
return [(renpy.TEXT_PARAGRAPH, "")]
# This tag is made to automatically wrap several Classes inside one another
# This is to reduce strain on the render pipeline and memory from nested classes
# Notes:
# GradientText and GlitchText are omitted because they were made after the 1.0 release.
# SwapText and MoveText are omitted for possible issues.
# SwapText because is not included in this due to it replacing whole sections rather than
# individual letters. Would be better to embed an Omega inside a SwapText.
# MoveText because of potential issues of having things like BounceText affect
# affecting the position of the letter visually.
# Would be better to have an event call attached to one of those so it can account
# for the transformations of other tags
# Argument Notes (all tag args accept same arguments as original tag):
# BT: BounceText
# SC: ScareText
# FI: FadeInText
# ROT: RotateText
# CH: ChaosText
# All tag arguments are seperated by @.
# Example: {omega=BT=[bt_arg]@SC=[sc_arg]@FI=[fi_arg1]-[fi_arg2]@ROT=[rot_arg]@CH}Text{/omega}
def omega_tag(tag, argument, contents):
new_list = [ ]
if argument == "": # This tag must have arguments
return contents
# Variable for each of our tags. None if it takes one argument.
# Boolean if 0 or many arguments.
bt_tag = None
sc_tag = None
fi_tag = False
rot_tag = None
chao_tag = False
fi_arg_1 = None
fi_arg_2 = None
args = [ ]
arg_count = argument.count('@') # Count how many partitions we will need to make
for x in range(arg_count): # Extract all the tags and arguments with them
new_arg, _, argument = argument.partition('@')
args.append(new_arg)
args.append(argument)
# Determine what tags we'll need to apply and the arguments associated with them
for arg in args:
tag, _, value = arg.partition('=')
if tag == "BT":
if value is not "":
bt_tag = value
else:
bt_tag = 10
elif tag == "SC":
if value is not "":
bt_tag = value
else:
bt_tag = 5
# Multiargument tag example. Be sure to use different partitions for these
elif tag == "FI":
fi_tag = True
str1, _, str2 = value.partition('-')
fi_arg_1 = int(str1)
fi_arg_2 = float(str2)
elif tag == "ROT":
rot_tag = value
elif tag == "CH":
chao_tag = True
my_style = DispTextStyle()
my_index = 0 # Some Classes will need an index
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
# Apply base Wrappers to letter
if chao_tag:
char_disp = ChaosText(my_style.apply_style(char))
else:
char_disp = Text(my_style.apply_style(char))
# Apply further Wraps
# Be sure to consider if the order will be important to you
if bt_tag is not None:
char_disp = BounceText(char_disp, my_index, bt_tag)
if sc_tag is not None:
char_disp = ScareText(char_disp, sc_tag)
if fi_tag:
char_disp = FadeInText(char_disp, my_index + fi_arg_1, fi_arg_2)
if rot_tag is not None:
char_disp = RotateText(char_disp, rot_tag)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
"""
# Template tag function to copy off of.
def TEMPLATE_tag(tag, argument, contents):
new_list = [ ]
if argument == "":
argument = 5
my_style = DispTextStyle()
for kind,text in contents:
if kind == renpy.TEXT_TEXT:
for char in text:
char_text = Text(my_style.apply_style(char))
char_disp = TEMPLATEText(char_text, argument)
new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
elif kind == renpy.TEXT_TAG:
if not my_style.add_tags(text):
new_list.append((kind, text))
else:
new_list.append((kind,text))
return new_list
"""
# Define our new text tags
config.custom_text_tags["bt"] = bounce_tag
config.custom_text_tags["fi"] = fade_in_tag
config.custom_text_tags["sc"] = scare_tag
config.custom_text_tags["rotat"] = rotate_tag
config.custom_text_tags["chaos"] = chaos_tag
config.custom_text_tags["swap"] = swap_tag
config.custom_text_tags["move"] = move_tag
config.custom_text_tags["omega"] = omega_tag
config.self_closing_custom_text_tags["para"] = paragraph_tag
# Template tag function
#config.custom_text_tags[""] = _tag
+8 -4
View File
@@ -12,7 +12,7 @@
##
## The _() surrounding the string marks it as eligible for translation.
define config.name = _("sexo_space_lady_game")
define config.name = _("A Star in her Eyes")
## Determines if the title given above is shown on the main menu screen. Set
@@ -30,6 +30,10 @@ define config.version = "1.0"
## triple-quotes, and leave a blank line between paragraphs.
define gui.about = _p("""
A game made by Cavemanon, an upcoming indie game team comprised of many members from around the world. Currently developing {color=#f1a5d8}Exit 665{/color}, {color=#f1a5d8}I Wani Hug that Gator!{/color}, and potentially more!
You can find out about most recent updates and developments at our {a=https://twitter.com/Cavemanon}twitter{/a}.
""")
@@ -37,7 +41,7 @@ define gui.about = _p("""
## distribution. This must be ASCII-only, and must not contain spaces, colons,
## or semicolons.
define build.name = "sexo_space_lady_game"
define build.name = "A_Star_in_her_Eyes"
## Sounds and music ############################################################
@@ -48,7 +52,7 @@ define build.name = "sexo_space_lady_game"
define config.has_sound = True
define config.has_music = True
define config.has_voice = True
define config.has_voice = False
## To allow the user to play a test sound on the sound or voice channel,
@@ -120,7 +124,7 @@ define config.window_hide_transition = Dissolve(.2)
## Controls the default text speed. The default, 0, is infinite, while any other
## number is the number of characters per second to type out.
default preferences.text_cps = 0
default preferences.text_cps = 50
## The default auto-forward delay. Larger numbers lead to longer waits, with 0
+823 -405
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

-1
View File
@@ -1 +0,0 @@
hello