Initial commit
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Exclude rpyc files, except the ones in old-game
|
||||||
|
*.rpyc
|
||||||
|
!old-game/**
|
||||||
|
|
||||||
|
*.rpyc~
|
||||||
|
*.rpymc
|
||||||
|
*.rpy~
|
||||||
|
log.txt
|
||||||
|
*.save
|
||||||
|
*.psd
|
||||||
|
.vscode/
|
||||||
|
game/saves/persistent
|
||||||
|
*.bak
|
||||||
|
cache/
|
||||||
|
|
||||||
|
game/cache/bytecode.rpyb
|
||||||
|
game/cache/pyanalysis.rpyb
|
||||||
|
game/cache/screens.rpyb
|
||||||
|
game/saves/navigation.json
|
||||||
|
traceback.txt
|
||||||
|
errors.txt
|
||||||
|
game/saves/navigation.json
|
||||||
|
game/script_version.txt
|
||||||
|
game/saves/sync/**
|
|
@ -0,0 +1,4 @@
|
||||||
|
# MESSAGE TO ANY DEVELOPERS #
|
||||||
|
# This isn't under any open source license but I've left the source accessible (or at least more accessible than just leaving the .rpyc) if you wanna read it #
|
||||||
|
# I should put this under a license... maybe I'll do it after the jam has ended #
|
||||||
|
# be cool, go to school #
|
|
@ -0,0 +1,196 @@
|
||||||
|
"""
|
||||||
|
Auto Highlight 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!
|
||||||
|
http://opensource.org/licenses/mit-license.php
|
||||||
|
Github: https://github.com/SoDaRa/Auto-Highlight
|
||||||
|
itch.io: https://wattson.itch.io/renpy-auto-highlight
|
||||||
|
"""
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
""" Setup (IMPORTANT) """
|
||||||
|
## To get this working you'll need to do two additional things along with having this file in your project.
|
||||||
|
|
||||||
|
# - First, you'll need to setup your character definitions to support it.
|
||||||
|
# Example:
|
||||||
|
# define eil = Character("Eileen", callback = name_callback, cb_name = "eileen")
|
||||||
|
# - cb_name provides the 'name' parameter to the function 'name_callback'
|
||||||
|
# - Remember that Ren'py supports say_with_arguments.
|
||||||
|
# So you can assign one for a particular line by doing:
|
||||||
|
# eil "I think someone else should be focused" (cb_name = "pileen")
|
||||||
|
# - Finally, if you wish for the special narrator to make all sprites unfocused or something similar,
|
||||||
|
# you can copy this.
|
||||||
|
# define narrator = Character(callback = name_callback, cb_name = None)
|
||||||
|
|
||||||
|
# - Second, you'll need to apply the sprite_highlight transform to all images you want this
|
||||||
|
# applied to. For people using layeredimages, this is very easy. As an example:
|
||||||
|
# layeredimage eileen:
|
||||||
|
# at sprite_highlight('eileen')
|
||||||
|
# ...
|
||||||
|
# - However, if you're using individual sprites, you'll have to be sure this is applied to every one.
|
||||||
|
# image eileen happy = At('eileen_happy', sprite_highlight('eileen'))
|
||||||
|
# image eileen sad = At('eileen_sad', sprite_highlight('eileen'))
|
||||||
|
# Or, if you'd prefer an ATL example
|
||||||
|
# image eileen happy:
|
||||||
|
# 'eileen_happy'
|
||||||
|
# function SpriteFocus('eileen')
|
||||||
|
|
||||||
|
""" General Note """
|
||||||
|
# - This file has to be compiled before any scripts that define images that use this.
|
||||||
|
# As such, this file is named 00auto-highlight.rpy to help with that.
|
||||||
|
# - Be sure that all images that you want to share the same sprite highlight name
|
||||||
|
# are using the same image tag.
|
||||||
|
|
||||||
|
""" Variables """
|
||||||
|
# - sprite_focus - (Dictionary) It is used to help inform who should be animated
|
||||||
|
# and occasionaly holds timing data
|
||||||
|
# - Has entries added to it in the SpriteFocus __call__ function.
|
||||||
|
# - I chose to use a define because it's status should not affect the story and
|
||||||
|
# it can be cleared safely when the player closes the game. Then, when someone boots
|
||||||
|
# up again, it will only have entries added to it as needed.
|
||||||
|
# - If you wish for it's status to be kept between play sessions, then change the 'define' to 'default'
|
||||||
|
define sprite_focus = {}
|
||||||
|
|
||||||
|
# - speaking_char - (Varient) Is manipulated by the character callback to help us know
|
||||||
|
# who the current speaking character is.
|
||||||
|
# - Keeps track of which character is currently speaking. Is updated in name_callback
|
||||||
|
# and checked in SpriteFocus __call__ to determine if sprite's character is speaking
|
||||||
|
# or not.
|
||||||
|
default speaking_char = None
|
||||||
|
|
||||||
|
""" Transforms """
|
||||||
|
# - This is the actual transform that will help apply the changes to your sprites.
|
||||||
|
# - SpriteFocus is used as a callable class here. The function statement doesn't
|
||||||
|
# pass additional parameters to our function, so I use a callable class here to
|
||||||
|
# give the function statement something it can call like a function, while still
|
||||||
|
# providing a way to pass through the transform parameter.
|
||||||
|
transform sprite_highlight(sprite_name):
|
||||||
|
function SpriteFocus(sprite_name)
|
||||||
|
# I don't recommend adding ATL down here since the above statement won't return None.
|
||||||
|
init -10 python:
|
||||||
|
import math
|
||||||
|
|
||||||
|
# name: Name of the character talking at present. Usually a string.
|
||||||
|
# Used by SpriteFocus's __call__ function to determine which sprites to put in talking and non-talking states
|
||||||
|
def name_callback(event, interact=True, name=None, **kwargs):
|
||||||
|
global speaking_char
|
||||||
|
if event == "begin":
|
||||||
|
speaking_char = name
|
||||||
|
|
||||||
|
# Used to help make sprite_tf more reusable while still using the function statement in the ATL
|
||||||
|
class SpriteFocus(object):
|
||||||
|
# char_name - Used to check who we are manipulating. This is used as a
|
||||||
|
# key into sprite_focus and should be equal to it's equivalent string
|
||||||
|
# that is written to speaking_char in the character callback.
|
||||||
|
def __init__(self, char_name):
|
||||||
|
self.char_name = char_name
|
||||||
|
|
||||||
|
## Main function ##
|
||||||
|
# trans - Renpy transform object that we'll manipulate
|
||||||
|
# start_time - (float) Starting time of the current transform
|
||||||
|
# anim_time - (float) Animation time of the current transform. May be >= st.
|
||||||
|
def __call__(self, trans, start_time, anim_time):
|
||||||
|
# The ease function we use to make the animation move a bit more naturally.
|
||||||
|
def get_ease(t):
|
||||||
|
return .5 - math.cos(math.pi * t) / 2.0
|
||||||
|
#### Setup ####
|
||||||
|
global sprite_focus, speaking_char # Get the global variables we defined earlier
|
||||||
|
char_name = self.char_name # Just to save having self.char_name everywhere
|
||||||
|
# Add an entry for our char_name if it's not in the dictionary yet
|
||||||
|
if char_name not in sprite_focus:
|
||||||
|
sprite_focus[char_name] = False
|
||||||
|
anim_length = 0.2 # How long (in seconds) the animation will last
|
||||||
|
bright_change = 0.08 # How much the brightness changes
|
||||||
|
sat_change = 0.2 # How much the saturation changes
|
||||||
|
zoom_change = 0.0025 # How much the zoom changes
|
||||||
|
# - y_change is mostly here because the Minotaur Hotel sprites were made to be kept level with
|
||||||
|
# the bottom of the screen. The zoom change causes them to rise slightly
|
||||||
|
# above it. So I apply a small yoffset to keep them in place.
|
||||||
|
# - If you have full sprites, this can be omitted.
|
||||||
|
# If you do, remember to remove the cooresponding lines in the Transform Manipulation near the bottom
|
||||||
|
y_change = 1 # How much y_offset to apply.
|
||||||
|
|
||||||
|
# is_talking - (Boolean) Determines if we're the talking char or not.
|
||||||
|
# True means we are talking. False means we aren't.
|
||||||
|
is_talking = speaking_char == char_name
|
||||||
|
# - If you would like to add support for multiple characters to be highlighted
|
||||||
|
# then you may want to pass a list of names to speaking_char. And then have something like:
|
||||||
|
# if isinstance(speaking_char, list):
|
||||||
|
# is_talking = char_name in speaking_char
|
||||||
|
# - Or if you want some special name like "all" to mean every sprite should be focused:
|
||||||
|
# if speaking_char == 'all':
|
||||||
|
# is_talking = True
|
||||||
|
|
||||||
|
#### Check & Update Status ####
|
||||||
|
# - If our key in the sprite_focus dictionary is a number AND anim_time is less than that number
|
||||||
|
# then we want to update our talking status in sprite_focus to be a boolean.
|
||||||
|
# - This is to prevent any issues that arrise from anim_time being less than a value we put into sprite_focus.
|
||||||
|
# - IMPORTANT: Anytime our value in sprite_focus is set to a boolean will
|
||||||
|
# represent us being either talking (boolean True) or not talking (boolean False).
|
||||||
|
# It being set to a number will represent animating from one to another.
|
||||||
|
if isinstance(sprite_focus[char_name], (int, float)) and anim_time < sprite_focus[char_name]:
|
||||||
|
sprite_focus[char_name] = is_talking
|
||||||
|
# If our value in the sprite_focus is not equivalent to our talking status AND is a boolean
|
||||||
|
if sprite_focus[char_name] != is_talking and isinstance(sprite_focus[char_name], bool):
|
||||||
|
# Since our talking status has flipped, log the time so we can use it as a timer in the next section
|
||||||
|
sprite_focus[char_name] = anim_time
|
||||||
|
# Unless we're in rollback or are skipping. In which case, we'll want to just snap to the new status
|
||||||
|
if renpy.is_skipping() or renpy.in_rollback():
|
||||||
|
sprite_focus[char_name] = is_talking
|
||||||
|
|
||||||
|
#### Determine Time and Position in Animation ####
|
||||||
|
# - Figure out the current time of the animation
|
||||||
|
# - This will still work, even if our entry in sprite_focus is currently a boolean.
|
||||||
|
# However, it will never be used in such a scenario due to the next if statement.
|
||||||
|
# - Also where that anim_time value we stored in sprite_focus is used
|
||||||
|
curr_time = max(anim_time - sprite_focus[char_name],0) # Prevent going below zero
|
||||||
|
# - The following variable is the actual value we'll use to animate on.
|
||||||
|
# - By default, it's set to 1.0. Which cooresponds to the animation being completed.
|
||||||
|
# It should always remain within the range 0 to 1.
|
||||||
|
curr_ease = 1.0
|
||||||
|
# If curr_time is still less than the animation length AND we aren't a boolean in sprite_focus
|
||||||
|
if curr_time < anim_length and not isinstance(sprite_focus[char_name], bool):
|
||||||
|
curr_ease = get_ease(curr_time/anim_length) # Get our actual animation position
|
||||||
|
else:
|
||||||
|
sprite_focus[char_name] = is_talking # If done with time, register talking status
|
||||||
|
|
||||||
|
#### Transform Manipulation ####
|
||||||
|
# - This bit is what actually applies the changes to the sprite we're manipulating
|
||||||
|
# - If you want a different effect for the talking and non-talking versions, you'll mostly
|
||||||
|
# be doing stuff in here. The actual values you want will depend on the properties you want
|
||||||
|
# to change. But will boil down to having the curr_ease * some_amount_of_change.
|
||||||
|
# - Both transformations should also smoothly flow into each other.
|
||||||
|
# For example, if the talking non-talking version has the sprite moved down 10 pixels,
|
||||||
|
# the talking version should start from 10 pixels down and rise up.
|
||||||
|
if is_talking: # Apply the talking transformation
|
||||||
|
trans.matrixcolor = SaturationMatrix((1.0-sat_change) + curr_ease * sat_change) * BrightnessMatrix(-bright_change + curr_ease * bright_change)
|
||||||
|
trans.zoom = min(curr_ease * zoom_change + (1.0-zoom_change), 1.0)
|
||||||
|
trans.yoffset = y_change - curr_ease * y_change # Delete here if you removed y_change earlier
|
||||||
|
else: # Apply the not-talking transformation
|
||||||
|
trans.matrixcolor = SaturationMatrix(1.0 - curr_ease * sat_change) * BrightnessMatrix(curr_ease * -bright_change)
|
||||||
|
trans.zoom = max(1.0 - curr_ease * zoom_change, (1.0-zoom_change))
|
||||||
|
trans.yoffset = y_change * curr_ease # Delete here if you removed y_change earlier
|
||||||
|
# Finally, we don't really want to ever stop running this.
|
||||||
|
# So we just ask to be continuously redrawn ASAP forever.
|
||||||
|
# Returning > 0 will cause it to redraw slower. And returning None will cause it to stop running
|
||||||
|
return 0
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 503 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 721 B |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 688 KiB |
After Width: | Height: | Size: 603 KiB |
After Width: | Height: | Size: 343 KiB |
After Width: | Height: | Size: 292 KiB |
|
@ -0,0 +1,841 @@
|
||||||
|
"""
|
||||||
|
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
|
|
@ -0,0 +1,54 @@
|
||||||
|
## Adjust Attributes ###########################################################
|
||||||
|
##
|
||||||
|
## This is a special configuration value which can be used to easily create
|
||||||
|
## shorthand for layered images. This code is adapted slightly from Ren'Py Tom's
|
||||||
|
## article on the topic:
|
||||||
|
## https://patreon.renpy.org/dev-2021-04.html#adjust-attribute-example
|
||||||
|
##
|
||||||
|
## You can learn more about config.adjust_attributes here:
|
||||||
|
## https://www.renpy.org/doc/html/config.html#var-config.adjust_attributes
|
||||||
|
##
|
||||||
|
## As per usual, if you do not need it, you may freely remove this file.
|
||||||
|
##
|
||||||
|
|
||||||
|
init -100 python:
|
||||||
|
|
||||||
|
class Aliases(object):
|
||||||
|
"""
|
||||||
|
Expands attributes into other attributes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **aliases):
|
||||||
|
|
||||||
|
# A map from an attribute name to a tuple of
|
||||||
|
# attributes it expands to.
|
||||||
|
self.aliases = { }
|
||||||
|
|
||||||
|
for k, v in aliases.items():
|
||||||
|
self.aliases[k] = tuple(v.split())
|
||||||
|
|
||||||
|
def __call__(self, name):
|
||||||
|
|
||||||
|
# The image tag
|
||||||
|
rv = [ name[0] ]
|
||||||
|
|
||||||
|
# The remaining attributes
|
||||||
|
for i in name[1:]:
|
||||||
|
## Also remove the provided attributes, if negated
|
||||||
|
if i.startswith("-"):
|
||||||
|
prefix = "-"
|
||||||
|
i = i[1:]
|
||||||
|
else:
|
||||||
|
prefix = ""
|
||||||
|
|
||||||
|
for attr in self.aliases.get(i, ( i, )):
|
||||||
|
rv.append(prefix + attr)
|
||||||
|
|
||||||
|
# Turn the results back into a tuple
|
||||||
|
return tuple(rv)
|
||||||
|
|
||||||
|
## A possible use case:
|
||||||
|
# define config.adjust_attributes['eileen'] = Aliases(
|
||||||
|
# happy="eyes_happy mouth_happy",
|
||||||
|
# concerned="eyes_concerned mouth_concerned",
|
||||||
|
# )
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
## Auto indicator screen #######################################################
|
||||||
|
##
|
||||||
|
## This screen is used to indicate that auto-forward mode is in progress.
|
||||||
|
## Created by me, Feniks. You may remove this whole file if you don't need
|
||||||
|
## an auto-forward indicator screen.
|
||||||
|
##
|
||||||
|
|
||||||
|
init python:
|
||||||
|
def auto_indicator():
|
||||||
|
"""
|
||||||
|
A function which, when called, determines if the Auto indicator
|
||||||
|
should be shown on-screen or not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Auto mode is on
|
||||||
|
if preferences.afm_enable and not renpy.get_screen('auto_indicator'):
|
||||||
|
renpy.show_screen('auto_indicator')
|
||||||
|
# Auto mode is off
|
||||||
|
elif not preferences.afm_enable and renpy.get_screen('auto_indicator'):
|
||||||
|
renpy.hide_screen('auto_indicator')
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# This adds the auto indicator to a list of overlay functions
|
||||||
|
# so that it can automatically show the Auto indicator.
|
||||||
|
if auto_indicator not in config.overlay_functions:
|
||||||
|
config.overlay_functions.append(auto_indicator)
|
||||||
|
|
||||||
|
screen auto_indicator():
|
||||||
|
|
||||||
|
zorder 100
|
||||||
|
style_prefix "auto"
|
||||||
|
|
||||||
|
frame:
|
||||||
|
has hbox
|
||||||
|
|
||||||
|
text _("Auto-Forward")
|
||||||
|
|
||||||
|
text "▸" at auto_blink(1.0) style "skip_triangle"
|
||||||
|
|
||||||
|
## This transform is used to blink the arrows one after another.
|
||||||
|
transform auto_blink(cycle):
|
||||||
|
alpha 0.0
|
||||||
|
linear 0.5 alpha 1.0
|
||||||
|
pause 0.2
|
||||||
|
linear 0.5 alpha 0.0
|
||||||
|
pause (cycle - .4)
|
||||||
|
repeat
|
||||||
|
|
||||||
|
style auto_hbox:
|
||||||
|
spacing 9
|
||||||
|
|
||||||
|
style auto_frame:
|
||||||
|
is empty
|
||||||
|
ypos 15
|
||||||
|
background Frame("#0008", 24, 8, 75, 8, tile=False)
|
||||||
|
padding (24, 8, 75, 8)
|
||||||
|
|
||||||
|
style auto_text:
|
||||||
|
size 24
|
||||||
|
|
||||||
|
style auto_triangle:
|
||||||
|
is auto_text
|
||||||
|
## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE
|
||||||
|
## glyph in it.
|
||||||
|
font "DejaVuSans.ttf"
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
## Custom Confirm Action #######################################################
|
||||||
|
##
|
||||||
|
## This file contains an action similar to the Confirm screen action which
|
||||||
|
## it can be used for information and confirmation prompts.
|
||||||
|
## It can be removed if unneeded. In order to work, it requires that
|
||||||
|
## `no_action=None` on the confirm screen so that a second action is optional
|
||||||
|
## (this is the case by default for this template).
|
||||||
|
## You may remove this file without consequence.
|
||||||
|
## See the original Confirm action here:
|
||||||
|
## https://www.renpy.org/doc/html/screen_actions.html#Confirm
|
||||||
|
##
|
||||||
|
## It has three main use cases:
|
||||||
|
## 1) CConfirm("You haven't unlocked this image yet.")
|
||||||
|
## This shows a prompt to the user with the provided text and a
|
||||||
|
## "Confirm" button to dismiss the prompt. There is no "Cancel" button.
|
||||||
|
## 2) CConfirm("Purchase flower? ($10)", SetVariable('money', money-10))
|
||||||
|
## This shows a prompt with Confirm and Cancel buttons. The Confirm
|
||||||
|
## button dismisses the prompt and executes the action or list of
|
||||||
|
## actions provided after the prompt, and Cancel hides the prompt without
|
||||||
|
## executing any other actions.
|
||||||
|
## 3) CConfirm("Go to the next chapter?", yes=Jump("chapter2"), no=MainMenu())
|
||||||
|
## This shows a prompt with Confirm and Cancel buttons. Clicking either
|
||||||
|
## button will dismiss the prompt in addition to performing the provided
|
||||||
|
## yes/no action.
|
||||||
|
##
|
||||||
|
|
||||||
|
init python:
|
||||||
|
|
||||||
|
class CConfirm(Show):
|
||||||
|
"""
|
||||||
|
A class which makes it easy to show simple confirmation prompts
|
||||||
|
to the player.
|
||||||
|
|
||||||
|
It also sets the default value of confirm_selected to True rather
|
||||||
|
than False.
|
||||||
|
"""
|
||||||
|
def __init__(self, prompt, yes=None, no=None, confirm_selected=True,
|
||||||
|
*args, **kwargs):
|
||||||
|
|
||||||
|
if config.confirm_screen and renpy.has_screen('confirm'):
|
||||||
|
screen = "confirm"
|
||||||
|
elif renpy.has_screen("yesno_prompt"):
|
||||||
|
screen = "yesno_prompt"
|
||||||
|
else:
|
||||||
|
screen = None
|
||||||
|
|
||||||
|
# Just a prompt; this only gets a Confirm button which
|
||||||
|
# dismisses the prompt.
|
||||||
|
if yes is None:
|
||||||
|
yes = Hide(screen, config.exit_yesno_transition)
|
||||||
|
no = None
|
||||||
|
else:
|
||||||
|
# All provided actions should hide the confirm screen
|
||||||
|
# after they are clicked
|
||||||
|
if isinstance(yes, list):
|
||||||
|
yes.insert(0, Hide(screen, config.exit_yesno_transition))
|
||||||
|
elif yes != Hide(screen, config.exit_yesno_transition):
|
||||||
|
yes = [Hide(screen, config.exit_yesno_transition), yes]
|
||||||
|
|
||||||
|
# Has both buttons, but "Cancel" should just hide the prompt
|
||||||
|
if no is None:
|
||||||
|
no = Hide(screen, config.exit_yesno_transition)
|
||||||
|
elif no is not None:
|
||||||
|
if isinstance(no, list):
|
||||||
|
no.insert(0, Hide(screen, config.exit_yesno_transition))
|
||||||
|
elif no != Hide(screen, config.exit_yesno_transition):
|
||||||
|
no = [Hide(screen, config.exit_yesno_transition), no]
|
||||||
|
|
||||||
|
self.prompt = prompt
|
||||||
|
self.yes = yes
|
||||||
|
self.no = no
|
||||||
|
self.confirm_selected = confirm_selected
|
||||||
|
self.screen = screen
|
||||||
|
|
||||||
|
super(CConfirm, self).__init__(screen, config.exit_yesno_transition,
|
||||||
|
*args, message=self.prompt, yes_action=self.yes,
|
||||||
|
no_action=self.no, **kwargs)
|
||||||
|
|
||||||
|
def get_sensitive(self):
|
||||||
|
if self.yes is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return renpy.is_sensitive(self.yes)
|
||||||
|
|
||||||
|
def get_selected(self):
|
||||||
|
return renpy.is_selected(self.yes)
|
||||||
|
|
||||||
|
def get_tooltip(self):
|
||||||
|
return renpy.display.behavior.get_tooltip(self.yes)
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
|
||||||
|
if self.screen is None:
|
||||||
|
return Confirm(self.prompt, self.yes, self.no, self.confirm_selected)()
|
||||||
|
elif self.confirm_selected or not self.get_selected():
|
||||||
|
return super(CConfirm, self).__call__()
|
||||||
|
else:
|
||||||
|
return renpy.run(self.yes)
|
|
@ -0,0 +1,76 @@
|
||||||
|
## Gallery #####################################################################
|
||||||
|
##
|
||||||
|
## A basic setup for a gallery screen, using Ren'Py's built-in Gallery
|
||||||
|
## system. More information here:
|
||||||
|
## https://www.renpy.org/doc/html/rooms.html#image-gallery
|
||||||
|
##
|
||||||
|
|
||||||
|
init python:
|
||||||
|
|
||||||
|
## First, some constants to speed up declarations
|
||||||
|
|
||||||
|
## The size of gallery buttons/thumbnails
|
||||||
|
gallery_thumb_size = (400, 225)
|
||||||
|
## For convenience's sake: list off all the gallery image
|
||||||
|
## names we're going to use in this gallery
|
||||||
|
gallery_buttons = [
|
||||||
|
'xia_cg_1', 'ashwin_cg_1', 'zoran_cg_1'
|
||||||
|
]
|
||||||
|
|
||||||
|
## Set up the gallery
|
||||||
|
g = Gallery()
|
||||||
|
g.locked_button = Transform("#333", xysize=gallery_thumb_size)
|
||||||
|
|
||||||
|
## And declare the various gallery images
|
||||||
|
## This file doesn't assume the presence of any GUI files, so I'm
|
||||||
|
## just using basic squares, declared as images below, but you will
|
||||||
|
## replace these with actual images.
|
||||||
|
## These use the names declared in the gallery_buttons list
|
||||||
|
g.button("xia_cg_1")
|
||||||
|
g.unlock_image("cg xia1")
|
||||||
|
|
||||||
|
g.button("ashwin_cg_1")
|
||||||
|
g.unlock_image("cg ashwin1")
|
||||||
|
|
||||||
|
g.button("zoran_cg_1")
|
||||||
|
g.unlock_image("cg zoran1")
|
||||||
|
|
||||||
|
## Declarations for the images used in the gallery. May or may not
|
||||||
|
## be needed if you're using Ren'Py's automatic image names.
|
||||||
|
image cg xia1 = Transform("#bd580a", xysize=(config.screen_width, config.screen_height))
|
||||||
|
image cg ashwin1 = Transform("#127151", xysize=(config.screen_width, config.screen_height))
|
||||||
|
image cg zoran1 = Transform("#8157b9", xysize=(config.screen_width, config.screen_height))
|
||||||
|
|
||||||
|
## This is just the button name + _thumb to make it easier to iterate
|
||||||
|
image xia_cg_1_thumb = Transform("#bd580a", xysize=gallery_thumb_size)
|
||||||
|
image ashwin_cg_1_thumb = Transform("#127151", xysize=gallery_thumb_size)
|
||||||
|
image zoran_cg_1_thumb = Transform("#8157b9", xysize=gallery_thumb_size)
|
||||||
|
|
||||||
|
screen gallery():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use game_menu(_("Gallery"))
|
||||||
|
|
||||||
|
|
||||||
|
fixed:
|
||||||
|
style_prefix 'gal'
|
||||||
|
## Organize the gallery images into a grid
|
||||||
|
grid 2 2:
|
||||||
|
for btn in gallery_buttons:
|
||||||
|
add g.make_button(btn, "{}_thumb".format(btn))
|
||||||
|
## If you're not using the loop, this will look instead like:
|
||||||
|
# add g.make_button("button_name", "button_thumbnail.png")
|
||||||
|
|
||||||
|
style gal_fixed:
|
||||||
|
yfill True
|
||||||
|
xsize config.screen_width-420
|
||||||
|
align (1.0, 0.5)
|
||||||
|
|
||||||
|
style gal_grid:
|
||||||
|
align (0.5, 0.5)
|
||||||
|
xsize config.screen_width-420
|
||||||
|
ysize config.screen_height-200
|
||||||
|
spacing 50
|
|
@ -0,0 +1,62 @@
|
||||||
|
## Mobile Input ################################################################
|
||||||
|
##
|
||||||
|
## This is a custom InputValue which does not begin as selected/ready for
|
||||||
|
## input and requires an action to be enabled. Pressing the Enter button
|
||||||
|
## will disable the input again.
|
||||||
|
##
|
||||||
|
## This makes it a good choice for most custom input screens, particularly
|
||||||
|
## on mobile devices where the keyboard can take up most of the screen space.
|
||||||
|
##
|
||||||
|
## As per usual, this file may be removed without consequence.
|
||||||
|
##
|
||||||
|
## Read more about InputValue here:
|
||||||
|
## https://www.renpy.org/doc/html/screen_python.html#inputvalue
|
||||||
|
##
|
||||||
|
init python:
|
||||||
|
|
||||||
|
class EnterInputValue(FieldInputValue):
|
||||||
|
"""
|
||||||
|
Subclass of InputValue which allows the Enter key to dismiss
|
||||||
|
the input button. Does not begin as selected (so, on mobile the
|
||||||
|
keyboard won't immediately appear).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, object, field, default=False):
|
||||||
|
self.object = object
|
||||||
|
self.field = field
|
||||||
|
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
def enter(self):
|
||||||
|
"""Disable this input when the user presses Enter."""
|
||||||
|
renpy.run(self.Disable())
|
||||||
|
raise renpy.IgnoreEvent()
|
||||||
|
|
||||||
|
default demo_name = "Feniks"
|
||||||
|
|
||||||
|
## An example screen using EnterInputValue
|
||||||
|
screen name_input_screen():
|
||||||
|
|
||||||
|
## The "object" here is `store` since it's a regular store variable.
|
||||||
|
## If the variable was persistent.name, it would use `persistent` instead.
|
||||||
|
default name_input = EnterInputValue(store, 'demo_name')
|
||||||
|
|
||||||
|
add "#601249bb"
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
align (0.5, 0.5)
|
||||||
|
spacing 25
|
||||||
|
button:
|
||||||
|
background "#000b"
|
||||||
|
hover_background "#0003"
|
||||||
|
# Ensure you can type without needing to hover this button
|
||||||
|
key_events True
|
||||||
|
# Enable the input
|
||||||
|
action name_input.Toggle()
|
||||||
|
has hbox
|
||||||
|
spacing 25
|
||||||
|
text "Name:"
|
||||||
|
# The actual input, which uses the EnterInputValue earlier
|
||||||
|
input value name_input
|
||||||
|
|
||||||
|
textbutton "Done" action Return() xalign 0.5
|
|
@ -0,0 +1,21 @@
|
||||||
|
## Special Labels ##############################################################
|
||||||
|
##
|
||||||
|
## These are special labels that Ren'Py automatically recognizes if they
|
||||||
|
## are included with the game. Read more here:
|
||||||
|
## https://www.renpy.org/doc/html/label.html#special-labels
|
||||||
|
##
|
||||||
|
|
||||||
|
## Splash Screen ###############################################################
|
||||||
|
##
|
||||||
|
## Put the splash screen code here. It runs when the game is launched.
|
||||||
|
##
|
||||||
|
label splashscreen():
|
||||||
|
return
|
||||||
|
|
||||||
|
## After Load ##################################################################
|
||||||
|
##
|
||||||
|
## Adjust any variables etc in the after_load label
|
||||||
|
## Also consider: define config.after_load_callbacks = [ ... ]
|
||||||
|
##
|
||||||
|
label after_load():
|
||||||
|
return
|
|
@ -0,0 +1,243 @@
|
||||||
|
## This file contains options that can be changed to customize your game.
|
||||||
|
##
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## TODO: Change these top three values (config.name, build.name,
|
||||||
|
## and config.save_directory) to something unique for your project!
|
||||||
|
|
||||||
|
## Basics ######################################################################
|
||||||
|
|
||||||
|
## A human-readable name of the game. This is used to set the default window
|
||||||
|
## title, and shows up in the interface and error reports.
|
||||||
|
##
|
||||||
|
## The _() surrounding the string marks it as eligible for translation.
|
||||||
|
|
||||||
|
define config.name = _("Jam13Yuuka")
|
||||||
|
|
||||||
|
## A short name for the game used for executables and directories in the built
|
||||||
|
## distribution. This must be ASCII-only, and must not contain spaces, colons,
|
||||||
|
## or semicolons.
|
||||||
|
|
||||||
|
define build.name = "Jam13Yuuka"
|
||||||
|
|
||||||
|
## Save directory ##############################################################
|
||||||
|
##
|
||||||
|
## Controls the platform-specific place Ren'Py will place the save files for
|
||||||
|
## this game. The save files will be placed in:
|
||||||
|
##
|
||||||
|
## Windows: %APPDATA\RenPy\<config.save_directory>
|
||||||
|
##
|
||||||
|
## Macintosh: $HOME/Library/RenPy/<config.save_directory>
|
||||||
|
##
|
||||||
|
## Linux: $HOME/.renpy/<config.save_directory>
|
||||||
|
##
|
||||||
|
## This generally should not be changed, and if it is, should always be a
|
||||||
|
## literal string, not an expression.
|
||||||
|
|
||||||
|
## Note: a typical save_directory value looks like "FreshProject-1671818013"
|
||||||
|
define config.save_directory = "Jam13Yuuka-1256128491"
|
||||||
|
|
||||||
|
|
||||||
|
## The version of the game.
|
||||||
|
|
||||||
|
define config.version = "1.0"
|
||||||
|
|
||||||
|
## Text that is placed on the game's about screen. Place the text between the
|
||||||
|
## triple-quotes, and leave a blank line between paragraphs.
|
||||||
|
|
||||||
|
define gui.about = _p("""A game created in 3 days for Touhou Fan Game Jam 13.
|
||||||
|
|
||||||
|
By Jacoder23, Shyraku, Nanossis, and hermit_irl.""")
|
||||||
|
|
||||||
|
# TODO: REPLACE THE ABOUT WITH NEW CREDITS WHEN POSSIBLE
|
||||||
|
|
||||||
|
## Sounds and music ############################################################
|
||||||
|
|
||||||
|
## These three variables control, among other things, which mixers are shown
|
||||||
|
## to the player by default. Setting one of these to False will hide the
|
||||||
|
## appropriate mixer.
|
||||||
|
|
||||||
|
define config.has_sound = True
|
||||||
|
define config.has_music = True
|
||||||
|
define config.has_voice = True
|
||||||
|
|
||||||
|
|
||||||
|
## To allow the user to play a test sound on the sound or voice channel,
|
||||||
|
## uncomment a line below and use it to set a sample sound to play.
|
||||||
|
|
||||||
|
# define config.sample_sound = "sample-sound.ogg"
|
||||||
|
# define config.sample_voice = "sample-voice.ogg"
|
||||||
|
|
||||||
|
|
||||||
|
## Uncomment the following line to set an audio file that will be played while
|
||||||
|
## the player is at the main menu. This file will continue playing into the
|
||||||
|
## game, until it is stopped or another file is played.
|
||||||
|
|
||||||
|
# define config.main_menu_music = "main-menu-theme.ogg"
|
||||||
|
|
||||||
|
|
||||||
|
## Transitions #################################################################
|
||||||
|
##
|
||||||
|
## These variables set transitions that are used when certain events occur.
|
||||||
|
## Each variable should be set to a transition, or None to indicate that no
|
||||||
|
## transition should be used.
|
||||||
|
|
||||||
|
## Entering or exiting the game menu.
|
||||||
|
|
||||||
|
define config.enter_transition = dissolve
|
||||||
|
define config.exit_transition = dissolve
|
||||||
|
|
||||||
|
|
||||||
|
## Between screens of the game menu.
|
||||||
|
|
||||||
|
define config.intra_transition = dissolve
|
||||||
|
|
||||||
|
|
||||||
|
## A transition that is used after a game has been loaded.
|
||||||
|
|
||||||
|
define config.after_load_transition = None
|
||||||
|
|
||||||
|
|
||||||
|
## Used when entering the main menu after the game has ended.
|
||||||
|
|
||||||
|
define config.end_game_transition = None
|
||||||
|
|
||||||
|
## Window management ###########################################################
|
||||||
|
##
|
||||||
|
## This controls when the dialogue window is displayed. If "show", it is always
|
||||||
|
## displayed. If "hide", it is only displayed when dialogue is present. If
|
||||||
|
## "auto", the window is hidden before scene statements and shown again once
|
||||||
|
## dialogue is displayed.
|
||||||
|
##
|
||||||
|
## After the game has started, this can be changed with the "window show",
|
||||||
|
## "window hide", and "window auto" statements.
|
||||||
|
|
||||||
|
define config.window = "auto"
|
||||||
|
|
||||||
|
|
||||||
|
## Transitions used to show and hide the dialogue window
|
||||||
|
|
||||||
|
define config.window_show_transition = Dissolve(.2)
|
||||||
|
define config.window_hide_transition = Dissolve(.2)
|
||||||
|
|
||||||
|
|
||||||
|
## Preference defaults #########################################################
|
||||||
|
|
||||||
|
## 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 = 40
|
||||||
|
|
||||||
|
|
||||||
|
## The default auto-forward delay. Larger numbers lead to longer waits, with 0
|
||||||
|
## to 30 being the valid range.
|
||||||
|
|
||||||
|
default preferences.afm_time = 15
|
||||||
|
|
||||||
|
## Icon ########################################################################
|
||||||
|
##
|
||||||
|
## The icon displayed on the taskbar or dock.
|
||||||
|
|
||||||
|
define config.window_icon = "gui/window_icon.png"
|
||||||
|
|
||||||
|
## Custom Options ##############################################################
|
||||||
|
##
|
||||||
|
## Config variables that I like to have set up.
|
||||||
|
|
||||||
|
## Convenience for not crashing on grids without enough items
|
||||||
|
## https://www.renpy.org/doc/html/config.html#var-config.allow_underfull_grids
|
||||||
|
## In modern Ren'Py, this is already the default.
|
||||||
|
define config.allow_underfull_grids = True
|
||||||
|
|
||||||
|
## Default volume % for the various volume sliders
|
||||||
|
## https://www.renpy.org/doc/html/preferences.html#audio-channel-defaults
|
||||||
|
define config.default_music_volume = 0.5
|
||||||
|
define config.default_sfx_volume = 0.5
|
||||||
|
define config.default_voice_volume = 0.5
|
||||||
|
|
||||||
|
## Optional; this reverts the behaviour of the volume sliders back to
|
||||||
|
## pre-8.1, so muting the game shows the volume sliders all at 0
|
||||||
|
# define config.preserve_volume_when_muted = False
|
||||||
|
|
||||||
|
## The number of auto save slots Ren'Py will save to before it
|
||||||
|
## starts overwriting the first one
|
||||||
|
define config.autosave_slots = 6
|
||||||
|
## Same thing, but for quick save
|
||||||
|
define config.quicksave_slots = 6
|
||||||
|
|
||||||
|
## Build configuration #########################################################
|
||||||
|
##
|
||||||
|
## This section controls how Ren'Py turns your project into distribution files.
|
||||||
|
|
||||||
|
init python:
|
||||||
|
|
||||||
|
## The following functions take file patterns. File patterns are case-
|
||||||
|
## insensitive, and matched against the path relative to the base directory,
|
||||||
|
## with and without a leading /. If multiple patterns match, the first is
|
||||||
|
## used.
|
||||||
|
##
|
||||||
|
## In a pattern:
|
||||||
|
##
|
||||||
|
## / is the directory separator.
|
||||||
|
##
|
||||||
|
## * matches all characters, except the directory separator.
|
||||||
|
##
|
||||||
|
## ** matches all characters, including the directory separator.
|
||||||
|
##
|
||||||
|
## For example, "*.txt" matches txt files in the base directory, "game/
|
||||||
|
## **.ogg" matches ogg files in the game directory or any of its
|
||||||
|
## subdirectories, and "**.psd" matches psd files anywhere in the project.
|
||||||
|
|
||||||
|
## Classify files as None to exclude them from the built distributions.
|
||||||
|
|
||||||
|
build.classify('**~', None)
|
||||||
|
build.classify('**.bak', None)
|
||||||
|
build.classify('**/.**', None)
|
||||||
|
build.classify('**/#**', None)
|
||||||
|
build.classify('**/thumbs.db', None)
|
||||||
|
build.classify('**.psd', None)
|
||||||
|
build.classify('game/cache/**', None)
|
||||||
|
## NOTE: This excludes markdown and txt files. If you use these formats
|
||||||
|
## for README or instructions, you may want to remove these lines.
|
||||||
|
build.classify('**.txt', None)
|
||||||
|
build.classify('**.md', None)
|
||||||
|
build.classify('**.rpy', None)
|
||||||
|
|
||||||
|
## To archive files, classify them as 'archive'.
|
||||||
|
|
||||||
|
build.classify("game/**.rpy", "archive")
|
||||||
|
build.classify("game/**.rpym", "archive")
|
||||||
|
|
||||||
|
build.classify("game/**.webp", "archive")
|
||||||
|
build.classify("game/**.webm", "archive")
|
||||||
|
build.classify("game/**.mp4", "archive")
|
||||||
|
build.classify("game/**.png", "archive")
|
||||||
|
build.classify("game/**.jpg", "archive")
|
||||||
|
build.classify("game/**.ttf", "archive")
|
||||||
|
build.classify("game/**.otf", "archive")
|
||||||
|
build.classify("game/**.mp3", "archive")
|
||||||
|
build.classify("game/**.wav", "archive")
|
||||||
|
build.classify("game/**.ogg", "archive")
|
||||||
|
build.classify("game/**.opus", "archive")
|
||||||
|
build.classify("game/**.rpyc", "archive")
|
||||||
|
build.classify("game/**.rpymc", "archive")
|
||||||
|
|
||||||
|
## Files matching documentation patterns are duplicated in a mac app build,
|
||||||
|
## so they appear in both the app and the zip file.
|
||||||
|
|
||||||
|
build.documentation('*.html')
|
||||||
|
build.documentation('*.txt')
|
||||||
|
|
||||||
|
## A Google Play license key is required to perform in-app purchases. It can be
|
||||||
|
## found in the Google Play developer console, under "Monetize" > "Monetization
|
||||||
|
## Setup" > "Licensing".
|
||||||
|
|
||||||
|
# define build.google_play_key = "..."
|
||||||
|
|
||||||
|
|
||||||
|
## The username and project name associated with an itch.io project, separated
|
||||||
|
## by a slash.
|
||||||
|
|
||||||
|
# define build.itch_project = "renpytom/test-project"
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
## Choice screen ###############################################################
|
||||||
|
##
|
||||||
|
## This screen is used to display the in-game choices presented by the menu
|
||||||
|
## statement. The one parameter, items, is a list of objects, each with caption
|
||||||
|
## and action fields.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#choice
|
||||||
|
|
||||||
|
screen choice(items):
|
||||||
|
style_prefix "choice"
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
for i in items:
|
||||||
|
textbutton i.caption action i.action
|
||||||
|
|
||||||
|
|
||||||
|
style choice_vbox:
|
||||||
|
xalign 0.5
|
||||||
|
ypos 405
|
||||||
|
yanchor 0.5
|
||||||
|
spacing 33
|
||||||
|
|
||||||
|
style choice_button:
|
||||||
|
is default # This means it doesn't use the usual button styling
|
||||||
|
xysize (926, None)
|
||||||
|
background Frame("gui/button/choice_[prefix_]background.png",
|
||||||
|
150, 25, 150, 25, tile=False)
|
||||||
|
padding (12, 12)
|
||||||
|
|
||||||
|
style choice_button_text:
|
||||||
|
is default # This means it doesn't use the usual button text styling
|
||||||
|
xalign 0.5 yalign 0.5
|
||||||
|
idle_color "#ccc"
|
||||||
|
hover_color "#fff"
|
||||||
|
insensitive_color "#444"
|
|
@ -0,0 +1,284 @@
|
||||||
|
|
||||||
|
## Say screen ##################################################################
|
||||||
|
##
|
||||||
|
## The say screen is used to display dialogue to the player. It takes two
|
||||||
|
## parameters, who and what, which are the name of the speaking character and
|
||||||
|
## the text to be displayed, respectively. (The who parameter can be None if no
|
||||||
|
## name is given.)
|
||||||
|
##
|
||||||
|
## This screen must create a text displayable with id "what", as Ren'Py uses
|
||||||
|
## this to manage text display. It can also create displayables with id "who"
|
||||||
|
## and id "window" to apply style properties.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#say
|
||||||
|
|
||||||
|
screen say(who, what):
|
||||||
|
style_prefix "say"
|
||||||
|
|
||||||
|
window:
|
||||||
|
id "window"
|
||||||
|
|
||||||
|
if who is not None:
|
||||||
|
|
||||||
|
window:
|
||||||
|
id "namebox"
|
||||||
|
style "namebox"
|
||||||
|
text who id "who"
|
||||||
|
|
||||||
|
text what id "what"
|
||||||
|
|
||||||
|
## If there's a side image, display it in front of the text.
|
||||||
|
add SideImage() xalign 0.0 yalign 1.0
|
||||||
|
|
||||||
|
|
||||||
|
## Make the namebox available for styling through the Character object.
|
||||||
|
init python:
|
||||||
|
config.character_id_prefixes.append('namebox')
|
||||||
|
|
||||||
|
# Style for the dialogue window
|
||||||
|
style window:
|
||||||
|
xalign 0.5
|
||||||
|
yalign 1.0
|
||||||
|
xysize (1231, 277)
|
||||||
|
padding (40, 10, 40, 40)
|
||||||
|
background Image("gui/textbox.png", xalign=0.5, yalign=1.0)
|
||||||
|
|
||||||
|
# Style for the dialogue
|
||||||
|
style say_dialogue:
|
||||||
|
adjust_spacing False
|
||||||
|
ypos 60
|
||||||
|
|
||||||
|
# The style for dialogue said by the narrator
|
||||||
|
style say_thought:
|
||||||
|
is say_dialogue
|
||||||
|
|
||||||
|
# Style for the box containing the speaker's name
|
||||||
|
style namebox:
|
||||||
|
xpos 20
|
||||||
|
xysize (None, None)
|
||||||
|
background Frame("gui/namebox.png", 5, 5, 5, 5, tile=False, xalign=0.0)
|
||||||
|
padding (5, 5, 5, 5)
|
||||||
|
|
||||||
|
# Style for the text with the speaker's name
|
||||||
|
style say_label:
|
||||||
|
color '#f93c3e'
|
||||||
|
xalign 0.0
|
||||||
|
yalign 0.5
|
||||||
|
size gui.name_text_size
|
||||||
|
font gui.name_text_font
|
||||||
|
|
||||||
|
|
||||||
|
## Quick Menu screen ###########################################################
|
||||||
|
##
|
||||||
|
## The quick menu is displayed in-game to provide easy access to the out-of-game
|
||||||
|
## menus.
|
||||||
|
|
||||||
|
screen quick_menu():
|
||||||
|
|
||||||
|
## Ensure this appears on top of other screens.
|
||||||
|
zorder 100
|
||||||
|
|
||||||
|
if quick_menu:
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
style_prefix "quick"
|
||||||
|
|
||||||
|
textbutton _("Back") action Rollback()
|
||||||
|
textbutton _("History") action ShowMenu('history')
|
||||||
|
textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True)
|
||||||
|
textbutton _("Auto") action Preference("auto-forward", "toggle")
|
||||||
|
textbutton _("Save") action ShowMenu('save')
|
||||||
|
textbutton _("Prefs") action ShowMenu('preferences')
|
||||||
|
|
||||||
|
|
||||||
|
## This code ensures that the quick_menu screen is displayed in-game, whenever
|
||||||
|
## the player has not explicitly hidden the interface.
|
||||||
|
init python:
|
||||||
|
config.overlay_screens.append("quick_menu")
|
||||||
|
|
||||||
|
default quick_menu = True
|
||||||
|
|
||||||
|
style quick_hbox:
|
||||||
|
xalign 0.5
|
||||||
|
yalign 1.0 yoffset -8
|
||||||
|
spacing 8
|
||||||
|
|
||||||
|
style quick_button:
|
||||||
|
background None
|
||||||
|
padding (15, 6, 15, 0)
|
||||||
|
|
||||||
|
style quick_button_text:
|
||||||
|
size 21
|
||||||
|
selected_color '#f93c3e'
|
||||||
|
idle_color "#aaa"
|
||||||
|
|
||||||
|
## NVL screen ##################################################################
|
||||||
|
##
|
||||||
|
## This screen is used for NVL-mode dialogue and menus.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#nvl
|
||||||
|
|
||||||
|
|
||||||
|
screen nvl(dialogue, items=None):
|
||||||
|
|
||||||
|
window:
|
||||||
|
style "nvl_window"
|
||||||
|
|
||||||
|
has vbox
|
||||||
|
spacing 15
|
||||||
|
|
||||||
|
use nvl_dialogue(dialogue)
|
||||||
|
|
||||||
|
## Displays the menu, if given. The menu may be displayed incorrectly if
|
||||||
|
## config.narrator_menu is set to True.
|
||||||
|
for i in items:
|
||||||
|
|
||||||
|
textbutton i.caption:
|
||||||
|
action i.action
|
||||||
|
style "nvl_button"
|
||||||
|
|
||||||
|
add SideImage() xalign 0.0 yalign 1.0
|
||||||
|
|
||||||
|
|
||||||
|
screen nvl_dialogue(dialogue):
|
||||||
|
|
||||||
|
for d in dialogue:
|
||||||
|
|
||||||
|
window:
|
||||||
|
id d.window_id
|
||||||
|
|
||||||
|
fixed:
|
||||||
|
yfit True
|
||||||
|
|
||||||
|
if d.who is not None:
|
||||||
|
|
||||||
|
text d.who:
|
||||||
|
id d.who_id
|
||||||
|
|
||||||
|
text d.what:
|
||||||
|
id d.what_id
|
||||||
|
|
||||||
|
|
||||||
|
## This controls the maximum number of NVL-mode entries that can be displayed at
|
||||||
|
## once.
|
||||||
|
define config.nvl_list_length = 6
|
||||||
|
|
||||||
|
# The style for the NVL "textbox"
|
||||||
|
style nvl_window:
|
||||||
|
is default
|
||||||
|
xfill True yfill True
|
||||||
|
background "gui/nvl.png"
|
||||||
|
padding (0, 15, 0, 30)
|
||||||
|
|
||||||
|
# The style for the text of the speaker's name
|
||||||
|
style nvl_label:
|
||||||
|
is say_label
|
||||||
|
xpos 645 xanchor 1.0
|
||||||
|
ypos 0 yanchor 0.0
|
||||||
|
xsize 225
|
||||||
|
min_width 225
|
||||||
|
textalign 1.0
|
||||||
|
|
||||||
|
# The style for dialogue in NVL
|
||||||
|
style nvl_dialogue:
|
||||||
|
is say_dialogue
|
||||||
|
xpos 675
|
||||||
|
ypos 12
|
||||||
|
xsize 885
|
||||||
|
min_width 885
|
||||||
|
|
||||||
|
# The style for dialogue said by the narrator in NVL
|
||||||
|
style nvl_thought:
|
||||||
|
is nvl_dialogue
|
||||||
|
|
||||||
|
style nvl_button:
|
||||||
|
xpos 675
|
||||||
|
xanchor 0.0
|
||||||
|
|
||||||
|
|
||||||
|
## Bubble screen ###############################################################
|
||||||
|
##
|
||||||
|
## The bubble screen is used to display dialogue to the player when using speech
|
||||||
|
## bubbles. The bubble screen takes the same parameters as the say screen, must
|
||||||
|
## create a displayable with the id of "what", and can create displayables with
|
||||||
|
## the "namebox", "who", and "window" ids.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/bubble.html#bubble-screen
|
||||||
|
|
||||||
|
screen bubble(who, what):
|
||||||
|
style_prefix "bubble"
|
||||||
|
|
||||||
|
window:
|
||||||
|
id "window"
|
||||||
|
|
||||||
|
if who is not None:
|
||||||
|
|
||||||
|
window:
|
||||||
|
id "namebox"
|
||||||
|
style "bubble_namebox"
|
||||||
|
|
||||||
|
text who:
|
||||||
|
id "who"
|
||||||
|
|
||||||
|
text what:
|
||||||
|
id "what"
|
||||||
|
|
||||||
|
style bubble_window:
|
||||||
|
is empty
|
||||||
|
xpadding 30
|
||||||
|
top_padding 5
|
||||||
|
bottom_padding 5
|
||||||
|
|
||||||
|
style bubble_namebox:
|
||||||
|
is empty
|
||||||
|
xalign 0.5
|
||||||
|
|
||||||
|
style bubble_who:
|
||||||
|
is default
|
||||||
|
xalign 0.5
|
||||||
|
textalign 0.5
|
||||||
|
color "#000"
|
||||||
|
|
||||||
|
style bubble_what:
|
||||||
|
is default
|
||||||
|
align (0.5, 0.5)
|
||||||
|
text_align 0.5
|
||||||
|
layout "subtitle"
|
||||||
|
color "#000"
|
||||||
|
|
||||||
|
define bubble.frame = Frame("gui/bubble.png", 55, 55, 55, 95)
|
||||||
|
define bubble.thoughtframe = Frame("gui/thoughtbubble.png", 55, 55, 55, 55)
|
||||||
|
|
||||||
|
define bubble.properties = {
|
||||||
|
"bottom_left" : {
|
||||||
|
"window_background" : Transform(bubble.frame, xzoom=1, yzoom=1),
|
||||||
|
"window_bottom_padding" : 27,
|
||||||
|
},
|
||||||
|
|
||||||
|
"bottom_right" : {
|
||||||
|
"window_background" : Transform(bubble.frame, xzoom=-1, yzoom=1),
|
||||||
|
"window_bottom_padding" : 27,
|
||||||
|
},
|
||||||
|
|
||||||
|
"top_left" : {
|
||||||
|
"window_background" : Transform(bubble.frame, xzoom=1, yzoom=-1),
|
||||||
|
"window_top_padding" : 27,
|
||||||
|
},
|
||||||
|
|
||||||
|
"top_right" : {
|
||||||
|
"window_background" : Transform(bubble.frame, xzoom=-1, yzoom=-1),
|
||||||
|
"window_top_padding" : 27,
|
||||||
|
},
|
||||||
|
|
||||||
|
"thought" : {
|
||||||
|
"window_background" : bubble.thoughtframe,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define bubble.expand_area = {
|
||||||
|
"bottom_left" : (0, 0, 0, 22),
|
||||||
|
"bottom_right" : (0, 0, 0, 22),
|
||||||
|
"top_left" : (0, 22, 0, 0),
|
||||||
|
"top_right" : (0, 22, 0, 0),
|
||||||
|
"thought" : (0, 0, 0, 0),
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
## Game Menu screen ############################################################
|
||||||
|
##
|
||||||
|
## This lays out the basic common structure of a game menu screen. It's called
|
||||||
|
## with the screen title, and displays the title and navigation.
|
||||||
|
##
|
||||||
|
## This screen no longer includes a background, and it no longer transcludes
|
||||||
|
## its contents. It is intended to be easily removable from any given menu
|
||||||
|
## screen and thus you are required to do some of the heavy lifting for
|
||||||
|
## setting up containers for the contents of your menu screens.
|
||||||
|
##
|
||||||
|
|
||||||
|
screen game_menu(title):
|
||||||
|
|
||||||
|
style_prefix "game_menu"
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
xpos 60 yalign 0.5
|
||||||
|
spacing 6
|
||||||
|
|
||||||
|
if main_menu:
|
||||||
|
|
||||||
|
textbutton _("Start") action Start()
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
textbutton _("History") action ShowMenu("history")
|
||||||
|
|
||||||
|
textbutton _("Save") action ShowMenu("save")
|
||||||
|
|
||||||
|
textbutton _("Load") action ShowMenu("load")
|
||||||
|
|
||||||
|
textbutton _("Preferences") action ShowMenu("preferences")
|
||||||
|
|
||||||
|
if _in_replay:
|
||||||
|
|
||||||
|
textbutton _("End Replay") action EndReplay(confirm=True)
|
||||||
|
|
||||||
|
elif not main_menu:
|
||||||
|
|
||||||
|
textbutton _("Main Menu") action MainMenu()
|
||||||
|
|
||||||
|
textbutton _("About") action ShowMenu("about")
|
||||||
|
|
||||||
|
if renpy.variant("pc") or (renpy.variant("web") and not renpy.variant("mobile")):
|
||||||
|
|
||||||
|
## Help isn't necessary or relevant to mobile devices.
|
||||||
|
textbutton _("Help") action ShowMenu("help")
|
||||||
|
|
||||||
|
if renpy.variant("pc"):
|
||||||
|
|
||||||
|
## The quit button is banned on iOS and
|
||||||
|
## unnecessary on Android and Web.
|
||||||
|
textbutton _("Quit") action Quit(confirm=not main_menu)
|
||||||
|
|
||||||
|
textbutton _("Return"):
|
||||||
|
style "return_button"
|
||||||
|
action Return()
|
||||||
|
|
||||||
|
## Remove this line if you don't want to show the screen
|
||||||
|
## title text as a label (for example, if it's baked into
|
||||||
|
## the background image.)
|
||||||
|
label title
|
||||||
|
|
||||||
|
if main_menu:
|
||||||
|
key "game_menu" action ShowMenu("main_menu")
|
||||||
|
|
||||||
|
style return_button:
|
||||||
|
xpos 60
|
||||||
|
yalign 1.0
|
||||||
|
yoffset -45
|
||||||
|
|
||||||
|
style game_menu_viewport:
|
||||||
|
xsize config.screen_width-420
|
||||||
|
ysize config.screen_height-200
|
||||||
|
align (0.5, 0.5)
|
||||||
|
|
||||||
|
style game_menu_side:
|
||||||
|
yfill True
|
||||||
|
align (1.0, 0.5)
|
||||||
|
|
||||||
|
style game_menu_vscrollbar:
|
||||||
|
unscrollable "hide"
|
||||||
|
|
||||||
|
style game_menu_label:
|
||||||
|
padding (10, 10)
|
||||||
|
style game_menu_label_text:
|
||||||
|
size 45
|
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
## History screen ##############################################################
|
||||||
|
##
|
||||||
|
## This is a screen that displays the dialogue history to the player. While
|
||||||
|
## there isn't anything special about this screen, it does have to access the
|
||||||
|
## dialogue history stored in _history_list.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/history.html
|
||||||
|
|
||||||
|
define config.history_length = 250
|
||||||
|
|
||||||
|
screen history():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
## Avoid predicting this screen, as it can be very large.
|
||||||
|
predict False
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use game_menu(_("History"))
|
||||||
|
|
||||||
|
viewport:
|
||||||
|
style_prefix 'game_menu'
|
||||||
|
mousewheel True draggable True pagekeys True
|
||||||
|
scrollbars "vertical" yinitial 1.0
|
||||||
|
|
||||||
|
has vbox
|
||||||
|
|
||||||
|
style_prefix "history"
|
||||||
|
|
||||||
|
for h in _history_list:
|
||||||
|
|
||||||
|
frame:
|
||||||
|
has hbox
|
||||||
|
if h.who:
|
||||||
|
label h.who style 'history_name':
|
||||||
|
substitute False
|
||||||
|
## Take the color of the who text
|
||||||
|
## from the Character, if set
|
||||||
|
if "color" in h.who_args:
|
||||||
|
text_color h.who_args["color"]
|
||||||
|
xsize 200 # this number and the null width
|
||||||
|
# number should be the same
|
||||||
|
else:
|
||||||
|
null width 200
|
||||||
|
|
||||||
|
$ what = renpy.filter_text_tags(h.what, allow=gui.history_allow_tags)
|
||||||
|
text what:
|
||||||
|
substitute False
|
||||||
|
|
||||||
|
if not _history_list:
|
||||||
|
label _("The dialogue history is empty.")
|
||||||
|
|
||||||
|
|
||||||
|
## This determines what tags are allowed to be displayed on the history screen.
|
||||||
|
|
||||||
|
define gui.history_allow_tags = { "alt", "noalt", "rt", "rb", "art" }
|
||||||
|
|
||||||
|
|
||||||
|
style history_frame:
|
||||||
|
xsize 1400
|
||||||
|
ysize None
|
||||||
|
background None
|
||||||
|
|
||||||
|
style history_hbox:
|
||||||
|
spacing 20
|
||||||
|
|
||||||
|
style history_vbox:
|
||||||
|
spacing 20
|
||||||
|
|
||||||
|
style history_name:
|
||||||
|
xalign 1.0
|
||||||
|
|
||||||
|
style history_name_text:
|
||||||
|
textalign 1.0
|
||||||
|
align (1.0, 0.0)
|
||||||
|
color '#f93c3e'
|
||||||
|
|
||||||
|
style history_text:
|
||||||
|
textalign 0.0
|
||||||
|
|
||||||
|
style history_label:
|
||||||
|
xfill True
|
||||||
|
|
||||||
|
style history_label_text:
|
||||||
|
xalign 0.5
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
## Input screen ################################################################
|
||||||
|
##
|
||||||
|
## This screen is used to display renpy.input. The prompt parameter is used to
|
||||||
|
## pass a text prompt in.
|
||||||
|
##
|
||||||
|
## This screen must create an input displayable with id "input" to accept the
|
||||||
|
## various input parameters.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#input
|
||||||
|
|
||||||
|
screen input(prompt):
|
||||||
|
style_prefix "input"
|
||||||
|
|
||||||
|
window:
|
||||||
|
# This makes the background the same as the ADV dialogue box
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
xanchor 0.0 ypos 20 spacing 10
|
||||||
|
text prompt style "input_prompt"
|
||||||
|
input id "input"
|
||||||
|
|
||||||
|
style input_prompt:
|
||||||
|
xalign 0.0
|
||||||
|
|
||||||
|
style input:
|
||||||
|
xalign 0.0
|
||||||
|
xmaximum 1116
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
## Main Menu screen ############################################################
|
||||||
|
##
|
||||||
|
## Used to display the main menu when Ren'Py starts.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#main-menu
|
||||||
|
|
||||||
|
## Replace this with your background image, if you like
|
||||||
|
image main_menu_background = HBox(
|
||||||
|
Solid("#292835", xsize=350),
|
||||||
|
Solid("#21212d")
|
||||||
|
)
|
||||||
|
|
||||||
|
screen main_menu():
|
||||||
|
|
||||||
|
## This ensures that any other menu screen is replaced.
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add "main_menu_background"
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
xpos 60
|
||||||
|
yalign 0.5
|
||||||
|
spacing 6
|
||||||
|
|
||||||
|
textbutton _("Start") action Start()
|
||||||
|
|
||||||
|
textbutton _("Load") action ShowMenu("load")
|
||||||
|
|
||||||
|
textbutton _("Preferences") action ShowMenu("preferences")
|
||||||
|
|
||||||
|
textbutton _("About") action ShowMenu("about")
|
||||||
|
|
||||||
|
if renpy.variant("pc") or (renpy.variant("web") and not renpy.variant("mobile")):
|
||||||
|
|
||||||
|
## Help isn't necessary or relevant to mobile devices.
|
||||||
|
textbutton _("Help") action ShowMenu("help")
|
||||||
|
|
||||||
|
if renpy.variant("pc"):
|
||||||
|
|
||||||
|
## The quit button is banned on iOS and unnecessary on Android and
|
||||||
|
## Web.
|
||||||
|
textbutton _("Quit") action Quit(confirm=not main_menu)
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
|
||||||
|
## About screen ################################################################
|
||||||
|
##
|
||||||
|
## This screen gives credit and copyright information about the game and Ren'Py.
|
||||||
|
##
|
||||||
|
## There's nothing special about this screen, and hence it also serves as an
|
||||||
|
## example of how to make a custom screen.
|
||||||
|
|
||||||
|
## Text that is placed on the game's about screen. Place the text between the
|
||||||
|
## triple-quotes, and leave a blank line between paragraphs.
|
||||||
|
|
||||||
|
define gui.about = _p("""
|
||||||
|
EasyRenPyGui is made by {a=https://github.com/shawna-p}Feniks{/a} {a=https://feniksdev.com/}@feniksdev.com{/a}
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
screen about():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add "#21212db2" # The background; can be whatever
|
||||||
|
|
||||||
|
use game_menu(_("About"))
|
||||||
|
|
||||||
|
viewport:
|
||||||
|
style_prefix 'game_menu'
|
||||||
|
mousewheel True draggable True pagekeys True
|
||||||
|
scrollbars "vertical"
|
||||||
|
|
||||||
|
has vbox
|
||||||
|
style_prefix "about"
|
||||||
|
|
||||||
|
label "[config.name!t]"
|
||||||
|
text _("Version [config.version!t]\n")
|
||||||
|
|
||||||
|
if gui.about:
|
||||||
|
text "[gui.about!t]\n"
|
||||||
|
|
||||||
|
text _("Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]")
|
||||||
|
|
||||||
|
|
||||||
|
style about_label_text:
|
||||||
|
size 36
|
||||||
|
|
||||||
|
|
||||||
|
## Help screen #################################################################
|
||||||
|
##
|
||||||
|
## A screen that gives information about key and mouse bindings. It uses other
|
||||||
|
## screens (keyboard_help, mouse_help, and gamepad_help) to display the actual
|
||||||
|
## help.
|
||||||
|
|
||||||
|
screen help():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
default device = "keyboard"
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use game_menu(_("Help"))
|
||||||
|
|
||||||
|
viewport:
|
||||||
|
style_prefix 'game_menu'
|
||||||
|
mousewheel True draggable True pagekeys True
|
||||||
|
scrollbars "vertical"
|
||||||
|
|
||||||
|
has vbox
|
||||||
|
style_prefix "help"
|
||||||
|
spacing 23
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
|
||||||
|
textbutton _("Keyboard") action SetScreenVariable("device", "keyboard")
|
||||||
|
textbutton _("Mouse") action SetScreenVariable("device", "mouse")
|
||||||
|
|
||||||
|
if GamepadExists():
|
||||||
|
textbutton _("Gamepad") action SetScreenVariable("device", "gamepad")
|
||||||
|
|
||||||
|
if device == "keyboard":
|
||||||
|
use keyboard_help
|
||||||
|
elif device == "mouse":
|
||||||
|
use mouse_help
|
||||||
|
elif device == "gamepad":
|
||||||
|
use gamepad_help
|
||||||
|
|
||||||
|
|
||||||
|
screen keyboard_help():
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Enter")
|
||||||
|
text _("Advances dialogue and activates the interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Space")
|
||||||
|
text _("Advances dialogue without selecting choices.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Arrow Keys")
|
||||||
|
text _("Navigate the interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Escape")
|
||||||
|
text _("Accesses the game menu.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Ctrl")
|
||||||
|
text _("Skips dialogue while held down.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Tab")
|
||||||
|
text _("Toggles dialogue skipping.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Page Up")
|
||||||
|
text _("Rolls back to earlier dialogue.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Page Down")
|
||||||
|
text _("Rolls forward to later dialogue.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label "H"
|
||||||
|
text _("Hides the user interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label "S"
|
||||||
|
text _("Takes a screenshot.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label "V"
|
||||||
|
text _("Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label "Shift+A"
|
||||||
|
text _("Opens the accessibility menu.")
|
||||||
|
|
||||||
|
|
||||||
|
screen mouse_help():
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Left Click")
|
||||||
|
text _("Advances dialogue and activates the interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Middle Click")
|
||||||
|
text _("Hides the user interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Right Click")
|
||||||
|
text _("Accesses the game menu.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Mouse Wheel Up\nClick Rollback Side")
|
||||||
|
text _("Rolls back to earlier dialogue.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Mouse Wheel Down")
|
||||||
|
text _("Rolls forward to later dialogue.")
|
||||||
|
|
||||||
|
|
||||||
|
screen gamepad_help():
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Right Trigger\nA/Bottom Button")
|
||||||
|
text _("Advances dialogue and activates the interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Left Trigger\nLeft Shoulder")
|
||||||
|
text _("Rolls back to earlier dialogue.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Right Shoulder")
|
||||||
|
text _("Rolls forward to later dialogue.")
|
||||||
|
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("D-Pad, Sticks")
|
||||||
|
text _("Navigate the interface.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Start, Guide, B/Right Button")
|
||||||
|
text _("Accesses the game menu.")
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
label _("Y/Top Button")
|
||||||
|
text _("Hides the user interface.")
|
||||||
|
|
||||||
|
textbutton _("Calibrate") action GamepadCalibrate()
|
||||||
|
|
||||||
|
|
||||||
|
style help_button:
|
||||||
|
xmargin 12
|
||||||
|
|
||||||
|
style help_label:
|
||||||
|
xsize 375
|
||||||
|
right_padding 30
|
||||||
|
|
||||||
|
style help_label_text:
|
||||||
|
xalign 1.0
|
||||||
|
textalign 1.0
|
|
@ -0,0 +1,157 @@
|
||||||
|
|
||||||
|
## Confirm screen ##############################################################
|
||||||
|
##
|
||||||
|
## The confirm screen is called when Ren'Py wants to ask the player a yes or no
|
||||||
|
## question.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#confirm
|
||||||
|
|
||||||
|
screen confirm(message, yes_action, no_action=None):
|
||||||
|
|
||||||
|
## Ensure other screens do not get input while this screen is displayed.
|
||||||
|
modal True
|
||||||
|
|
||||||
|
zorder 200
|
||||||
|
|
||||||
|
style_prefix "confirm"
|
||||||
|
|
||||||
|
add "#0008" # You can replace this with your own overlay image
|
||||||
|
|
||||||
|
frame:
|
||||||
|
has vbox
|
||||||
|
|
||||||
|
label _(message) style "confirm_prompt"
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
|
||||||
|
textbutton _("Confirm") action yes_action
|
||||||
|
# Modified so you can just have a confirmation prompt
|
||||||
|
if no_action is not None:
|
||||||
|
textbutton _("Cancel") action no_action
|
||||||
|
|
||||||
|
## Right-click and escape answer "no".
|
||||||
|
if no_action is not None:
|
||||||
|
key "game_menu" action no_action
|
||||||
|
else:
|
||||||
|
key "game_menu" action yes_action
|
||||||
|
|
||||||
|
style confirm_frame:
|
||||||
|
background Frame("gui/frame.png", 60, 60, 60, 60, tile=False)
|
||||||
|
padding (60, 60, 60, 60)
|
||||||
|
xalign 0.5
|
||||||
|
yalign 0.5
|
||||||
|
|
||||||
|
style confirm_vbox:
|
||||||
|
align (0.5, 0.5)
|
||||||
|
spacing 45
|
||||||
|
|
||||||
|
style confirm_prompt:
|
||||||
|
xalign 0.5
|
||||||
|
|
||||||
|
style confirm_prompt_text:
|
||||||
|
textalign 0.5
|
||||||
|
align (0.5, 0.5)
|
||||||
|
layout "subtitle"
|
||||||
|
|
||||||
|
style confirm_hbox:
|
||||||
|
xalign 0.5
|
||||||
|
spacing 150
|
||||||
|
|
||||||
|
style confirm_button:
|
||||||
|
xalign 0.5
|
||||||
|
|
||||||
|
style confirm_button_text:
|
||||||
|
textalign 0.5
|
||||||
|
|
||||||
|
|
||||||
|
## Skip indicator screen #######################################################
|
||||||
|
##
|
||||||
|
## The skip_indicator screen is displayed to indicate that skipping is in
|
||||||
|
## progress.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#skip-indicator
|
||||||
|
|
||||||
|
screen skip_indicator():
|
||||||
|
|
||||||
|
zorder 100
|
||||||
|
style_prefix "skip"
|
||||||
|
|
||||||
|
frame:
|
||||||
|
has hbox
|
||||||
|
|
||||||
|
text _("Skipping")
|
||||||
|
|
||||||
|
text "▸" at delayed_blink(0.0, 1.0) style "skip_triangle"
|
||||||
|
text "▸" at delayed_blink(0.2, 1.0) style "skip_triangle"
|
||||||
|
text "▸" at delayed_blink(0.4, 1.0) style "skip_triangle"
|
||||||
|
|
||||||
|
|
||||||
|
## This transform is used to blink the arrows one after another.
|
||||||
|
transform delayed_blink(delay, cycle):
|
||||||
|
alpha .5
|
||||||
|
|
||||||
|
pause delay
|
||||||
|
|
||||||
|
block:
|
||||||
|
linear .2 alpha 1.0
|
||||||
|
pause .2
|
||||||
|
linear .2 alpha 0.5
|
||||||
|
pause (cycle - .4)
|
||||||
|
repeat
|
||||||
|
|
||||||
|
style skip_hbox:
|
||||||
|
spacing 9
|
||||||
|
|
||||||
|
style skip_frame:
|
||||||
|
is empty
|
||||||
|
ypos 15
|
||||||
|
background Frame("gui/skip.png", 24, 8, 75, 8, tile=False)
|
||||||
|
padding (24, 8, 75, 8)
|
||||||
|
|
||||||
|
style skip_text:
|
||||||
|
size 24
|
||||||
|
|
||||||
|
style skip_triangle:
|
||||||
|
is skip_text
|
||||||
|
## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE
|
||||||
|
## glyph in it.
|
||||||
|
font "DejaVuSans.ttf"
|
||||||
|
|
||||||
|
## Notify screen ###############################################################
|
||||||
|
##
|
||||||
|
## The notify screen is used to show the player a message. (For example, when
|
||||||
|
## the game is quicksaved or a screenshot has been taken.)
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#notify-screen
|
||||||
|
|
||||||
|
screen notify(message):
|
||||||
|
|
||||||
|
zorder 100
|
||||||
|
style_prefix "notify"
|
||||||
|
|
||||||
|
frame at notify_appear:
|
||||||
|
text "[message!tq]"
|
||||||
|
|
||||||
|
timer 3.25 action Hide('notify')
|
||||||
|
|
||||||
|
|
||||||
|
transform notify_appear:
|
||||||
|
on show:
|
||||||
|
alpha 0
|
||||||
|
linear .25 alpha 1.0
|
||||||
|
on hide:
|
||||||
|
linear .5 alpha 0.0
|
||||||
|
|
||||||
|
|
||||||
|
style notify_frame:
|
||||||
|
is empty
|
||||||
|
ypos 68
|
||||||
|
|
||||||
|
background Frame("gui/notify.png", 24, 8, 60, 8, tile=False)
|
||||||
|
padding (24, 8, 60, 8)
|
||||||
|
|
||||||
|
style notify_text:
|
||||||
|
size 24
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
|
||||||
|
## Preferences screen ##########################################################
|
||||||
|
##
|
||||||
|
## The preferences screen allows the player to configure the game to better suit
|
||||||
|
## themselves.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#preferences
|
||||||
|
|
||||||
|
screen preferences():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use game_menu(_("Preferences"))
|
||||||
|
|
||||||
|
viewport:
|
||||||
|
style_prefix 'game_menu'
|
||||||
|
mousewheel True draggable True pagekeys True
|
||||||
|
scrollbars "vertical"
|
||||||
|
has vbox
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
box_wrap True
|
||||||
|
|
||||||
|
if renpy.variant("pc") or renpy.variant("web"):
|
||||||
|
# Only need fullscreen/windowed on desktop and web builds
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
style_prefix "radio"
|
||||||
|
label _("Display")
|
||||||
|
textbutton _("Window"):
|
||||||
|
# Ensures this button is selected when
|
||||||
|
# not in fullscreen.
|
||||||
|
selected not preferences.fullscreen
|
||||||
|
action Preference("display", "window")
|
||||||
|
textbutton _("Fullscreen"):
|
||||||
|
action Preference("display", "fullscreen")
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
style_prefix "check"
|
||||||
|
label _("Skip")
|
||||||
|
textbutton _("Unseen Text"):
|
||||||
|
action Preference("skip", "toggle")
|
||||||
|
textbutton _("After Choices"):
|
||||||
|
action Preference("after choices", "toggle")
|
||||||
|
textbutton _("Transitions"):
|
||||||
|
action InvertSelected(Preference("transitions", "toggle"))
|
||||||
|
|
||||||
|
## Additional vboxes of type "radio_pref" or "check_pref" can be
|
||||||
|
## added here, to add additional creator-defined preferences.
|
||||||
|
|
||||||
|
null height 60
|
||||||
|
|
||||||
|
hbox:
|
||||||
|
style_prefix "slider"
|
||||||
|
box_wrap True
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
|
||||||
|
label _("Text Speed")
|
||||||
|
bar value Preference("text speed")
|
||||||
|
|
||||||
|
label _("Auto-Forward Time")
|
||||||
|
bar value Preference("auto-forward time")
|
||||||
|
|
||||||
|
vbox:
|
||||||
|
|
||||||
|
if config.has_music:
|
||||||
|
label _("Music Volume")
|
||||||
|
hbox:
|
||||||
|
bar value Preference("music volume")
|
||||||
|
|
||||||
|
if config.has_sound:
|
||||||
|
label _("Sound Volume")
|
||||||
|
hbox:
|
||||||
|
bar value Preference("sound volume")
|
||||||
|
if config.sample_sound:
|
||||||
|
textbutton _("Test") action Play("sound", config.sample_sound)
|
||||||
|
|
||||||
|
|
||||||
|
if config.has_voice:
|
||||||
|
label _("Voice Volume")
|
||||||
|
hbox:
|
||||||
|
bar value Preference("voice volume")
|
||||||
|
if config.sample_voice:
|
||||||
|
textbutton _("Test") action Play("voice", config.sample_voice)
|
||||||
|
|
||||||
|
if config.has_music or config.has_sound or config.has_voice:
|
||||||
|
null height 15
|
||||||
|
textbutton _("Mute All"):
|
||||||
|
style_prefix "check"
|
||||||
|
action Preference("all mute", "toggle")
|
||||||
|
|
||||||
|
### PREF
|
||||||
|
style pref_label:
|
||||||
|
top_margin 15
|
||||||
|
bottom_margin 3
|
||||||
|
|
||||||
|
style pref_label_text:
|
||||||
|
yalign 1.0
|
||||||
|
|
||||||
|
style pref_vbox:
|
||||||
|
xsize 338
|
||||||
|
|
||||||
|
## RADIO
|
||||||
|
style radio_label:
|
||||||
|
is pref_label
|
||||||
|
|
||||||
|
style radio_label_text:
|
||||||
|
is pref_label_text
|
||||||
|
|
||||||
|
style radio_vbox:
|
||||||
|
is pref_vbox
|
||||||
|
spacing 0
|
||||||
|
|
||||||
|
style radio_button:
|
||||||
|
foreground "gui/button/radio_[prefix_]foreground.png"
|
||||||
|
padding (35, 6, 6, 6)
|
||||||
|
|
||||||
|
## CHECK
|
||||||
|
style check_label:
|
||||||
|
is pref_label
|
||||||
|
style check_label_text:
|
||||||
|
is pref_label_text
|
||||||
|
|
||||||
|
style check_vbox:
|
||||||
|
is pref_vbox
|
||||||
|
spacing 0
|
||||||
|
|
||||||
|
style check_button:
|
||||||
|
foreground "gui/button/check_[prefix_]foreground.png"
|
||||||
|
padding (35, 6, 6, 6)
|
||||||
|
|
||||||
|
## SLIDER
|
||||||
|
style slider_label:
|
||||||
|
is pref_label
|
||||||
|
style slider_label_text:
|
||||||
|
is pref_label_text
|
||||||
|
|
||||||
|
style slider_slider:
|
||||||
|
xsize 525
|
||||||
|
|
||||||
|
style slider_button:
|
||||||
|
yalign 0.5
|
||||||
|
left_margin 15
|
||||||
|
|
||||||
|
style slider_vbox:
|
||||||
|
is pref_vbox
|
||||||
|
xsize 675
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
## Load and Save screens #######################################################
|
||||||
|
##
|
||||||
|
## These screens are responsible for letting the player save the game and load
|
||||||
|
## it again. Since they share nearly everything in common, both are implemented
|
||||||
|
## in terms of a third screen, file_slots.
|
||||||
|
##
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#save
|
||||||
|
## https://www.renpy.org/doc/html/screen_special.html#load
|
||||||
|
|
||||||
|
|
||||||
|
## The width and height of thumbnails used by the save slots.
|
||||||
|
define config.thumbnail_width = 384
|
||||||
|
define config.thumbnail_height = 216
|
||||||
|
|
||||||
|
|
||||||
|
screen save():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use file_slots(_("Save"))
|
||||||
|
|
||||||
|
|
||||||
|
screen load():
|
||||||
|
|
||||||
|
tag menu
|
||||||
|
|
||||||
|
add HBox(Transform("#292835", xsize=350), "#21212db2") # The background; can be whatever
|
||||||
|
|
||||||
|
use file_slots(_("Load"))
|
||||||
|
|
||||||
|
|
||||||
|
screen file_slots(title):
|
||||||
|
|
||||||
|
default page_name_value = FilePageNameInputValue(
|
||||||
|
pattern=_("Page {}"), auto=_("Automatic saves"),
|
||||||
|
quick=_("Quick saves"))
|
||||||
|
|
||||||
|
use game_menu(title)
|
||||||
|
|
||||||
|
fixed:
|
||||||
|
xsize 1500 xalign 1.0
|
||||||
|
## This ensures the input will get the enter event before any of the
|
||||||
|
## buttons do.
|
||||||
|
order_reverse True
|
||||||
|
|
||||||
|
## The page name, which can be edited by clicking on it.
|
||||||
|
## This can be pretty easily removed if you want.
|
||||||
|
## Don't forget to also remove the `default` at the top if so.
|
||||||
|
button:
|
||||||
|
style "page_label"
|
||||||
|
key_events True
|
||||||
|
action page_name_value.Toggle()
|
||||||
|
|
||||||
|
input:
|
||||||
|
style "page_label_text"
|
||||||
|
value page_name_value
|
||||||
|
|
||||||
|
## The grid of file slots.
|
||||||
|
grid 3 2:
|
||||||
|
style_prefix "slot"
|
||||||
|
|
||||||
|
for i in range(3*2):
|
||||||
|
$ slot = i + 1
|
||||||
|
|
||||||
|
button:
|
||||||
|
action FileAction(slot)
|
||||||
|
has vbox
|
||||||
|
|
||||||
|
add FileScreenshot(slot) xalign 0.5
|
||||||
|
|
||||||
|
## https://www.fabriziomusacchio.com/blog/2021-08-15-strftime_Cheat_Sheet/
|
||||||
|
text FileTime(slot,
|
||||||
|
format=_("{#file_time}%A, %B %d %Y, %H:%M"),
|
||||||
|
empty=_("empty slot")):
|
||||||
|
style "slot_time_text"
|
||||||
|
|
||||||
|
text FileSaveName(slot) style "slot_name_text"
|
||||||
|
|
||||||
|
# This means the player can hover this save
|
||||||
|
# slot and hit delete to delete it
|
||||||
|
key "save_delete" action FileDelete(slot)
|
||||||
|
|
||||||
|
## Buttons to access other pages.
|
||||||
|
vbox:
|
||||||
|
style_prefix "page"
|
||||||
|
hbox:
|
||||||
|
textbutton _("<") action FilePagePrevious()
|
||||||
|
|
||||||
|
if config.has_autosave:
|
||||||
|
textbutton _("{#auto_page}A") action FilePage("auto")
|
||||||
|
|
||||||
|
if config.has_quicksave:
|
||||||
|
textbutton _("{#quick_page}Q") action FilePage("quick")
|
||||||
|
|
||||||
|
## range(1, 10) gives the numbers from 1 to 9.
|
||||||
|
for page in range(1, 10):
|
||||||
|
textbutton "[page]" action FilePage(page)
|
||||||
|
|
||||||
|
textbutton _(">") action FilePageNext()
|
||||||
|
|
||||||
|
if config.has_sync:
|
||||||
|
if CurrentScreenName() == "save":
|
||||||
|
textbutton _("Upload Sync"):
|
||||||
|
action UploadSync()
|
||||||
|
else:
|
||||||
|
textbutton _("Download Sync"):
|
||||||
|
action DownloadSync()
|
||||||
|
|
||||||
|
|
||||||
|
style page_label:
|
||||||
|
xpadding 75
|
||||||
|
ypadding 5
|
||||||
|
xalign 0.5
|
||||||
|
|
||||||
|
style page_label_text:
|
||||||
|
textalign 0.5
|
||||||
|
layout "subtitle"
|
||||||
|
hover_color '#ff8335'
|
||||||
|
|
||||||
|
style slot_grid:
|
||||||
|
xalign 0.5
|
||||||
|
yalign 0.5
|
||||||
|
spacing 15
|
||||||
|
|
||||||
|
style slot_time_text:
|
||||||
|
size 25
|
||||||
|
xalign 0.5
|
||||||
|
|
||||||
|
style slot_vbox:
|
||||||
|
spacing 12
|
||||||
|
|
||||||
|
style slot_button:
|
||||||
|
xysize (414, 309)
|
||||||
|
padding (15, 15, 15, 15)
|
||||||
|
background "gui/button/slot_[prefix_]background.png"
|
||||||
|
|
||||||
|
style slot_button_text:
|
||||||
|
size 21
|
||||||
|
xalign 0.5
|
||||||
|
idle_color '#aaaaaa'
|
||||||
|
hover_color '#ff8335'
|
||||||
|
selected_idle_color '#ffffff'
|
||||||
|
|
||||||
|
style page_hbox:
|
||||||
|
xalign 0.5
|
||||||
|
spacing 5
|
||||||
|
|
||||||
|
style page_vbox:
|
||||||
|
xalign 0.5
|
||||||
|
yalign 1.0
|
||||||
|
spacing 5
|
||||||
|
|
||||||
|
style page_button:
|
||||||
|
padding (15, 6, 15, 6)
|
||||||
|
xalign 0.5
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
define yuuka = Character("Yuuka", callback = name_callback, cb_name = "yuuka")
|
||||||
|
define reimu = Character("Reimu", callback = name_callback, cb_name = "reimu")
|
||||||
|
define marisa = Character("Marisa", callback = name_callback, cb_name = "marisa")
|
||||||
|
define alice = Character("Alice", callback = name_callback, cb_name = "alice")
|
||||||
|
define yumemi = Character("Yumemi", callback = name_callback, cb_name = "yumemi")
|
||||||
|
define narrator = Character(callback = name_callback, cb_name = None)
|
||||||
|
|
||||||
|
image yuuka:
|
||||||
|
"yuuka.png"
|
||||||
|
function SpriteFocus('yuuka')
|
||||||
|
|
||||||
|
image yuuka happy:
|
||||||
|
"yuuka happy.png"
|
||||||
|
function SpriteFocus('yuuka')
|
||||||
|
|
||||||
|
image reimu:
|
||||||
|
"reimu.png"
|
||||||
|
function SpriteFocus('reimu')
|
||||||
|
|
||||||
|
image reimu happy:
|
||||||
|
"reimu happy.png"
|
||||||
|
function SpriteFocus('reimu')
|
||||||
|
|
||||||
|
label start:
|
||||||
|
|
||||||
|
scene bg room
|
||||||
|
|
||||||
|
show yuuka happy:
|
||||||
|
xalign 0.2
|
||||||
|
yalign 0.99
|
||||||
|
|
||||||
|
show reimu happy:
|
||||||
|
xalign 0.8
|
||||||
|
yalign 0.99
|
||||||
|
|
||||||
|
yuuka "Good evening."
|
||||||
|
|
||||||
|
yuuka "You all may know me as the substitute this past week for Professor Okazaki."
|
||||||
|
|
||||||
|
yuuka "I've been teaching Botany, a topic on which I am incredibly overqualified for, to idiots younger than you but still very much like you."
|
||||||
|
|
||||||
|
yuuka "But enough of the customary ribbing and teasing, I am here because Professor Okazaki is returning today."
|
||||||
|
|
||||||
|
yuuka "As is stated in the faculty handbook she wrote and doodled over, because clearly not even she could have handwriting THAT horrendous,"
|
||||||
|
|
||||||
|
yuuka "I must give a presentation to report to the faculty and administration exactly what I did as subsitute for Professor Okazaki."
|
||||||
|
|
||||||
|
yuuka "This is that presentation."
|
||||||
|
|
||||||
|
yuuka "You might also be wondering why I've invited select students to attend this presentation."
|
||||||
|
|
||||||
|
yuuka "I will be getting to that, please do not leave your seats through out this presentation. I will be brief."
|
||||||
|
|
||||||
|
return
|
|
@ -0,0 +1,131 @@
|
||||||
|
################################################################################
|
||||||
|
## Initialization
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
## The init offset statement causes the initialization statements in this file
|
||||||
|
## to run before init statements in any other file.
|
||||||
|
init offset = -2
|
||||||
|
|
||||||
|
## Calling gui.init resets the styles to sensible default values, and sets the
|
||||||
|
## width and height of the game.
|
||||||
|
init python:
|
||||||
|
gui.init(1920, 1080)
|
||||||
|
|
||||||
|
define config.check_conflicting_properties = True
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## GUI Configuration Variables
|
||||||
|
################################################################################
|
||||||
|
## Some choice gui values have been left in, to make them
|
||||||
|
## easier to adjust for accessibility purposes e.g. to allow
|
||||||
|
## players to change the default text font or size by rebuilding the gui.
|
||||||
|
## You may add more back if you need to adjust them, or find-and-replace
|
||||||
|
## any instances where they are used directly with their value.
|
||||||
|
|
||||||
|
# The text font for dialogue and choice menus
|
||||||
|
define gui.text_font = gui.preference("font", "DejaVuSans.ttf")
|
||||||
|
# The text font for buttons
|
||||||
|
define gui.interface_text_font = gui.preference("interface_font", "DejaVuSans.ttf")
|
||||||
|
# The default size of in-game text
|
||||||
|
define gui.text_size = gui.preference("size", 33)
|
||||||
|
# The font for character names
|
||||||
|
define gui.name_text_font = gui.preference("name_font", "DejaVuSans.ttf")
|
||||||
|
# The size for character names
|
||||||
|
define gui.name_text_size = gui.preference("name_size", 45)
|
||||||
|
|
||||||
|
## Localization ################################################################
|
||||||
|
|
||||||
|
## This controls where a line break is permitted. The default is suitable
|
||||||
|
## for most languages. A list of available values can be found at
|
||||||
|
## https://www.renpy.org/doc/html/style_properties.html#style-property-language
|
||||||
|
|
||||||
|
define gui.language = "unicode"
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Style Initialization
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
init offset = -1
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Styles
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
style default:
|
||||||
|
font gui.text_font
|
||||||
|
size gui.text_size
|
||||||
|
language gui.language
|
||||||
|
|
||||||
|
style input:
|
||||||
|
adjust_spacing False
|
||||||
|
|
||||||
|
style hyperlink_text:
|
||||||
|
hover_underline True
|
||||||
|
color "#f93c3e"
|
||||||
|
|
||||||
|
style gui_text:
|
||||||
|
color '#ffffff'
|
||||||
|
size gui.text_size
|
||||||
|
font gui.interface_text_font
|
||||||
|
|
||||||
|
style button:
|
||||||
|
xysize (None, None)
|
||||||
|
padding (0, 0)
|
||||||
|
|
||||||
|
style button_text:
|
||||||
|
is gui_text
|
||||||
|
yalign 0.5
|
||||||
|
xalign 0.0
|
||||||
|
## The color used for a text button when it is neither selected nor hovered.
|
||||||
|
idle_color '#888888'
|
||||||
|
## The color that is used for buttons and bars that are hovered.
|
||||||
|
hover_color '#ff8335'
|
||||||
|
## The color used for a text button when it is selected but not focused. A
|
||||||
|
## button is selected if it is the current screen or preference value.
|
||||||
|
selected_color '#ffffff'
|
||||||
|
## The color used for a text button when it cannot be selected.
|
||||||
|
insensitive_color '#8888887f'
|
||||||
|
|
||||||
|
style label_text:
|
||||||
|
is gui_text
|
||||||
|
size 36
|
||||||
|
color '#f93c3e'
|
||||||
|
|
||||||
|
|
||||||
|
style bar:
|
||||||
|
ysize 38
|
||||||
|
left_bar Frame("gui/bar/left.png", 6, 6, 6, 6, tile=False)
|
||||||
|
right_bar Frame("gui/bar/right.png", 6, 6, 6, 6, tile=False)
|
||||||
|
|
||||||
|
style vbar:
|
||||||
|
xsize 38
|
||||||
|
top_bar Frame("gui/bar/top.png", 6, 6, 6, 6, tile=False)
|
||||||
|
bottom_bar Frame("gui/bar/bottom.png", 6, 6, 6, 6, tile=False)
|
||||||
|
|
||||||
|
style scrollbar:
|
||||||
|
ysize 18
|
||||||
|
base_bar Frame("gui/scrollbar/horizontal_[prefix_]bar.png", 6, 6, 6, 6, tile=False)
|
||||||
|
thumb Frame("gui/scrollbar/horizontal_[prefix_]thumb.png", 6, 6, 6, 6, tile=False)
|
||||||
|
unscrollable 'hide'
|
||||||
|
|
||||||
|
style vscrollbar:
|
||||||
|
xsize 18
|
||||||
|
base_bar Frame("gui/scrollbar/vertical_[prefix_]bar.png", 6, 6, 6, 6, tile=False)
|
||||||
|
thumb Frame("gui/scrollbar/vertical_[prefix_]thumb.png", 6, 6, 6, 6, tile=False)
|
||||||
|
unscrollable 'hide'
|
||||||
|
|
||||||
|
style slider:
|
||||||
|
ysize 38
|
||||||
|
base_bar Frame("gui/slider/horizontal_[prefix_]bar.png", 6, 6, 6, 6, tile=False)
|
||||||
|
thumb "gui/slider/horizontal_[prefix_]thumb.png"
|
||||||
|
|
||||||
|
style vslider:
|
||||||
|
xsize 38
|
||||||
|
base_bar Frame("gui/slider/vertical_[prefix_]bar.png", 6, 6, 6, 6, tile=False)
|
||||||
|
thumb "gui/slider/vertical_[prefix_]thumb.png"
|
||||||
|
|
||||||
|
|
||||||
|
style frame:
|
||||||
|
padding (6, 6, 6, 6)
|
||||||
|
background Frame("gui/frame.png", 6, 6, 6, 6, tile=False)
|
|
@ -0,0 +1 @@
|
||||||
|
{ "type" : "template" }
|