<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.summertimesaga.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dogeek</id>
	<title>Summertime Saga Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.summertimesaga.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dogeek"/>
	<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/Special:Contributions/Dogeek"/>
	<updated>2026-06-04T07:20:15Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Summertime_Saga_API&amp;diff=17751</id>
		<title>Summertime Saga API</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Summertime_Saga_API&amp;diff=17751"/>
		<updated>2019-09-28T01:12:19Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* FSMs (Finite State Machines) added dating system docs*/&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Message box important|&lt;br /&gt;
* The API for Summertime Saga is currently under development and this page is subject to changes.&lt;br /&gt;
* This page was last updated as of Summertime Saga version 0.18.0.}}&lt;br /&gt;
The &#039;&#039;Summertime Saga&#039;&#039; development team provides an application programming interface for those who would like to create or modify the game content (modding). In this article you will find documentation on the technical specifications and programming language. Find all the information concerning the modding on [[Modding|its own article]].&lt;br /&gt;
{{TOC right|limit=3}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
{{strong|Finite State Machines}} control the flow of the game for a particular character. They are basically linked chains of events (which are called &#039;&#039;&#039;States&#039;&#039;&#039;). The progress is achieved via a &#039;&#039;&#039;Trigger&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
[[File:Fsm1.png|thumb|600px|left|A basic example of a FSM]]&amp;lt;br clear=left&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
&lt;br /&gt;
Creating a FSM is done in 3 steps:&lt;br /&gt;
&lt;br /&gt;
# Create the states, triggers and a machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
# Link the states together with {{nowrap|&amp;lt;code&amp;gt;State.add(Trigger t, State next_state)&amp;lt;/code&amp;gt;}} method.&lt;br /&gt;
# Add all the states to the machine with {{nowrap|&amp;lt;code&amp;gt;Machine.add(*State states)&amp;lt;/code&amp;gt;}} method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;lt;code&amp;gt;character_fsm_init&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;character&amp;lt;/code&amp;gt; being the character’s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;lt;code&amp;gt;character_machine_init&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;character&amp;lt;/code&amp;gt; being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The machine constructor has plenty of arguments, here is the detail and what is expected:&lt;br /&gt;
&lt;br /&gt;
; name : A name for the machine used as a unique identifier for the machine. It’s also used to find the button dialogue for that machine.&lt;br /&gt;
; default_loc : A 4x7 matrix of locations to be used as the schedule for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it’s assumed that the location only varies by time of day, and the day of the week doesn’t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
; description, states : (to be deprecated) An alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
; vars : A dictionary containing variables (as strings, the keys of that dictionary), and init values for those variables. These variables are used with the state actions and the {{nowrap|&amp;lt;code&amp;gt;get(string variable)&amp;lt;/code&amp;gt;}} and {{nowrap|&amp;lt;code&amp;gt;set(string variable, object value)&amp;lt;/code&amp;gt;}} methods of the machine class. When a specific state doesn’t apply, or you need a variable to change based on the progress with a given path. The {{nowrap|&amp;lt;code&amp;gt;sex speed&amp;lt;/code&amp;gt;}} variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The machine class defines a lot of useful methods:&lt;br /&gt;
&lt;br /&gt;
; set_priority(int priority) : Set the priority of the machine. Currently used to display the hints on the phone. A machine with a &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt; of 1 or more will show up in the phone. This may be used later to sort quests into main quests and side quests.&lt;br /&gt;
; property button_dialogue : Return the button dialogue for that machine ({{nowrap|&amp;lt;code&amp;gt;machine name&amp;lt;/code&amp;gt;}} + &amp;lt;code&amp;gt;_button_dialogue&amp;lt;/code&amp;gt;), used in the [[#TalkTo|TalkTo]] screen action.&lt;br /&gt;
; image, show, say, and hide : Now defunct methods.&lt;br /&gt;
; property progress : Return an integer that is the progress out of a 100%.&lt;br /&gt;
; add_action(*actions) : Add a machine action to this machine.&lt;br /&gt;
; set_state(State state, bool null_delay=False) : Revert the machine to init, then advance the machine until it is in the state &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;null_delay&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, set the delay of the state reached to 0.&lt;br /&gt;
; machine_trigger : Trigger for machine actions.&lt;br /&gt;
; trigger(Trigger trigger, bool noactions=False) : Trigger the machine to pass onto the next state. If &amp;lt;code&amp;gt;noactions&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, don’t process the actions.&lt;br /&gt;
; add(State* states) : Add the states to the machine.&lt;br /&gt;
; get(string var) : Get the machine variable &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt;.&lt;br /&gt;
; set(string var, object value) : Set the machine variable &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt;.&lt;br /&gt;
; get_state() : Return the current state the machine is in.&lt;br /&gt;
; property where : Compute where the machine should be based on her default location, time of day, day of the week, forced location and if it’s forced or not for that time of day. Return a location.&lt;br /&gt;
; is_state(State* states) : Return boolean if the machine is in any of the provided states.&lt;br /&gt;
; between_states(State stateBegin, State* statesEnd) : Return boolean if the machine is between &amp;lt;code&amp;gt;stateBegin&amp;lt;/code&amp;gt; and any of the &amp;lt;code&amp;gt;statesEnd&amp;lt;/code&amp;gt; (non‐inclusive).&lt;br /&gt;
; finished_state(State* states) : Return boolean if the machine has finished any of the states provided.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
You may want to add a delay to state creation by using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are:&lt;br /&gt;
&lt;br /&gt;
; [&#039;set&#039;,&#039;flag_1&#039;] : Set the value of &amp;lt;code&amp;gt;flag_1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;.&lt;br /&gt;
; [&#039;clear&#039;,&#039;flag_1&#039;] : Set the value of &amp;lt;code&amp;gt;flag_1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;.&lt;br /&gt;
; [&#039;toggle&#039;,&#039;flag_1&#039;] : Toggle the value of &amp;lt;code&amp;gt;flag_1&amp;lt;/code&amp;gt; between &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;.&lt;br /&gt;
; [&#039;assign&#039;,[&#039;v1&#039;,100]] : Set the value of &amp;lt;code&amp;gt;v1&amp;lt;/code&amp;gt; to 100.&lt;br /&gt;
; [&#039;inc&#039;,&#039;v1&#039;] : Increase the value of &amp;lt;code&amp;gt;v1&amp;lt;/code&amp;gt; by 1.&lt;br /&gt;
; [&#039;dec&#039;,&#039;v1&#039;] : Decrease the value of &amp;lt;code&amp;gt;v1&amp;lt;/code&amp;gt; by 1.&lt;br /&gt;
; &amp;lt;nowiki&amp;gt;[&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]]&amp;lt;/nowiki&amp;gt; : Set &amp;lt;code&amp;gt;v1 -= 1&amp;lt;/code&amp;gt;, and fire the trigger &amp;lt;code&amp;gt;T_a_trigger&amp;lt;/code&amp;gt; if &amp;lt;code&amp;gt;v1&amp;lt;/code&amp;gt; is less than or equal to 0.&lt;br /&gt;
; [&#039;trigger&#039;,T_a_trigger] : Fire the trigger &amp;lt;code&amp;gt;T_a_trigger&amp;lt;/code&amp;gt;.&lt;br /&gt;
; [&#039;call&#039;,&#039;label&#039;] : Make a Ren’Py call to label. Label MUST return.&lt;br /&gt;
; &amp;lt;nowiki&amp;gt;[&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]]&amp;lt;/nowiki&amp;gt; : Set the forced location for the machine to place (moves the non‐player character).&lt;br /&gt;
: &amp;lt;code&amp;gt;tod&amp;lt;/code&amp;gt; is 1‐indexed (&amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is morning, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; is afternoon, &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; is evening, &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; is night).&lt;br /&gt;
; &amp;lt;nowiki&amp;gt;[&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&amp;lt;/nowiki&amp;gt; : Say if the location is forced at tod or sets force flags according to the 4-list provided.&lt;br /&gt;
; [&#039;unforce&#039;, None/machine] : Reset the locations for machine or the machine specified forced.&lt;br /&gt;
; [&#039;exec&#039;, callable] : Call the callable function or method.&lt;br /&gt;
; [&#039;exec&#039;, [callable, *args]] : Call the callable function or method and pass in the arguments &amp;lt;code&amp;gt;args&amp;lt;/code&amp;gt; specified.&lt;br /&gt;
; [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]] : Execute the actions in &amp;lt;code&amp;gt;actions_list_true&amp;lt;/code&amp;gt; if &amp;lt;code&amp;gt;condition_string&amp;lt;/code&amp;gt; evaluates to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, otherwise executes &amp;lt;code&amp;gt;actions_list_false&amp;lt;/code&amp;gt;. Conditions lists are assumed to be state actions.&lt;br /&gt;
; [&#039;action&#039;, [target_machine, action, target]] : Execute the state action on another machine.&lt;br /&gt;
; &amp;lt;nowiki&amp;gt;[&#039;setdefaultloc&#039;, [[Location, Location, Location, Location]]]&amp;lt;/nowiki&amp;gt; : Set the default locations for the current machine.&lt;br /&gt;
: The argument is in the same format as the &amp;lt;code&amp;gt;default_loc&amp;lt;/code&amp;gt; argument in the machine constructor (1x4, 2x4 or 7x4 matrices).&lt;br /&gt;
; [&#039;setoutfit&#039;, [location, outfit]] : Set the outfit for that location. &amp;lt;code&amp;gt;outfit&amp;lt;/code&amp;gt; may be either a string, or a 1x4, 2x4, 7x4 array of strings (similar to the locations).&lt;br /&gt;
; [&#039;setnaked&#039;, True/False] : Set &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute of the [[#Outfit manager|outfit manager]] to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; for the current machine.&lt;br /&gt;
; &amp;lt;nowiki&amp;gt;[&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]]&amp;lt;/nowiki&amp;gt; : Set the default outfit for the current machine.&lt;br /&gt;
: &amp;lt;code&amp;gt;tod&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dow&amp;lt;/code&amp;gt; can be omitted. &amp;lt;code&amp;gt;outfit&amp;lt;/code&amp;gt; is a required argument in the format of a string or a 1x4, 2x4, 7x4 matrix.&lt;br /&gt;
: If &amp;lt;code&amp;gt;tod&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dow&amp;lt;/code&amp;gt; are omitted, &amp;lt;code&amp;gt;outfit&amp;lt;/code&amp;gt; cannot be a matrix, but only a string. A workaround solution exists by passing the {{nowrap|&amp;lt;code&amp;gt;{&amp;quot;tod&amp;quot;:None,&amp;quot;dow&amp;quot;:None}&amp;lt;/code&amp;gt;}} dictionary.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing an existing Finite State Machine is as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, &amp;lt;code&amp;gt;cleardelay&amp;lt;/code&amp;gt;, which defaults to &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;cleardelay&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, then the delay of the state is cleared. If you don’t want to edit the state but clear the delay, just set the &amp;lt;code&amp;gt;State.delay&amp;lt;/code&amp;gt; attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once cleared, the state is unlinked to the FSM, which means that story will block at that state. It’s up to you to link that state to the rest of the machine, with additional states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is easy. In the location labels, the machine state should be tested with &amp;lt;code&amp;gt;is_state(State* states)&amp;lt;/code&amp;gt; method. Multiple states may be passed in that method, as well as a list of states. If the machine is in any of the provided states, then the method returns &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; otherwise. For convenience, similar methods are used: &amp;lt;code&amp;gt;between_states(State state1, State state2)&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; if the machine is in any state between &amp;lt;code&amp;gt;state1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;state2&amp;lt;/code&amp;gt; but is not in state &amp;lt;code&amp;gt;state2&amp;lt;/code&amp;gt;; {{nowrap|&amp;lt;code&amp;gt;finished_state(State* states)&amp;lt;/code&amp;gt;}} returns &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; if the machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, {{nowrap|&amp;lt;code&amp;gt;trigger(Trigger t)&amp;lt;/code&amp;gt;}} method of the machine class is used. It moves the machine to the next state associated with that trigger if the provided trigger is in the current state table, and doesn’t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of FSM ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie’s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie’s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool,&lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It’s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, since the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file or reloading the game, the states are created and linked together, but after the machine itself is initialized. Here is the order applies to the previous example:&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;init (triggers)&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;call (after_load/start)&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;call &amp;lt;code&amp;gt;cassie_machine_init&amp;lt;/code&amp;gt;&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;call &amp;lt;code&amp;gt;cassie_fsm_init&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Explication: the machine is named &amp;lt;code&amp;gt;M_cassie&amp;lt;/code&amp;gt; and is given the name &amp;lt;code&amp;gt;cassie&amp;lt;/code&amp;gt;. This name is used in several places throughout the code to refer to that object. Furthermore, Cassie’s default location (&amp;lt;code&amp;gt;default_loc&amp;lt;/code&amp;gt; argument) specifies that the character is at the pool from morning to evening, and nowhere at night. A dictionary is initialized as well to keep track of some other variables, like the sex animations speed, the previous sexual interactions with that character, the variables to trigger repeatable dialogues, counters, etc.&amp;lt;br&amp;gt;&lt;br /&gt;
In the same label, you can set up the [[#Outfit manager|outfit system]] of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the Finite State Machine.&lt;br /&gt;
&lt;br /&gt;
The states are created and linked in the label &amp;lt;code&amp;gt;cassie_fsm_init&amp;lt;/code&amp;gt;. In the given example, the last link has a state action attached to it, which means that on reaching the &amp;lt;code&amp;gt;S_cassie_end&amp;lt;/code&amp;gt; state, the machine automatically calls the unlock method for the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same way, other state actions may be defined.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;More examples:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an {{strong|outfit manager}} instance attached to it. This system is designed a bit like the Location system: each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. The manager also considers the current location and handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind the schedule of an outfit to a specific location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the location as first argument, and the outfit string/schedule as second argument.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a location schedule, it’s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
; default_outfit : Defaults to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
; is_naked : Defaults to &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
; default_outfit : The outfit schedule used if the character is in a location that doesn’t have a table of outfits for that character.&lt;br /&gt;
; is_naked : Boolean that tells if the machine is naked or not.&lt;br /&gt;
; bind_outfit_to_location(Location location, object outfit_schedule) : Bind the given outfit schedule to the given location. The outfit schedule may be a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
; format_outfit_schedule(object outfit_schedule) : Format the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
; property get() : Return the proper outfit given the current time of day, day of week, whether the machine is naked or not, and current location.&lt;br /&gt;
&lt;br /&gt;
{{Message box important|Below is a copy‐paste from Discord that will be rewritten later. It gets the point across though.}}&lt;br /&gt;
&lt;br /&gt;
So basically how the new outfit system works; you have to setup the outfit manager. The same manager has one method called &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt; that takes 2 arguments: &amp;lt;code&amp;gt;location&amp;lt;/code&amp;gt;, a location object, and &amp;lt;code&amp;gt;outfit&amp;lt;/code&amp;gt;, which can be an outfit string or an outfit schedule, i.e. a matrix just like the locations. This method creates a map of outfits to use in certain conditions.&lt;br /&gt;
&lt;br /&gt;
Moreover, the outfits can be set with a simple state action which takes care of calling the &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt; method. Now, to get the outfit, it’s as simple as calling &amp;lt;code&amp;gt;M_diane.outfit.get&amp;lt;/code&amp;gt; (without any parentheses as &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; is a property of the outfit manager). The variable &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; has also been moved to the outfit manager.&lt;br /&gt;
&lt;br /&gt;
Instead of &amp;lt;code&amp;gt;M_diane.get_naked_str&amp;lt;/code&amp;gt;, use &amp;lt;code&amp;gt;M_diane.outfit.get&amp;lt;/code&amp;gt;; and instead of doing &amp;lt;code&amp;gt;M_diane.outfit = &amp;quot;whatever&amp;quot;&amp;lt;/code&amp;gt;, configure the outfit manager with &amp;lt;code&amp;gt;M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&amp;lt;/code&amp;gt;. If you want more granularity, write &amp;lt;code&amp;gt;M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&amp;lt;/code&amp;gt;. You can even set that matrix to bean individual outfit for each time of day, each day of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;setnaked&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;setoutfit&amp;lt;/code&amp;gt; are dedicated to the state action:&lt;br /&gt;
* &amp;lt;code&amp;gt;setnaked&amp;lt;/code&amp;gt; sets the machine to be naked or not, thing you can also do with &amp;lt;code&amp;gt;M_diane.outfit.is_naked = True/False&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;setoutfit&amp;lt;/code&amp;gt; calls &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt; method with two arguments specified like that: &amp;lt;code&amp;gt;actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example for&amp;lt;/u&amp;gt; &amp;lt;code&amp;gt;Machine.outfit.get property&amp;lt;/code&amp;gt;:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;del M_diane.outfit.outfits[L_home_livingroom]&amp;lt;/code&amp;gt; to revert back to the default if needed.&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy manager ===&lt;br /&gt;
&lt;br /&gt;
=== Dating System ===&lt;br /&gt;
In version 0.19 of the game, the dating system was introduced, as a way to limit the impact it would have on future save and compatibility.&lt;br /&gt;
&lt;br /&gt;
The dating system functions through &amp;lt;code&amp;gt;dating_points&amp;lt;/code&amp;gt;. Dating points are a secondary currency that is specific to each machine, and that you earn by performing tasks with said machines.&lt;br /&gt;
&lt;br /&gt;
==== The dating.json file ====&lt;br /&gt;
Each datable state machine has an entry in that file, which specifies what are this machine&#039;s likes and dislikes, among other things. Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=js&amp;gt;&lt;br /&gt;
    &amp;quot;roxxy&amp;quot;: {&lt;br /&gt;
        &amp;quot;activities&amp;quot;: {&lt;br /&gt;
            &amp;quot;movies&amp;quot;: 5,&lt;br /&gt;
            &amp;quot;eating&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;swimming&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;gifts&amp;quot;: {&lt;br /&gt;
            &amp;quot;crystal_necklace&amp;quot;: 5,&lt;br /&gt;
            &amp;quot;pearl_necklace&amp;quot;: 4,&lt;br /&gt;
            &amp;quot;heart_necklace&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;plush_*&amp;quot;: 2,&lt;br /&gt;
            &amp;quot;flower_*&amp;quot;: 1&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;dialogues&amp;quot;: {&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;thresholds&amp;quot;: {&lt;br /&gt;
            &amp;quot;sex&amp;quot;: 30&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* activities : possible activities with this datable machine, include things like picnics, eating at a restaurant, swimming, going to the movies&lt;br /&gt;
* gifts : possible gifts to give to this machine. Items from Cupid are giftable, but other items may be gifted as well, depending on the machine. June might like videogames found at Cosmic Cumics for instance&lt;br /&gt;
* dialogues : possible dialogues tied to dating, that are triggered when talking to the character. Some dialogues may be tied to a threshold.&lt;br /&gt;
* thresholds : dating_points thresholds the machine must reach beefore certain events may occur, like dialogues, sex, oral sex, foreplay and so on.&lt;br /&gt;
&lt;br /&gt;
Each like or dislike is rated on a scale of -5 to 5, corresponding to the amount of dating points one earns when performing that action.&lt;br /&gt;
&lt;br /&gt;
==== Dating points exponential decrease ====&lt;br /&gt;
&lt;br /&gt;
The more one performs a specific action with a machine, the less points are awarded for performing said action. The formula is as follows :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;value_awarded = base_value * exp(-0.3 * t), t= n of times the action was performed.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result is then rounded, and cast as an integer before being added to the total dating points.&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
{{strong|Locations}} handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith’s Bedroom, which has the front yard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a location ===&lt;br /&gt;
&lt;br /&gt;
Locations are easy to create. It’s as simple as instantiating the Location class, and providing a name for that location to the constructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;lt;code&amp;gt;modname_locations_init&amp;lt;/code&amp;gt; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, a locations has several optional arguments:&lt;br /&gt;
&lt;br /&gt;
; name : The name for that location, as can be seen in the top‐left corner of the screen. It’s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
; unlock_popup : The name of a Ren’Py‐defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
; background : The name of the background used for that location. The background name must follow several conventions to properly work:&lt;br /&gt;
:* Must be in the folder &amp;lt;code&amp;gt;images/backgrounds/&amp;lt;/code&amp;gt;&lt;br /&gt;
:* Name must start with &amp;lt;code&amp;gt;location_&amp;lt;/code&amp;gt;&lt;br /&gt;
:* Name must end with &amp;lt;code&amp;gt;_day.jpg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;_evening.jpg&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;_night.jpg&amp;lt;/code&amp;gt;, respectively for day, evening or night background.&lt;br /&gt;
:* For Halloween or Christmas backgrounds, the strings &amp;lt;code&amp;gt;_halloween&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;_christmas&amp;lt;/code&amp;gt; must be added before the time of day code. This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. &amp;lt;code&amp;gt;background_blur&amp;lt;/code&amp;gt;) properties.&lt;br /&gt;
; parents : Either a list of location or a single location instance. Provide the parents of that location. If left empty, the location is assumed to be the root of the tree. The root should always be &amp;lt;code&amp;gt;L_map&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;L_NULL&amp;lt;/code&amp;gt;, but &amp;lt;code&amp;gt;L_NULL&amp;lt;/code&amp;gt; should not have children).&lt;br /&gt;
; locked : Defaults to &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. Whether that location should be initially locked, and inaccessible at the beginning of the game.&lt;br /&gt;
; label : (to be deprecated) The label name for that location. &amp;lt;code&amp;gt;formatted_name&amp;lt;/code&amp;gt; property will be used later on.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code defines a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name: &amp;lt;code&amp;gt;dianes_barn&amp;lt;/code&amp;gt;), child of &amp;lt;code&amp;gt;L_map&amp;lt;/code&amp;gt;, that shows &amp;lt;code&amp;gt;popup_diane_barn&amp;lt;/code&amp;gt; on unlock, and that is initially locked. The background is set as &amp;lt;code&amp;gt;barn_frontyard&amp;lt;/code&amp;gt;, which means the game looks for files named &amp;lt;code&amp;gt;backgrounds/location_barn_frontyard_day.jpg&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;backgrounds/location_barn_frontyard_night.jpg&amp;lt;/code&amp;gt; for instance.&lt;br /&gt;
&lt;br /&gt;
== User‐defined screen actions ==&lt;br /&gt;
&lt;br /&gt;
The {{strong|screen actions}} are specific to &#039;&#039;Summertime Saga&#039;&#039; and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
&lt;br /&gt;
This action expects a location to be passed. It hides the current screen, moves the player to that location, and calls the corresponding screen as well as jumps to the location label.&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, buys the item, and shows the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the &amp;lt;code&amp;gt;callback_label&amp;lt;/code&amp;gt; optional argument. If the transaction succeeds, the game then calls that label. Useful if you want some story element to trigger after buying an item.&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
This action is used to talk to the character. It hides the screen and start the conversation with the given character. It expects a machine instance, or a string to identify it, in which case it attempts to find the machine in the &amp;lt;code&amp;gt;store.machines&amp;lt;/code&amp;gt; dictionary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
This action resets all persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
This action gets the item, and attempts to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The {{strong|inventory manager}} is fully automatic, but you may want to add some items to the game. Items are stored in &amp;lt;code&amp;gt;items.json&amp;lt;/code&amp;gt; file located in &amp;lt;code&amp;gt;scripts/data/folder&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order:&lt;br /&gt;
* &amp;lt;code&amp;gt;birth_control_pills&amp;lt;/code&amp;gt;: the item identifier.&lt;br /&gt;
* &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;: a numeric id. Unused at this moment.&lt;br /&gt;
* &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;: the item name, as seen in the inventory.&lt;br /&gt;
* &amp;lt;code&amp;gt;cost&amp;lt;/code&amp;gt;: the item cost. It’s cast as an integer, and prevents the player from picking up the item if he doesn’t have sufficient money.&lt;br /&gt;
* &amp;lt;code&amp;gt;image&amp;lt;/code&amp;gt;: the item miniature image, as seen in the inventory.&lt;br /&gt;
* &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt;: the item description, as seen in the inventory.&lt;br /&gt;
* &amp;lt;code&amp;gt;closeup&amp;lt;/code&amp;gt;: the item close‐up image, if there is one.&lt;br /&gt;
* &amp;lt;code&amp;gt;dialogue_label&amp;lt;/code&amp;gt;: the item dialogue label. It’s triggered if it exists, on clicking the item. The label should always return, and take an item argument.&lt;br /&gt;
* &amp;lt;code&amp;gt;popup_image&amp;lt;/code&amp;gt;: the item popup image. It’s displayed when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text messages ===&lt;br /&gt;
&lt;br /&gt;
{{strong|Text messages}} are stored in this format in &amp;lt;code&amp;gt;text_messages.json&amp;lt;/code&amp;gt; file. Once defined there, you can use &amp;lt;code&amp;gt;player.receive_message(message_id)&amp;lt;/code&amp;gt; for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order:&lt;br /&gt;
* &amp;lt;code&amp;gt;mia02&amp;lt;/code&amp;gt;: the message identifier. Must be unique. Message identifiers ending in &amp;lt;code&amp;gt;_pregnancy&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;_pregnancy_labor&amp;lt;/code&amp;gt; are reserved for the pregnancy system messages.&lt;br /&gt;
* &amp;lt;code&amp;gt;sender&amp;lt;/code&amp;gt;: the name of the machine that sent this message.&lt;br /&gt;
* &amp;lt;code&amp;gt;content_preview&amp;lt;/code&amp;gt;: the preview text displayed on the phone main screen.&lt;br /&gt;
* &amp;lt;code&amp;gt;content&amp;lt;/code&amp;gt;: the actual message displayed when clicking the message in the phone.&lt;br /&gt;
* &amp;lt;code&amp;gt;image&amp;lt;/code&amp;gt;: the image used as a &amp;quot;profile picture on the phone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
{{strong|Achievements}} are defined in &amp;lt;code&amp;gt;achievements.json&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order:&lt;br /&gt;
* &amp;lt;code&amp;gt;angler&amp;lt;/code&amp;gt;: the achievement identifier. Must be unique. The identifier is used to name the achievement variable. Dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;: a numeric id. Unused.&lt;br /&gt;
* &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;: the achievement’s name.&lt;br /&gt;
* &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt;: the achievement’s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* &amp;lt;code&amp;gt;hidden&amp;lt;/code&amp;gt;: whether it’s a secret achievement or not.&lt;br /&gt;
* &amp;lt;code&amp;gt;enabled&amp;lt;/code&amp;gt;: if the achievement can be achieved.&lt;br /&gt;
* &amp;lt;code&amp;gt;image&amp;lt;/code&amp;gt;: the icon for this achievement.&lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;dialogues.json&amp;lt;/code&amp;gt; file is used for the dialogue lines written by the higher tier contributors of DarkCookie’s Patreon.&lt;br /&gt;
&lt;br /&gt;
=== Key binding ===&lt;br /&gt;
&lt;br /&gt;
{{Message box warning|This code is not yet implemented.}}&lt;br /&gt;
&lt;br /&gt;
This file lists the default key bindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
&lt;br /&gt;
{{Message box warning|This code is not yet implemented.}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to &amp;lt;code&amp;gt;items.json&amp;lt;/code&amp;gt;. At the moment, no furnishings have been implemented. They will be available for the [[beachhouse]] location with an upgrade system.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The {{strong|game manager class}} handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still usable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
; language : Set the language of the game which is used for translations. Defaults to &amp;lt;code&amp;gt;&amp;quot;en&amp;quot;&amp;lt;/code&amp;gt; for English with other languages in the game untranslated.&lt;br /&gt;
; cheat_mode : Return &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; if the game is currently in cheat mode (thus allowing minigames to be skipped).&lt;br /&gt;
; CA_FILE : Path to a certification file used to enable requests to websites. Used only if the player has checked the option &amp;quot;Allow Internet Access&amp;quot;.&lt;br /&gt;
; lock_ui() : Lock the user interface.&lt;br /&gt;
; unlock_ui() : Unlock the user interface.&lt;br /&gt;
; ui_locked() : Return whether the user interface is locked or not (i.e. grayed‐out).&lt;br /&gt;
; dialog_select(string label_name) : Classmethod that chooses a label based on its name and the language class attribute. To be used to split dialogues and logic, and also allows your mod to be easily translated.&lt;br /&gt;
; choose_label(string template) : Classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
; main() : Method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player’s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not indigestible. It may take two arguments, &amp;lt;code&amp;gt;clear_return_stack&amp;lt;/code&amp;gt; to enable or not return stack clearing, and location, to call the screen of another location than the player’s currently in.&lt;br /&gt;
; is_christmas() : Classmethods that checks if the system clock matches Christmas.&lt;br /&gt;
; is_halloween() : Classmethods that checks if the system clock matches Halloween.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The {{strong|player class}} handles everything related to the player: the inventory, grades, vehicle level and stats. Notable methods:&lt;br /&gt;
&lt;br /&gt;
; receive_message(string message_id) : Check if the player has received the given text message on the phone. Also sets up the alert icon on the user interface.&lt;br /&gt;
; has_item(string* items) : Check if the player has any of the items provided at this moment.&lt;br /&gt;
; has_picked_up_item(string* items) : Check if the player has ever picked up any of the items provided.&lt;br /&gt;
; get_item(string item) : Get the item if the price of the item doesn’t exceed the amount of the player’s money.&lt;br /&gt;
; remove_item(string item) : Remove an item by its string id.&lt;br /&gt;
; get_money(int money) : Add money to the player.&lt;br /&gt;
; spend_money(int money) : Subtract money from the player.&lt;br /&gt;
; has_required_str(int min_str) : Check if the player has the required strength. Similar method exist for &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;chr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dex&amp;lt;/code&amp;gt;.&lt;br /&gt;
; go_to(Location location) : Go to the given location.&lt;br /&gt;
; go_to_previous() : Go to the first parent location of the current location.&lt;br /&gt;
; increase_str(int amount) : Increase the strength by amount. Defaults to 1. Similar method exist for &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;chr&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dex&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
; KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:; get_instances() : Classmethod to get a generator of all the instances of this class subclass.&lt;br /&gt;
&lt;br /&gt;
; LastUpdatedOrderedDict : A dictionary‐like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python’s OrderedDict from the collections package.&lt;br /&gt;
:; listvalues : Return a list of all the values of this dictionary.&lt;br /&gt;
:; listkeys : Return a list of all the keys of this dictionary.&lt;br /&gt;
:; lastkey : Return the last key added to this dictionary.&lt;br /&gt;
:; lastvalue : Return the value of the last key added to this dictionary.&lt;br /&gt;
:; isempty : Return whether the dictionary is empty.&lt;br /&gt;
&lt;br /&gt;
; format_seconds_to_dhm(int seconds) : Return a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
; insert_newlines(string string_to_format, int every) : Return a new string based on the passed in string, with newlines inserted every &amp;lt;code&amp;gt;every&amp;lt;/code&amp;gt; character. &amp;lt;code&amp;gt;every&amp;lt;/code&amp;gt; defaults to 30. Differs from &amp;lt;code&amp;gt;splice_string()&amp;lt;/code&amp;gt; in that it is not cut a word in the middle if possible. &amp;lt;code&amp;gt;splice_string()&amp;lt;/code&amp;gt; inserts a newline every &amp;lt;code&amp;gt;every&amp;lt;/code&amp;gt; characters without question. &amp;lt;code&amp;gt;insert_newline()&amp;lt;/code&amp;gt; is much safer as it will not cut a variable substitution, but is much slower than &amp;lt;code&amp;gt;splice_string()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; text_identity(string text) : Return unmodified text, useful for &amp;lt;code&amp;gt;config.say_menu_text_filter&amp;lt;/code&amp;gt; if it is &amp;lt;code&amp;gt;None&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; replace_bracket(string text) : Return text without the [ and ] characters (Ren’Py variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
; gauss(float mean, float deviation, float lower, float upper) : Return a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
; get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : Return two lists – &amp;lt;code&amp;gt;true angles&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false angles&amp;lt;/code&amp;gt; – which are lists of tuples (&amp;lt;code&amp;gt;initial_angle, initial_speed&amp;lt;/code&amp;gt;) for which the result land in or out of the &amp;lt;code&amp;gt;angle_width&amp;lt;/code&amp;gt;. Used in [[Impregnation minigame]] and [[Spin the bottle minigame]].&lt;br /&gt;
&lt;br /&gt;
; safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : Return the content of the dictionary at keys &amp;lt;code&amp;gt;keys&amp;lt;/code&amp;gt;, subscribed in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionally, you can pass in a list to append the name of the missing keys of the dictionary to.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Examples:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positional argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Community]]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=17750</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=17750"/>
		<updated>2019-09-26T15:34:39Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Screens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The modding of the game is based on the Summertime Saga API. It is recommended to read the [[Summertime Saga API|corresponding article]] beforehand in order to familiarize yourself with the specificities of the code.&lt;br /&gt;
{{TOC limit|3}}&lt;br /&gt;
&lt;br /&gt;
== Hooking into the game ==&lt;br /&gt;
&lt;br /&gt;
{{Message box important|This feature is incomplete as of version 0.18.6, the ModManager class is present, but no hooking of any kind can be done at the moment.}}&lt;br /&gt;
&lt;br /&gt;
=== Registration and enabling of the mod ===&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game. This registration makes the mod show up in the (upcoming) Mods menu on the main menu so the players have the choice to enable or disable the mod for the game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A manifest file named &amp;lt;code&amp;gt;modname_manifest.json&amp;lt;/code&amp;gt; must be added in the &amp;lt;code&amp;gt;scripts/data&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
=== Manifest file ===&lt;br /&gt;
&lt;br /&gt;
The {{strong|manifest file}} details in which labels the mod should hook into the game, and which screens. It also defines the name of the main function you wish to use to hook into the &amp;lt;code&amp;gt;game.main()&amp;lt;/code&amp;gt; function, if any.&lt;br /&gt;
&lt;br /&gt;
==== Preferred mod load order ====&lt;br /&gt;
&lt;br /&gt;
Adding a key named &amp;lt;code&amp;gt;load_order&amp;lt;/code&amp;gt; to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&amp;lt;br&amp;gt;&lt;br /&gt;
The value of this key must be a string leading with either &amp;lt;code&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; followed by an integer. Additionally, the values &amp;lt;code&amp;gt;inf&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-inf&amp;lt;/code&amp;gt; can be used to set the load order as last, and absolutely first. If several mods are defined with &amp;lt;code&amp;gt;-inf&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;load_order&amp;lt;/code&amp;gt;, then a random order is chosen. The default value is &amp;lt;code&amp;gt;inf&amp;lt;/code&amp;gt;, which means the mods are added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
==== Main function name ====&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function is searched for ini the &amp;lt;code&amp;gt;globals()&amp;lt;/code&amp;gt; of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
==== Init label name ====&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game is fully initialized, either at the start of the game or after the load of the game.&amp;lt;br&amp;gt;&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won’t be loaded&lt;br /&gt;
&lt;br /&gt;
==== Adding to the game’s json files ====&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;lt;code&amp;gt;items&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;achievements&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;text_messages&amp;lt;/code&amp;gt; can be used to add data to the game json files. Each of these keys expects a full json dictionary formatted in the same way as their respective models.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example of manifest:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;text_filter&amp;quot;:&amp;quot;ikarumod_text_filter&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mod init order ===&lt;br /&gt;
&lt;br /&gt;
{{Message box information|Mods are assumed to be in an initial random order.}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod’s name, parse the load order from the manifest, then insert that mod in the &amp;lt;code&amp;gt;ModManager.mods&amp;lt;/code&amp;gt; list in the proper position. Then, for every mod in the &amp;lt;code&amp;gt;ModManager.mods&amp;lt;/code&amp;gt; list, call their init label, if defined. Finally, update the game stores (i.e. achievements, items and text_messages) with every data of the mod. Updates overwrite the keys, so the load order can be used to overwrite the game’s (although ill‐advised) or another mod’s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
=== Text filter ===&lt;br /&gt;
&lt;br /&gt;
The {{strong|text filter}} key in the manifest allows you to create your own filter function without overwriting other mods.&lt;br /&gt;
If undefined, this defaults to {{nowrap|&amp;lt;code&amp;gt;lambda text:text&amp;lt;/code&amp;gt;}}, otherwise the value of this key should be a string of the name of the function you wish to pass in as a text filter. If the function cannot be found in the global namespace (i.e. the &amp;lt;code&amp;gt;globals()&amp;lt;/code&amp;gt; dictionary), then a &amp;lt;code&amp;gt;ModLoaderError(&amp;quot;No Function named {text_filter} found in the global namespace. Is it defined properly?&amp;quot;)&amp;lt;/code&amp;gt; exception will be raised.&lt;br /&gt;
&lt;br /&gt;
=== Screens ===&lt;br /&gt;
&lt;br /&gt;
Create your {{strong|screens}} with the following convention: &amp;lt;code&amp;gt;modname&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;_&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;in‐game screen name&amp;lt;/code&amp;gt; (the Ren’Py definition name). Screens are being included into the main game screens with the use statement. If you wish to add new locations, you have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&amp;lt;br&amp;gt;&lt;br /&gt;
To ensure proper game progression, you shoul only add imagebuttons. Please refer to {{section link|Summertime Saga API#User-defined screen actions}} for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
The mod screen hook is quite simple as it uses RenPy&#039;s &amp;lt;code&amp;gt;use&amp;lt;/code&amp;gt; statement for every modded screen. The screen hook is called at the end of each screen, so background set up and imagebuttons for the game are already properly shown and defined. You can then add your own imagebuttons, and other screen features to it.&lt;br /&gt;
&lt;br /&gt;
Note : Hookable screens are, at least for now, only the location screens, and do not include the UI.&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
{{Message box warning|This code is not yet implemented.}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; {{strong|labels}} can be hooked into. Those are labels that end in {{nowrap|&amp;lt;code&amp;gt;$ game.main()&amp;lt;/code&amp;gt;}}.&lt;br /&gt;
&lt;br /&gt;
=== Main function ===&lt;br /&gt;
&lt;br /&gt;
{{Message box warning|This code is not yet implemented.}}&lt;br /&gt;
&lt;br /&gt;
To hook into the {{strong|main function}}, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;code&amp;gt;ikarumod_main&amp;lt;/code&amp;gt; is assumed to be a callable, which should be a python function. The function is called with no arguments at the end of &amp;lt;code&amp;gt;game.main()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
== Imported modules and directory structure ==&lt;br /&gt;
&lt;br /&gt;
=== Third‐party modules ===&lt;br /&gt;
&lt;br /&gt;
==== Platform agnostic ====&lt;br /&gt;
&lt;br /&gt;
* os&lt;br /&gt;
* pygame&lt;br /&gt;
* sys&lt;br /&gt;
* from time : time, clock&lt;br /&gt;
* from copy : copy, deepcopy&lt;br /&gt;
* datetime&lt;br /&gt;
* re&lt;br /&gt;
* random&lt;br /&gt;
* math&lt;br /&gt;
* from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
* weakref&lt;br /&gt;
* codecs&lt;br /&gt;
* hashlib&lt;br /&gt;
* json&lt;br /&gt;
* itertools&lt;br /&gt;
* operator&lt;br /&gt;
* textwrap&lt;br /&gt;
* deuces&lt;br /&gt;
&lt;br /&gt;
==== Desktop builds ====&lt;br /&gt;
&lt;br /&gt;
* certifi&lt;br /&gt;
* requests&lt;br /&gt;
&lt;br /&gt;
==== Mobile builds ====&lt;br /&gt;
&lt;br /&gt;
* android&lt;br /&gt;
* pyjnius&lt;br /&gt;
&lt;br /&gt;
=== Directory structure ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;game&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;audio&amp;lt;/code&amp;gt;: SFX and musics&lt;br /&gt;
** &amp;lt;code&amp;gt;fonts&amp;lt;/code&amp;gt;: fonts for the game.&lt;br /&gt;
** &amp;lt;code&amp;gt;images&amp;lt;/code&amp;gt;&lt;br /&gt;
*** &amp;lt;code&amp;gt;achievements&amp;lt;/code&amp;gt;: achievement‐related images.&lt;br /&gt;
*** &amp;lt;code&amp;gt;cookie_jar&amp;lt;/code&amp;gt;: cookie jar buttons, popups and thumbnails.&lt;br /&gt;
*** &amp;lt;code&amp;gt;backgrounds&amp;lt;/code&amp;gt;: backgrounds and close‐ups.&lt;br /&gt;
*** &amp;lt;code&amp;gt;boxes&amp;lt;/code&amp;gt;: popups and general purpose buttons (like the go back button).&lt;br /&gt;
*** &amp;lt;code&amp;gt;buttons&amp;lt;/code&amp;gt;: most minigame assets, and menu buttons.&lt;br /&gt;
*** &amp;lt;code&amp;gt;cellphone&amp;lt;/code&amp;gt;: cellphone images assets.&lt;br /&gt;
*** &amp;lt;code&amp;gt;characters&amp;lt;/code&amp;gt;: character poses. One folder per character.&lt;br /&gt;
*** &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt;: map locations and map background.&lt;br /&gt;
*** &amp;lt;code&amp;gt;objects&amp;lt;/code&amp;gt;: character buttons, item buttons, doors, etc.&lt;br /&gt;
*** &amp;lt;code&amp;gt;vfx&amp;lt;/code&amp;gt;: special visual effects (like the rain in Roxxy’s trailing scene).&lt;br /&gt;
** &amp;lt;code&amp;gt;python-packages&amp;lt;/code&amp;gt;: third party python modules.&lt;br /&gt;
** &amp;lt;code&amp;gt;scripts&amp;lt;/code&amp;gt;&lt;br /&gt;
*** &amp;lt;code&amp;gt;characters&amp;lt;/code&amp;gt;: one folder for each character, containing an fsm file, a character.rpy file for miscellaneous stuff, and a layeredimage definition file. May contain a file for the character’s button and the according dialogues.&lt;br /&gt;
*** &amp;lt;code&amp;gt;core&amp;lt;/code&amp;gt;: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
*** &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;: JSON files that contain data about the game. Items, achievements, keymap or text messages are defined here.&lt;br /&gt;
*** &amp;lt;code&amp;gt;defines&amp;lt;/code&amp;gt;: general image definitions, transforms, etc.&lt;br /&gt;
*** &amp;lt;code&amp;gt;locations&amp;lt;/code&amp;gt;: one folder for every location, sorted in a tree‐like structure. Each location has a main file, a screen file and a dialogues file.&lt;br /&gt;
*** &amp;lt;code&amp;gt;minigames&amp;lt;/code&amp;gt;: one folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
*** &amp;lt;code&amp;gt;script.rpy&amp;lt;/code&amp;gt;&lt;br /&gt;
*** &amp;lt;code&amp;gt;pregnancy_announcements.rpy&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;changelog.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;pledge_list.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Translating the game ==&lt;br /&gt;
&lt;br /&gt;
=== Label calling in the game ===&lt;br /&gt;
&lt;br /&gt;
The game offers a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it’s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for Spanish for instance, &amp;quot;fr&amp;quot; for French, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every time a dialogue is called, the game looks for the label name and the language string at the end. For instance, the label &amp;lt;code&amp;gt;bank_liu_account_info&amp;lt;/code&amp;gt; has the English version in; and to overwrite that dialogue, you’d have &amp;lt;code&amp;gt;bank_liu_account_info_fr&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;bank_liu_account_info_es&amp;lt;/code&amp;gt; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
Any dialogue can be translated with this method. Keeping a consistent directory structure is recommended, because of the large number of dialogues in the game. You also have to copy over the posing. For your convenience, every dialogue label is stored in a &amp;lt;code&amp;gt;dialogues.rpy&amp;lt;/code&amp;gt; file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
=== Cutscenes and minigame instructions ===&lt;br /&gt;
&lt;br /&gt;
You can’t edit the &#039;&#039;&#039;cutscenes&#039;&#039;&#039; directly. Well, you could, but you shouldn’t! Using the &amp;lt;code&amp;gt;config.say_menu_text_filter&amp;lt;/code&amp;gt; variable is the best way. Just register a function to that variable with one argument, &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt;, which contains the text of the displayable. Then edit the text how you see fit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example of translation:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je pus aller dans le grenier.\nJe n&#039;y avais jamais été auparavant.\nUn sentiment d&#039;excitation m&#039;envahissait alors que je me demandais quels trésors {b}[deb_name]{/b} et papa avaient caché là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that Ren’Py engine doesn’t handle large dictionaries. &amp;lt;code&amp;gt;elif&amp;lt;/code&amp;gt; statements can be used to split the content into several dictionaries if necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, registering to &amp;lt;code&amp;gt;config.say_menu_text_filter&amp;lt;/code&amp;gt; variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;br /&gt;
&lt;br /&gt;
=== Location names ===&lt;br /&gt;
&lt;br /&gt;
In an &amp;lt;code&amp;gt;init 1 python&amp;lt;/code&amp;gt; (or later) block, you can set the display name of any location object in the game. This allows renaming and translation of any game location, thus displaying that name in relevant parts of the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Example:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init -1 python:&lt;br /&gt;
    L_map.display_name = &amp;quot;New Map Name&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Community]]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Daisy%E2%80%99s_route&amp;diff=15332</id>
		<title>Daisy’s route</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Daisy%E2%80%99s_route&amp;diff=15332"/>
		<updated>2019-08-07T05:50:24Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Story */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
* Progress until step 20 in [[Diane&#039;s route]]&lt;br /&gt;
* Progress until step 20 in [[Roxxy&#039;s route]]&lt;br /&gt;
* $5,270&lt;br /&gt;
&lt;br /&gt;
== Story ==&lt;br /&gt;
{{AlertInfo|If clyde is not available because of progress in Roxxy&#039;s storyline, finish Roxxy first so that he reappears as Cletus}}&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
 | direction = vertical&lt;br /&gt;
 | header = Statue Parts&lt;br /&gt;
 | width = 125&lt;br /&gt;
 | image1 = Mysterious Statue (Legs) icon.png&lt;br /&gt;
 | caption1 = The legs are found by Richard&lt;br /&gt;
 | image2 = Mysterious Statue (Torso) icon.png&lt;br /&gt;
 | caption2 = The torso is found by Clyde&lt;br /&gt;
 | image3 = Mysterious Statue (Head) icon.png&lt;br /&gt;
 | caption3 = The head is found by Consuela&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Introduction: A Mysterious Statue&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;Find the 3 parts of the mysterious statue:&amp;lt;/li&amp;gt;&lt;br /&gt;
# Upon completion of Diane&#039;s barn, [[Annie]]&#039;s father, [[Richard]], hands over the bottom part of the statue to you.&lt;br /&gt;
# Ask Clyde about his dog at the [[Trailer Park|trailer park]]. Go to [[Cupid]] store at the [[Hillside Mall|mall]] and buy a [[Plush - Pink Beaver|Pink Beaver plush]]. Go back and give him the plush. Clyde rewards you with the middle part of the statue.&lt;br /&gt;
# Buy the [[Beach House]]. Meet [[Consuela]] at the Beach House on Thursday in the afternoon (&amp;lt;u&amp;gt;she is only available on Thursday afternoons&amp;lt;/u&amp;gt;). Revisit the house the next Thursday: she has found the top part of the statue.&lt;br /&gt;
The 3 parts in your possession, go to the barn, then examine the statue in the garden. Ask Diane for a [[Milk Sample|sample of her milk]] and pour it on the statue. It suddenly turns into a cow girl! Join the girls inside the barn.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Allow 3 days to pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Meet Daisy&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;ol start=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;li&amp;gt;Go to the barn. You can now talk to the newcomer called [[Daisy]].&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Allow 2 days to pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Veggie Pizza&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;ol start=&amp;quot;3&amp;quot;&amp;gt;&amp;lt;li&amp;gt;Go to Diane&#039;s and [[Gardening minigame|take care of the garden]]. Diane is milking the cow girl in the barn. Daisy wants a pizza, so go to [[Tony&#039;s Pizza]], buy a [[Vegetarian Pizza|vegetarian pizza]] and bring it back to her.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Allow 2 days to pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Sunflowers&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;ol start=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;li&amp;gt;Go to the barn. Daisy&#039;s flowers have died. To make her happy, buy [[Bouquet - Sunflowers|sunflowers]] at Cupid. Return to the barn and hand your gift to the cow girl: mission accomplished! Talk to her again to begin your first [[Milking minigame|milking session]].&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Next day, go say hi to Daisy before a horny Diane expects some sexual favour from you (Diane CANNOT be pregnant for this to occur). Both girls have a discussion together later.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Next day, meet Daisy who is eagerly wanting to have some fun with you. Agree.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{note|You get the [[Achievements|achievement]] &#039;&#039;&#039;More girl than cow&#039;&#039;&#039;.}}&lt;br /&gt;
&lt;br /&gt;
== Pregnancy ==&lt;br /&gt;
&lt;br /&gt;
{{note|For more information about the pregnancy planning pills, see {{section link|Dating and pregnancy|Pregnancy}}}}&lt;br /&gt;
&lt;br /&gt;
Having sex with Daisy provides the option of [[Impregnation minigame|making her pregnant]]. One week later, read the phone message and visit the barn for the announcement; four more weeks and a new message notifies she has given birth, read it and meet the girls at the barn. It takes three weeks until the baby is sent to daycare and you can resume normal activities with Daisy.&lt;br /&gt;
&lt;br /&gt;
{{Navbox Walkthrough}}&lt;br /&gt;
[[Category:Routes]]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14864</id>
		<title>Developers logs</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14864"/>
		<updated>2019-07-16T20:50:16Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* 2019 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A {{strong|developer log}} or devlog is a post dedicated to the development of &#039;&#039;Summertime Saga&#039;&#039; project. Team members can introduce their works in progress and share updates as they have them. The infos, gathered from various sources, are compiled by antichronological order.&lt;br /&gt;
&lt;br /&gt;
=== 2019 ===&lt;br /&gt;
&lt;br /&gt;
* [[File:Reddit logo rounded.png|20px|link=]] [https://www.reddit.com/r/SummertimeSaga/comments/ca4iq1/summertime_saga_sundays_2 Lead coder devlog #2 — 07/07/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/0-18-5-and-0-19-26695540 0.18.5 and 0.19 status update — 05/08/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Reddit logo rounded.png|20px|link=]] [https://www.reddit.com/r/SummertimeSaga/comments/blnzsg/devlog_summertime_saga_devlogs_1 Lead coder devlog #1 — 05/07/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/almost-done-26089100 0.18, 0.18.5 and 0.19 status update — 04/14/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Reddit logo rounded.png|20px|link=]] [https://www.reddit.com/r/SummertimeSaga/comments/b8xhiz/devlogama_a_status_update_on_018 General discussion — 04/03/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/status-update-0-257387130 0.18 status update — 03/30/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/characters-that-24376340 Characters upgraded — 02/01/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Reddit logo rounded.png|20px|link=]] [https://www.reddit.com/r/SummertimeSaga/comments/b8xhiz/devlogama_a_status_update_on_018 Lead coder devlog/AMA — 04/03/19]&lt;br /&gt;
&lt;br /&gt;
=== 2018 ===&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/happy-halloween-22419763 0.18 status update — 10/31/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Reddit logo rounded.png|20px|link=]] [https://www.reddit.com/r/SummertimeSaga/comments/9y94lm/save_retrocompatibility_why_it_is_so_hard_to/ Save retrocompatibility — 18/11/19]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/status-update-0-22053987 Characters improvements and 0.17 status update — 10/14/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/more-and-new-21499515 Characters improvements and new character — 09/19/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/new-character-21231213 Characters improvements: Jane and Jenny — 09/05/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/new-characters-20909420 New characters: Annie&#039;s parents and Priya — 08/22/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/old-art-vs-new-20659058 Old art vs new art — 08/09/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/0-17-diane-20165296 0.16 and 0.17 status update — 07/19/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/improved-diane-0-20148026 Character art improvement: Diane — 07/18/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/character-rework-19435580 New character: Kim — 06/13/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/status-update-19301719 0.16 status update — 06/07/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/0-16-status-18912887 0.16 status update — 05/20/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/character-art-18547081 Character art improvement: Roxxy and Missy — 05/02/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/0-16-kick-off-18228167 0.15 and 0.16 status update — 04/17/18]&lt;br /&gt;
&lt;br /&gt;
* [[File:Patreon logo rounded.png|20px|link=]] [https://www.patreon.com/posts/status-update-17824905 0.15 status update — 03/28/18]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14753</id>
		<title>Developers logs</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14753"/>
		<updated>2019-07-07T08:15:34Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Official Releases ==&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/93b7t1/official_0161_release/ Official 0.16.1 Release (Reddit Thread)]&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/82vylt/a_quick_update_on_what_were_currently_working_on/ Update #0]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== DevLogs ==&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/blnzsg/devlog_summertime_saga_devlogs_1/ DevLog #2]&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/ca4iq1/summertime_saga_sundays_2/? DevLog #2]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14752</id>
		<title>Developers logs</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Developers_logs&amp;diff=14752"/>
		<updated>2019-07-07T08:15:06Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: Created page with &amp;quot;# Official Releases  [https://www.reddit.com/r/SummertimeSaga/comments/93b7t1/official_0161_release/ Official 0.16.1 Release (Reddit Thread)]  # Updates  [https://www.reddit.c...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Official Releases&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/93b7t1/official_0161_release/ Official 0.16.1 Release (Reddit Thread)]&lt;br /&gt;
&lt;br /&gt;
# Updates&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/82vylt/a_quick_update_on_what_were_currently_working_on/ Update #0]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# DevLogs&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/blnzsg/devlog_summertime_saga_devlogs_1/ DevLog #2]&lt;br /&gt;
&lt;br /&gt;
[https://www.reddit.com/r/SummertimeSaga/comments/ca4iq1/summertime_saga_sundays_2/? DevLog #2]&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9557</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9557"/>
		<updated>2019-05-09T09:37:21Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
This menu is accessed by clicking on the wifi icon in the player&#039;s cellphone.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs, and 3 buttons : one for displaying the console history, one for showing the console screen and the last one to close the debug menu.&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
&lt;br /&gt;
- unlock all locations&lt;br /&gt;
&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9556</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9556"/>
		<updated>2019-05-09T09:35:38Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Locations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
&lt;br /&gt;
- unlock all locations&lt;br /&gt;
&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9555</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9555"/>
		<updated>2019-05-09T09:35:29Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Machines */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
&lt;br /&gt;
- unlock all locations&lt;br /&gt;
&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9554</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9554"/>
		<updated>2019-05-09T09:35:20Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Time */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
&lt;br /&gt;
- unlock all locations&lt;br /&gt;
&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9553</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9553"/>
		<updated>2019-05-09T09:35:10Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
&lt;br /&gt;
- unlock all locations&lt;br /&gt;
&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9552</id>
		<title>Debug menu</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Debug_menu&amp;diff=9552"/>
		<updated>2019-05-09T09:34:51Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: Created page with &amp;quot;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.  It provides a lot of useful features to cheat your way...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The debug menu is a menu unlocked by setting the game in developper mode. It is unlocked by default on android devices.&lt;br /&gt;
&lt;br /&gt;
It provides a lot of useful features to cheat your way through the game, or get yourself out of bugs and softlocks.&lt;br /&gt;
&lt;br /&gt;
The debug menu has 6 main tabs&lt;br /&gt;
&lt;br /&gt;
= General =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to general options. From there you can :&lt;br /&gt;
&lt;br /&gt;
- unlock/lock the UI&lt;br /&gt;
- unlock all cookie jar scenes&lt;br /&gt;
- set the rump scene at the mall&lt;br /&gt;
- skip the first day of the game&lt;br /&gt;
- unlock all locations&lt;br /&gt;
- force/unforce the map lock. forcing it unlocked will make the map available from any screen in the game.&lt;br /&gt;
- lock/unlock the sleep lock, allowing you to sleep through anything.&lt;br /&gt;
- toggle the cheat mode on/off&lt;br /&gt;
- watch/unwatch any python expression&lt;br /&gt;
- toggle on/off notifications for label names (on the topleft corner) whenever you enter a new label.&lt;br /&gt;
- toggle on/off the skip intro (which will skip the intro as well as the first day, starting you on the second day)&lt;br /&gt;
&lt;br /&gt;
= Time =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to all the time manipulation functionnalities&lt;br /&gt;
&lt;br /&gt;
- tick timer will advance time by one tick&lt;br /&gt;
- set day to will set the current day to whatever you want, advancing the time until that day.&lt;br /&gt;
- set time to will set the time to whatever you choose moving forward/backwards in time if necessary&lt;br /&gt;
- skip forward allows you to skip ahead a day, week, month or year&lt;br /&gt;
- toggle debug period allows to get christmas/halloween decorations even if it is not christmas or halloween time yet.&lt;br /&gt;
&lt;br /&gt;
= Machines =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to FSMs, gives info about where the machine is located and in which state it is. For each one you can :&lt;br /&gt;
&lt;br /&gt;
- Advance : advances the FSM by one state. Can result in bugs though.&lt;br /&gt;
- Show vars : opens a separate window that shows all the variables for that FSM&lt;br /&gt;
- Pregnancy : opens a separate window with all the variables for that machine&#039;s pregnancy manager.&lt;br /&gt;
&lt;br /&gt;
= Locations =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to locations. For each location you can : &lt;br /&gt;
&lt;br /&gt;
- Lock/Unlock that location&lt;br /&gt;
- Visit/Unvisit that location&lt;br /&gt;
- Set the can_leave flag for that location&lt;br /&gt;
- move the player to that location (Teleportation)&lt;br /&gt;
&lt;br /&gt;
= Player =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the Player object. Its purpose is to be able to manipulate stats and money for the player&lt;br /&gt;
&lt;br /&gt;
= Items =&lt;br /&gt;
&lt;br /&gt;
This tab is dedicated to the items in game. From there you can give or remove yourself any item in the game. It has a convenient search box to filter out items given that there are over 150 of them. You can also use this to print the full item list to the console.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Characters&amp;diff=9123</id>
		<title>Characters</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Characters&amp;diff=9123"/>
		<updated>2019-05-01T17:25:18Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* 0.18 adjustment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Main character and family ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Main Character icon.png|link=[[Main Character]]|[[Main Character]]&lt;br /&gt;
File:Father icon.png|link=[[Father]]|[[Father]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Housemates and close friends ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Debbie icon.png|link=[[Debbie]]|[[Debbie]]&lt;br /&gt;
File:Jenny icon.png|link=[[Jenny]]|[[Jenny]]&lt;br /&gt;
File:Diane icon.png|link=[[Diane]]|[[Diane]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Students ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Annie icon.png|link=[[Annie]]|[[Annie]]&lt;br /&gt;
File:Becca icon.png|link=[[Becca]]|[[Becca]]&lt;br /&gt;
File:Chad icon.png|link=[[Chad]]|[[Chad]]&lt;br /&gt;
File:Chico icon.png|link=[[Chico]]|[[Chico]]&lt;br /&gt;
File:Dexter icon.png|link=[[Dexter]]|[[Dexter]]&lt;br /&gt;
File:Erik icon.png|link=[[Erik]]|[[Erik]]&lt;br /&gt;
File:Eve icon.png|link=[[Eve]]|[[Eve]]&lt;br /&gt;
File:Judith icon.png|link=[[Judith]]|[[Judith]]&lt;br /&gt;
File:June icon.png|link=[[June]]|[[June]]&lt;br /&gt;
File:Kevin icon.png|link=[[Kevin]]|[[Kevin]]&lt;br /&gt;
File:Lopez icon.png|link=[[Lopez]]|[[Lopez]]&lt;br /&gt;
File:Martinez icon.png|link=[[Martinez]]|[[Martinez]]&lt;br /&gt;
File:Mia icon.png|link=[[Mia]]|[[Mia]]&lt;br /&gt;
File:Missy icon.png|link=[[Missy]]|[[Missy]]&lt;br /&gt;
File:Ronda icon.png|link=[[Ronda]]|[[Ronda]]&lt;br /&gt;
File:Roxxy icon.png|link=[[Roxxy]]|[[Roxxy]]&lt;br /&gt;
File:Titty icon.png|link=[[Titty]]|[[Titty]]&lt;br /&gt;
File:Tyrone icon.png|link=[[Tyrone]]|[[Tyrone]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Teachers ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Coach Bridget icon.png|link=[[Coach Bridget]]|[[Coach Bridget]]&lt;br /&gt;
File:Ms. Bissette icon.png|link=[[Ms. Bissette]]|[[Ms. Bissette]]&lt;br /&gt;
File:Ms. Dewitt icon.png|link=[[Ms. Dewitt]]|[[Ms. Dewitt]]&lt;br /&gt;
File:Ms. Okita icon.png|link=[[Ms. Okita]]|[[Ms. Okita]]&lt;br /&gt;
File:Ms. Ross icon.png|link=[[Ms. Ross]]|[[Ms. Ross]]&lt;br /&gt;
File:Principal Smith icon.png|link=[[Principal Smith]]|[[Principal Smith]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Family of students ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Beth icon.png|link=[[Beth]]|[[Beth]]&lt;br /&gt;
File:Clyde icon.png|link=[[Clyde]]|[[Clyde]]&lt;br /&gt;
File:Crystal icon.png|link=[[Crystal]]|[[Crystal]]&lt;br /&gt;
File:Earl icon.png|link=[[Earl]]|[[Earl]]&lt;br /&gt;
File:Grace icon.png|link=[[Grace]]|[[Grace]]&lt;br /&gt;
File:Harold icon.png|link=[[Harold]]|[[Harold]]&lt;br /&gt;
File:Helen icon.png|link=[[Helen]]|[[Helen]]&lt;br /&gt;
File:Lucy icon.png|link=[[Lucy]]|[[Lucy]]&lt;br /&gt;
File:Mrs. Johnson icon.png|link=[[Mrs. Johnson]]|[[Mrs. Johnson]]&lt;br /&gt;
File:Richard icon.png|link=[[Richard]]|[[Richard]]&lt;br /&gt;
File:Consuela icon.png|link=[[Consuela]]|[[Consuela]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other characters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Sploosh icon.png|link=[[Sploosh]]|[[Sploosh|Admiral Sploosh]]&lt;br /&gt;
File:Angelica icon.png|link=[[Angelica]]|[[Angelica]]&lt;br /&gt;
File:Anna icon.png|link=[[Anna]]|[[Anna]]&lt;br /&gt;
File:Terry icon.png|link=[[Terry]]|[[Terry|Captain Terry]]&lt;br /&gt;
File:Cassie icon.png|link=[[Cassie]]|[[Cassie]]&lt;br /&gt;
File:Cedric icon.png|link=[[Cedric]]|[[Cedric]]&lt;br /&gt;
File:Henchman 1 icon.png|link=[[Henchman 1]]|[[Henchman 1]]&lt;br /&gt;
File:Henchman 2 icon.png|link=[[Henchman 2]]|[[Henchman 2]]&lt;br /&gt;
File:Ivy icon.png|link=[[Ivy]]|[[Ivy]]&lt;br /&gt;
File:Iwanka icon.png|link=[[Iwanka]]|[[Iwanka]]&lt;br /&gt;
File:Jane icon.png|link=[[Jane]]|[[Jane]]&lt;br /&gt;
File:Jaing icon.png|link=[[Jaing]]|[[Jaing]]&lt;br /&gt;
File:Josephine icon.png|link=[[Josephine]]|[[Josephine]]&lt;br /&gt;
File:Kass icon.png|link=[[Kass]]|[[Kass]]&lt;br /&gt;
File:Kim icon.png|link=[[Kim]]|[[Kim]]&lt;br /&gt;
File:Larry icon.png|link=[[Larry]]|[[Larry]]&lt;br /&gt;
File:Lilly icon.png|link=[[Lilly]]|[[Lilly]]&lt;br /&gt;
File:Liu Wang icon.png|link=[[Liu Wang]]|[[Liu Wang]]&lt;br /&gt;
File:Maria icon.png|link=[[Maria]]|[[Maria]]&lt;br /&gt;
File:Master Somrak icon.png|link=[[Somrak]]|[[Somrak|Master Somrak]]&lt;br /&gt;
File:Rump icon.png|link=[[Rump]]|[[Rump|Mayor Rump]]&lt;br /&gt;
File:Micoe icon.png|link=[[Micoe]]|[[Micoe]]&lt;br /&gt;
File:Mr. Bubbles icon.png|link=[[Mr. Bubbles]]|[[Mr. Bubbles]]&lt;br /&gt;
File:Mr. Sato icon.png|link=[[Mr. Sato]]|[[Mr. Sato]]&lt;br /&gt;
File:Pilly icon.png|link=[[Pilly]]|[[Pilly]]&lt;br /&gt;
File:Priya icon.png|link=[[Priya]]|[[Priya]]&lt;br /&gt;
File:Roz icon.png|link=[[Roz]]|[[Roz]]&lt;br /&gt;
File:Sara icon.png|link=[[Sara]]|[[Sara]]&lt;br /&gt;
File:Tony icon.png|link=[[Tony]]|[[Tony]]&lt;br /&gt;
File:Veronica icon.png|link=[[Veronica]]|[[Veronica]]&lt;br /&gt;
File:Yumi icon.png|link=[[Yumi]]|[[Yumi]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Secret characters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Aqua icon.png|link=[[Aqua]]|[[Aqua]]&lt;br /&gt;
File:Daisy icon.png|link=[[Daisy]]|[[Daisy]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Pets ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;nolines&amp;quot; heights=100px&amp;gt;&lt;br /&gt;
File:Awesomo icon.png|link=[[Awesomo]]|[[Awesomo]]&lt;br /&gt;
File:Dogeek icon.png|link=[[Dogeek]]|[[Dogeek]]&lt;br /&gt;
File:Konterina icon.png|link=[[Konterina]]|[[Konterina]]&lt;br /&gt;
File:Pussywillow icon.png|link=[[Pussywillow]]|[[Pussywillow]]&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview table for characters the players can engage with ==&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;col&amp;quot; style=&amp;quot;color:white; background-color:#3f4562;&amp;quot; | Character&lt;br /&gt;
! scope=&amp;quot;col&amp;quot; style=&amp;quot;color:white; background-color:#3f4562;&amp;quot; | Route&lt;br /&gt;
! scope=&amp;quot;col&amp;quot; style=&amp;quot;color:white; background-color:#3f4562;&amp;quot; | Pregnancy&lt;br /&gt;
! scope=&amp;quot;col&amp;quot; class=&amp;quot;unsortable&amp;quot; style=&amp;quot;color:white; background-color:#3f4562;&amp;quot; | Cookie Jar scenes&lt;br /&gt;
|-&lt;br /&gt;
| [[Debbie]]&lt;br /&gt;
| [[Walkthrough#Debbie&#039;s route|Debbie&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Debbie|10]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Jenny]]&lt;br /&gt;
| [[Walkthrough#Jenny&#039;s route|Jenny&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | Yes&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Jenny|14]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Diane]]&lt;br /&gt;
| [[Walkthrough#Diane&#039;s route|Diane&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | Yes&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Diane|7]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Mrs. Johnson]]&lt;br /&gt;
| [[Walkthrough#Erik, Mrs. Johnson and June&#039;s route|Erik, Mrs. Johnson and June&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Mrs. Johnson|5]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Mia]]&lt;br /&gt;
| [[Walkthrough#Mia and Helen&#039;s route|Mia and Helen&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Mia|3]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Helen]]&lt;br /&gt;
| [[Walkthrough#Mia and Helen&#039;s route|Mia and Helen&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Helen|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Angelica]]&lt;br /&gt;
| [[Walkthrough#Mia and Helen&#039;s route|Mia and Helen&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Angelica|3]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Ivy]]&lt;br /&gt;
| None&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Ivy|4]]&lt;br /&gt;
|-&lt;br /&gt;
| [[June]]&lt;br /&gt;
| [[Walkthrough#Erik, Mrs. Johnson and June&#039;s route|Erik, Mrs. Johnson and June&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row June|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Cassie]]&lt;br /&gt;
| No route yet&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Cassie|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Roz]]&lt;br /&gt;
| [[Walkthrough#Aqua&#039;s route|Aqua&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Roz|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Judith]]&lt;br /&gt;
| No route yet&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Judith|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Ms. Bissette]]&lt;br /&gt;
| [[Walkthrough#Ms. Bissette&#039;s route|Ms. Bissette&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Ms. Bissette|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Ms. Dewitt]]&lt;br /&gt;
| [[Walkthrough#Ms. Dewitt&#039;s route|Ms. Dewitt&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Ms. Dewitt|3]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Ms. Ross]]&lt;br /&gt;
| [[Walkthrough#Ms. Ross&#039; route|Ms. Ross&#039; route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Ms. Ross|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Ms. Okita]]&lt;br /&gt;
| [[Walkthrough#Ms. Okita&#039;s route|Ms. Okita&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Ms. Okita|5]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Roxxy]]&lt;br /&gt;
| [[Walkthrough#Roxxy&#039;s route|Roxxy&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Roxxy|7]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Lopez]] &amp;amp; [[Martinez]]&lt;br /&gt;
| None&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Lopez &amp;amp; Martinez|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Annie]]&lt;br /&gt;
| No route yet&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Annie|2]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Eve]]&lt;br /&gt;
| No route yet&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Eve|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Becca]] &amp;amp; [[Missy]]&lt;br /&gt;
| [[Walkthrough#Roxxy&#039;s route|Roxxy&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Becca &amp;amp; Missy|4]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Crystal]]&lt;br /&gt;
| [[Walkthrough#Roxxy&#039;s route|Roxxy&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Crystal|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Micoe]]&lt;br /&gt;
| [[Walkthrough#Diane&#039;s route|Diane&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Micoe|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Daisy]]&lt;br /&gt;
| [[Walkthrough#Daisy&#039;s route|Daisy&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | Yes&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Daisy|1]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Aqua]]&lt;br /&gt;
| [[Walkthrough#Aqua&#039;s route|Aqua&#039;s route]]&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | No&lt;br /&gt;
| style=&amp;quot;text-align: center;&amp;quot; | [[Cookie Jar#Table row Aqua|3]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Jobs&amp;diff=8377</id>
		<title>Jobs</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Jobs&amp;diff=8377"/>
		<updated>2019-04-09T03:30:29Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: Undo revision 6106 by Casiope (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of the [[Minigames]] in Summertime Saga provide the player with money.&lt;br /&gt;
&lt;br /&gt;
{{Grid|&lt;br /&gt;
{{Minigame Icon|Garden Minigame}}&lt;br /&gt;
{{Minigame Icon|Pizza Delivery Minigame}}&lt;br /&gt;
{{Minigame Icon|Shooting Range Minigame}}&lt;br /&gt;
{{Minigame Icon|Fishing Minigame}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3338</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3338"/>
		<updated>2019-02-06T19:20:57Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Translating the game */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionnally, you can pass in a list to append the name of the missing keys of the dict to.&lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;text_filter&amp;quot;:&amp;quot;ikarumod_text_filter&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Text Filter ==&lt;br /&gt;
This key in the manifest will allow you to implement your own text filter function, without overwriting other mods&#039;.&lt;br /&gt;
If undefined, this will default to &amp;lt;code&amp;gt;lambda text:text&amp;lt;/code&amp;gt;, otherwise the value of this key should be a string of the name of the function you wish to pass in as a text filter. If the function cannot be found in the global namespace (i.e. the globals() dictionnary), then a &amp;lt;code&amp;gt;ModLoaderError(&amp;quot;No Function named {text_filter} found in the global namespace. Is it defined properly?&amp;quot;)&amp;lt;/code&amp;gt; exception will be raised.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;br /&gt;
&lt;br /&gt;
== For location names ==&lt;br /&gt;
&lt;br /&gt;
In an &amp;lt;code&amp;gt;init 1 python&amp;lt;/code&amp;gt; (or later) block, you can set the display name of any Location object in the game like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init -1 python:&lt;br /&gt;
    L_map.display_name = &amp;quot;New Map Name&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will allow you to rename/translate any location in the game, thus displaying that name in relevant parts of the UI.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=User:Dogeek&amp;diff=3332</id>
		<title>User:Dogeek</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=User:Dogeek&amp;diff=3332"/>
		<updated>2019-01-28T07:53:07Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox_character&lt;br /&gt;
 | name         = Dogeek&lt;br /&gt;
 | aliases      = Code Guru&lt;br /&gt;
 | gender       = Male&lt;br /&gt;
 | occupation   = Lead Coder&lt;br /&gt;
 | birthday     = February 17th&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Lead Developer at Kompas Productions.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=User:Dogeek&amp;diff=3324</id>
		<title>User:Dogeek</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=User:Dogeek&amp;diff=3324"/>
		<updated>2019-01-15T03:39:46Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: Created page with &amp;quot;Lead Developer at Kompas Productions.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lead Developer at Kompas Productions.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3310</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3310"/>
		<updated>2019-01-11T21:24:53Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Text Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionnally, you can pass in a list to append the name of the missing keys of the dict to.&lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;text_filter&amp;quot;:&amp;quot;ikarumod_text_filter&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Text Filter ==&lt;br /&gt;
This key in the manifest will allow you to implement your own text filter function, without overwriting other mods&#039;.&lt;br /&gt;
If undefined, this will default to &amp;lt;code&amp;gt;lambda text:text&amp;lt;/code&amp;gt;, otherwise the value of this key should be a string of the name of the function you wish to pass in as a text filter. If the function cannot be found in the global namespace (i.e. the globals() dictionnary), then a &amp;lt;code&amp;gt;ModLoaderError(&amp;quot;No Function named {text_filter} found in the global namespace. Is it defined properly?&amp;quot;)&amp;lt;/code&amp;gt; exception will be raised.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3309</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3309"/>
		<updated>2019-01-11T21:24:10Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Hooking into the game */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionnally, you can pass in a list to append the name of the missing keys of the dict to.&lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;text_filter&amp;quot;:&amp;quot;ikarumod_text_filter&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Text Filter ==&lt;br /&gt;
This key in the manifest will allow you to implement your own text filter function, without overwriting other mods&#039;.&lt;br /&gt;
If undefined, this will default to &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;lambda text:text&amp;lt;/syntaxhighlight&amp;gt;, otherwise the value of this key should be a string of the name of the function you wish to pass in as a text filter. If the function cannot be found in the global namespace (i.e. the globals() dictionnary), then a &amp;lt;code&amp;gt;ModLoaderError(&amp;quot;No Function named {text_filter} found in the global namespace. Is it defined properly?&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3308</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3308"/>
		<updated>2019-01-11T21:19:59Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Example of a manifest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionnally, you can pass in a list to append the name of the missing keys of the dict to.&lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;text_filter&amp;quot;:&amp;quot;ikarumod_text_filter&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3307</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3307"/>
		<updated>2019-01-11T21:19:23Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Miscellaneous functions and classes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None, list list_to_append=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 253 (hard limit in CPython). Additionnally, you can pass in a list to append the name of the missing keys of the dict to.&lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, list_to_append=missing_keys)&lt;br /&gt;
# appends &amp;quot;c&amp;quot; to list missing keys and returns None. If a default argument is passed, will return default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3306</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3306"/>
		<updated>2019-01-11T02:40:19Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Miscellaneous functions and classes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 254 (hard limit in CPython). &lt;br /&gt;
&#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
# returns 2&lt;br /&gt;
safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
# prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3305</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3305"/>
		<updated>2019-01-11T02:39:49Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Miscellaneous functions and classes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
safe_parse_dict(dict dct, object* keys, object default=None) : returns the content of the dict at keys keys, subscripted in order. If a KeyError exception is raised, and a default is provided, then will return that default object. Any number of keys can be passed up to 254 (hard limit in CPython). &lt;br /&gt;
:: &#039;&#039;&#039;Examples :&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
    safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;c&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
    # returns &amp;quot;default return value&amp;quot;&lt;br /&gt;
    safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, default=&amp;quot;default return value&amp;quot;)&lt;br /&gt;
    # returns 2&lt;br /&gt;
    safe_parse_dict({&amp;quot;a&amp;quot;:{&amp;quot;b&amp;quot;:2}}, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;default return value&amp;quot;)&lt;br /&gt;
    # prints &amp;quot;Extra positionnal argument passed, is default properly named in the arguments?&amp;quot; and returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3304</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3304"/>
		<updated>2019-01-10T19:55:08Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* For cutscenes, and minigame instructions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_1[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3287</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3287"/>
		<updated>2019-01-09T17:42:35Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* FSMs (Finite State Machines) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
The Machine class defines a lot of methods that might prove useful :&lt;br /&gt;
&lt;br /&gt;
:: set_priority(int priority) : Sets the priority of the machine. Currently used to display the hints on the phone. A machine with a priority of 1 or more will show up in the phone. Later, this may be used to sort quests into main quests and side quests.&lt;br /&gt;
:: property button_dialogue : returns the button dialogue for that machine (machine name + &amp;quot;_button_dialogue&amp;quot;), used in the TalkTo screen action.&lt;br /&gt;
:: image, show, say, and hide : now defunct methods.&lt;br /&gt;
:: property progress : returns an integer that is the progress out of a 100%.&lt;br /&gt;
:: add_action(*actions) : adds a Machine action to this Machine.&lt;br /&gt;
:: set_state(State state, bool null_delay=False) : reverts the machine to init, then advances the machine until it is in the state &#039;&#039;&#039;state&#039;&#039;&#039;. If null_delay is True, then set the delay of the state reached to 0.&lt;br /&gt;
:: machine_trigger : trigger for machine actions.&lt;br /&gt;
:: trigger(Trigger trigger, bool noactions=False) : triggers the machine to pass onto the next state. If noaction is True, don&#039;t process the actions&lt;br /&gt;
:: add(State* states) : add the states to the machine.&lt;br /&gt;
:: get(string var), set(string var, object value) : gets and sets the machine variable var.&lt;br /&gt;
:: get_state() : returns the State the machine is in.&lt;br /&gt;
:: property where : computes where the machine should be based on her default location, time of day, day of week, forced location and if it&#039;s forced or not for that time of day. Returns a location.&lt;br /&gt;
:: is_state(State* states), between_states(State stateBegin, State* statesEnd), finished_state(State* states) : returns boolean if the machine is in any of the provided states, between stateBegin and any of the statesEnd(non inclusive) and if the machine has finished any of the states provided, respectfully.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Example of an FSM ===&lt;br /&gt;
&lt;br /&gt;
Below is the code for [[Cassie]]&#039;s FSM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    T_cassie_ban_mc = Trigger(&amp;quot;ban mc&amp;quot;)&lt;br /&gt;
    T_cassie_lift_ban = Trigger(&amp;quot;lift ban&amp;quot;)&lt;br /&gt;
    T_cassie_drowning = Trigger(&amp;quot;drowning&amp;quot;)&lt;br /&gt;
    T_cassie_end = Trigger(&amp;quot;end&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
label cassie_fsm_init:&lt;br /&gt;
    python:&lt;br /&gt;
        # Cassie&#039;s States&lt;br /&gt;
        S_cassie_start = State(&amp;quot;start&amp;quot;)&lt;br /&gt;
        S_cassie_ban_from_pool = State(&amp;quot;ban from pool&amp;quot;, &amp;quot;You should go to the pool at night...&amp;quot;)&lt;br /&gt;
        S_cassie_caught_skinny_dipping = State(&amp;quot;caught skinny dipping&amp;quot;, &amp;quot;Cassie lifted your ban! Go for a swim!&amp;quot;)&lt;br /&gt;
        S_cassie_medic_room = State(&amp;quot;medic room&amp;quot;, &amp;quot;Have fun in the medic room...&amp;quot;)&lt;br /&gt;
        S_cassie_end = State(&amp;quot;end&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
        # Build out Cassie&#039;s FSM&lt;br /&gt;
        S_cassie_start.add(T_cassie_ban_mc, S_cassie_ban_from_pool)&lt;br /&gt;
        S_cassie_ban_from_pool.add(T_cassie_lift_ban, S_cassie_caught_skinny_dipping)&lt;br /&gt;
        S_cassie_caught_skinny_dipping.add(T_cassie_drowning, S_cassie_medic_room)&lt;br /&gt;
        S_cassie_medic_room.add(T_cassie_end, S_cassie_end, actions=[&amp;quot;exec&amp;quot;, A_drowning_in_pussy.unlock])&lt;br /&gt;
        &lt;br /&gt;
        M_cassie.add(S_cassie_start, S_cassie_ban_from_pool, &lt;br /&gt;
                     S_cassie_caught_skinny_dipping,&lt;br /&gt;
                     S_cassie_medic_room, S_cassie_end)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
label cassie_machine_init:&lt;br /&gt;
    python:&lt;br /&gt;
        M_cassie = Machine(&amp;quot;cassie&amp;quot;, default_loc=[[L_pool, L_pool, L_pool, L_NULL]],&lt;br /&gt;
                         vars={&#039;sex speed&#039;: .3,&lt;br /&gt;
                               &#039;had sex&#039;: False},&lt;br /&gt;
        )&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At init time, all the triggers are created. It&#039;s important that triggers be created at an init time of &#039;&#039;&#039;0 or later&#039;&#039;&#039;, sine the Trigger class is defined in an init -2 python block, and other parts of FSMs in an init -1 python block.&lt;br /&gt;
&lt;br /&gt;
On starting the game, and on loading a save file/reloading the game, the states are created and linked together, but after the machine itself is initialized. In the above example, here is the order :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;init (triggers) &amp;gt; call (after_load/start) &amp;gt; call cassie_machine_init &amp;gt; call cassie_fsm_init&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In the example, the machine is named &amp;quot;M_cassie&amp;quot; and is given the name &amp;quot;cassie&amp;quot;. This name is used in several places throughout the code to refer to that object. Furthermore, her default location (the default_loc argument) specifies that she will be in the pool from morning to evening, and nowhere in the night. A dictionnary is initialized as well, to keep track of some other variables, like for instance, the sex speed for the animations, whether or not the character had sex with that character, variables to trigger repeatable dialogues, counters etc.&lt;br /&gt;
In the same label, you can also set up the outfit system of that character, as seen in the next section, or add machine actions to the FSM. This is also the place to set the priority of the FSM.&lt;br /&gt;
&lt;br /&gt;
In the cassie_fsm_init label, you&#039;re supposed to create your states, and link them together. As you can see, the last link has a state action attached to it, which means that on reaching the S_cassie_end state, the machine will automatically call the unlock method of the &#039;&#039;&#039;A_drowning_in_pussy&#039;&#039;&#039; achievement. In the same fashion, other state actions may be defined. &lt;br /&gt;
&lt;br /&gt;
Here are some other examples from the game :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_drunken_splur.add(T_diane_help_carry_to_bed, S_diane_get_cold_towel,&lt;br /&gt;
                                  actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_diane_bedroom},&lt;br /&gt;
                                             &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: [0,1]},&lt;br /&gt;
                                             ]&lt;br /&gt;
                                  )&lt;br /&gt;
        S_diane_milking_help.add(T_diane_milking_malfunction_help, S_diane_debbie_evening_visit,&lt;br /&gt;
                                 actions = [&amp;quot;location&amp;quot;, {&amp;quot;place&amp;quot;: L_home_kitchen,&lt;br /&gt;
                                                         &amp;quot;condition&amp;quot;: &amp;quot;not M_diane.is_set(&#039;first cucumber&#039;)&amp;quot;,&lt;br /&gt;
                                                         },&lt;br /&gt;
                                            &amp;quot;force&amp;quot;, {&amp;quot;tod&amp;quot;: 2},&lt;br /&gt;
                                            ]&lt;br /&gt;
                                 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_look_in_kitchen.add(T_diane_search_kitchen, S_diane_seen_cucumber,&lt;br /&gt;
                                    actions = [&amp;quot;action&amp;quot;, [M_player, &amp;quot;set&amp;quot;, &amp;quot;jerk diane&amp;quot;]&lt;br /&gt;
                                               ]&lt;br /&gt;
                                    )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
        S_diane_fetch_pump.add(T_diane_found_pump, S_diane_delivery_2_task,&lt;br /&gt;
                               actions = [&amp;quot;setdefaultloc&amp;quot;, [[L_diane_shed, L_diane_shed, L_diane_shed, L_diane_bedroom]]]&lt;br /&gt;
                               )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3285</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3285"/>
		<updated>2019-01-06T20:34:58Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* For cutscenes, and minigame instructions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3284</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3284"/>
		<updated>2019-01-06T20:29:48Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: translating guide&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;br /&gt;
&lt;br /&gt;
= Translating the game =&lt;br /&gt;
&lt;br /&gt;
== Label calling in the game ==&lt;br /&gt;
&lt;br /&gt;
The game has a function in the Game class to select different dialogues based on the language class attribute defined there. To change that attribute, it&#039;s just a matter of writing this piece of code in a separate &amp;quot;.rpy&amp;quot; file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 1 python:&lt;br /&gt;
    Game.language = &amp;quot;es&amp;quot; # for spanish for instance, &amp;quot;fr&amp;quot; for french, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will then, every time a dialogue is called, look for the label name + the language string at the end. For instance, the label &amp;quot;bank_liu_account_info&amp;quot; has the english version in, to overwrite that dialogue, you&#039;d have &amp;quot;bank_liu_account_info_fr&amp;quot; or &amp;quot;bank_liu_account_info_es&amp;quot; depending on the value of the language string.&lt;br /&gt;
&lt;br /&gt;
This method can be used to translate any dialogue in the game. It is advised to keep a consistent directory structure, because there are a lot of dialogues in the game. You&#039;ll also have to copy over the posing. For your convenience, every dialogue label is in a dialogues.rpy file for that location. Just copy the file and edit the dialogue and the label name.&lt;br /&gt;
&lt;br /&gt;
== For cutscenes, and minigame instructions ==&lt;br /&gt;
&lt;br /&gt;
For these cases, you can&#039;t edit the Cutscene directly. Well, to be honest, you could, but you shouldn&#039;t. The preferred way to do this will be to use the config.say_menu_text_filter variable. Just register a function to that variable that should take one argument : text, which will contain the text of the displayable. You can then edit that text how you see fit. A good way to translate would be to do something like that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init 10 python:&lt;br /&gt;
    fr_translations = {&amp;quot;Using the key and stool, I was able to get into our attic.\nI had never been up there before.\nI was filled with excitement wondering what treasures {b}[deb_name]{/b} and dad had stashed away.&amp;quot;: &amp;quot;En utilisant la clé et le tabouret, je suis allé dans le grenier.\nJe n&#039;y avais jamais été auparavent.\nJ&#039;étais excité de découvrir tous les trésors cachés par {b}[deb_name]{/b} là-haut.&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    def fr_text_filter(text):&lt;br /&gt;
        if text in fr_translations.keys():&lt;br /&gt;
            return fr_translations[text]&lt;br /&gt;
        else:&lt;br /&gt;
            return text&lt;br /&gt;
    &lt;br /&gt;
    config.say_menu_text_filter = fr_text_filter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind however that renpy won&#039;t handle dictionnaries that are too large. You can use elif statements and split the content into several dictionnaries if necessary. Below is an example of that :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
def fr_text_filter(text):&lt;br /&gt;
    if text in fr_translations_1.keys():&lt;br /&gt;
        return fr_translations_[text]&lt;br /&gt;
    elif text in fr_translations_2.keys():&lt;br /&gt;
        return fr_translations_2[text]&lt;br /&gt;
    else:&lt;br /&gt;
        return text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{color|red|FUTURE : In the future, registering to the config.say_menu_text_filter variable will be done with the &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt; assignment, to allow several mods to subscribe to it. Mod load order will apply.}}&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3283</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3283"/>
		<updated>2019-01-05T21:57:41Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* JSON Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
=== Keybindings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
This file lists the default keybindings used by the minigames.&lt;br /&gt;
&lt;br /&gt;
=== Furnishings ===&lt;br /&gt;
{{AlertWarn|This is not currently implemented in the game}}&lt;br /&gt;
&lt;br /&gt;
This file will be similar to items.json. At the moment, no furnishings have been implemented. Those will be furnishings to be put in the beach house, with an upgrade system, among other things.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3282</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3282"/>
		<updated>2019-01-05T21:52:49Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Outfit Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]]&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
if need be you can use del M_diane.outfit.outfits[L_home_livingroom] to revert back to the default&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3281</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3281"/>
		<updated>2019-01-05T21:51:29Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Outfit Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, [[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]])&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3280</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3280"/>
		<updated>2019-01-05T21:51:05Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Outfit Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
{{AlertInfo|Below is a copy-paste from discord, I&#039;m gonna rewrite it at some point, it gets the point accross though.}}&lt;br /&gt;
So basically how the new outfit system works&lt;br /&gt;
you have to setup the outfit manager. The outfit manager has one method called bind_outfit_to_location that takes 2 arguments : location (a Location object) and outfit (which can be an outfit string, or an outfit schedule ie a matrix just like the locations)&lt;br /&gt;
so what you do is use that method to create basically a map of outfits to use in certain conditions&lt;br /&gt;
moreover, outfits can be set with a simple state action, which takes care of calling the bind_outfit_to_location method&lt;br /&gt;
also, now, to get the outfit, it&#039;s as simple as calling M_diane.outfit.get&lt;br /&gt;
(without any parentheses, get is a property of the outfit manager)&lt;br /&gt;
the is_naked variable has also been moved to the outfit manager, because it&#039;s cleaner&lt;br /&gt;
&lt;br /&gt;
instead of M_diane.get_naked_str, you use M_diane.outfit.get&lt;br /&gt;
instead of doing M_diane.outfit = &amp;quot;whatever&amp;quot; you must configure the outfit manager&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, &amp;quot;casual&amp;quot;)&lt;br /&gt;
if you want more granularity, you can do this&lt;br /&gt;
M_diane.outfit.bind_outfit_to_location(L_home_livingroom, [[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;casual&amp;quot;, &amp;quot;casual&amp;quot;]])&lt;br /&gt;
you can even set that matrix to bean individual outfit for each time of day, each day of the week&lt;br /&gt;
as for the state action, there is &amp;quot;setnaked&amp;quot; and &amp;quot;setoutfit&amp;quot;&lt;br /&gt;
setnaked will set the machine to be naked or not, thing you can also do with M_diane.outfit.is_naked = True / False&lt;br /&gt;
True /False not True over False, it&#039;s not a division&lt;br /&gt;
and setoutfit just calls the bind_outfit_to_location method with the two arguments you specify, like so&lt;br /&gt;
actions=[&amp;quot;setoutfit&amp;quot;, [L_home_livingroom, &amp;quot;casual&amp;quot;]]&lt;br /&gt;
the Machine.outfit.get property works like that :&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
if the machine is naked&lt;br /&gt;
    return &amp;quot;naked&amp;quot;&lt;br /&gt;
otherwise if the player is in a location the outfit manager is not bound to&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return default_outfit for that day of week and time of day&lt;br /&gt;
otherwise&lt;br /&gt;
    if the outfit to be returned is &amp;quot;naked&amp;quot;, set the is_naked attribute to True, and False otherwise&lt;br /&gt;
    return outfit for that location at that day of week and time of day&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3279</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3279"/>
		<updated>2019-01-05T20:41:23Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Pregnancy Manager = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
=== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3278</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3278"/>
		<updated>2019-01-05T20:40:48Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Modding API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Summertime Saga&#039;s API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3277</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3277"/>
		<updated>2019-01-05T20:35:08Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* State specific */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
:::: if tod and dow are omitted, outfit cannot be a matrix, but only a string. You can work around that by passing the&lt;br /&gt;
:::: {&amp;quot;tod&amp;quot;:None, &amp;quot;dow&amp;quot;:None} dict.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3276</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3276"/>
		<updated>2019-01-05T20:33:13Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* State specific */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
:: [&#039;setdefaultoutfit&#039;, [outfit, {&#039;tod&#039;:tod, &#039;dow&#039;:dow}]] Sets the current machine&#039;s default outfit. &lt;br /&gt;
:::: tod and dow can be omitted. outfit is a required argument, can be a string or a 1x4,2x4,7x4 matrix.&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3275</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3275"/>
		<updated>2019-01-05T20:11:31Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Hooking into the game */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Main function name ===&lt;br /&gt;
&lt;br /&gt;
This key should be a string containing the name of the main function of your mod. The function will be searched for ini the globals() of the game (global namespace)&lt;br /&gt;
&lt;br /&gt;
=== Init label name ===&lt;br /&gt;
&lt;br /&gt;
This key should give the name of a label your mod uses at init time, which means after the game fully initializes, either at the start of the game or after the load of the game.&lt;br /&gt;
&lt;br /&gt;
This label is called in a new context, and it must return, otherwise other mods won&#039;t be loaded&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mod init order ==&lt;br /&gt;
{{AlertInfo|Mods are assumed to be in an initial random order}}&lt;br /&gt;
&lt;br /&gt;
For every mod that is enabled, create a Mod instance with that mod&#039;s name, parse the load order from the manifest, then insert that mod in the ModManager.mods list, in the proper position.&lt;br /&gt;
&lt;br /&gt;
Then, for every mod in the ModManager.mods list, call their init label, if defined.&lt;br /&gt;
&lt;br /&gt;
Finally, update the game&#039;s stores (ie achievements, items and text_messages) with every mod&#039;s data. Updates overwrite the keys, so the load order can be used to overwrite the game&#039;s (although ill-advised) or another mod&#039;s items/text_messages/achievements.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3274</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3274"/>
		<updated>2019-01-05T19:40:30Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* State specific */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
:: [&#039;setnaked&#039;, True/False] Sets the is_naked attribute of the current machine&#039;s outfit manager to True/False&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3273</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3273"/>
		<updated>2019-01-05T19:09:21Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Example of a manifest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;achievements&amp;quot;:{&lt;br /&gt;
        &amp;quot;angler-2&amp;quot;{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3272</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3272"/>
		<updated>2019-01-05T17:59:34Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Outfit Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to &amp;lt;nowiki&amp;gt;[[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3271</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3271"/>
		<updated>2019-01-05T17:58:54Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Outfit Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Init arguments:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : defaults to [[&amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;, &amp;quot;dressed&amp;quot;]]&lt;br /&gt;
:: is_naked : defaults to False&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3270</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3270"/>
		<updated>2019-01-05T17:45:02Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
:: [&#039;setoutfit&#039;, [location, outfit]] Sets the outfit for that location. Outfit may be either a string, or &lt;br /&gt;
:::: or a 1x4,2x4,7x4 array of strings (similar to the locations)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Outfit Manager ===&lt;br /&gt;
&lt;br /&gt;
Every FSM has an OutfitManager instance attached to it. The outfit system is designed a bit like the Location system, in that each outfit has a specific time of day/day of week schedule for which the character is wearing that outfit. In addition, the outfit manager also takes into account the location the player is currently in. The outfit manager also handles whether the character is naked or not, with the &amp;lt;code&amp;gt;is_naked&amp;lt;/code&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
To bind an outfit &amp;quot;schedule&amp;quot; to a location, use the method &amp;lt;code&amp;gt;bind_outfit_to_location&amp;lt;/code&amp;gt;, with the arguments being first, the location and second the outfit string/schedule.&lt;br /&gt;
&lt;br /&gt;
An outfit schedule is very similar to a Location schedule, it&#039;s a 1x4/2x4/7x4 matrix of strings, each of those strings being the outfit of a given pair of time of day/day of week.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Methods and attributes:&#039;&#039;&#039;&lt;br /&gt;
:: default_outfit : the outfit schedule that will be used if the character is in a location not in the table of outfits for thatt character.&lt;br /&gt;
:: is_naked : pretty self-explanatory. Boolean that tells if the machine is naked or not.&lt;br /&gt;
:: bind_outfit_to_location(Location location, object outfit_schedule) : Will bind the given outfit schedule to the given location. The outfit schedule may be one of the following : a string, a 1x4 matrix, a 2x4 matrix or a 7x4 matrix of strings.&lt;br /&gt;
:: format_outfit_schedule(object outfit_schedule) : formats the outfit schedule to a 7x4 matrix of strings. Used internally.&lt;br /&gt;
:: property get() : returns the proper outfit given the current time of day, day of week, whether the machine is naked or not and player location.&lt;br /&gt;
&lt;br /&gt;
== Pregnancy Manager ===&lt;br /&gt;
&lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3251</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3251"/>
		<updated>2019-01-04T15:50:26Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Directory Structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio &lt;br /&gt;
:::::: sfx and musics&lt;br /&gt;
:::: fonts &lt;br /&gt;
:::::: fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements &lt;br /&gt;
:::::::: achievement-related images&lt;br /&gt;
:::::: cookie_jar &lt;br /&gt;
:::::::: cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds &lt;br /&gt;
:::::::: backgrounds and close-ups&lt;br /&gt;
:::::: boxes &lt;br /&gt;
:::::::: popups go in this folder, as well as general purpose buttons (like the go back button)&lt;br /&gt;
:::::: buttons &lt;br /&gt;
:::::::: most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone &lt;br /&gt;
:::::::: cellphone images assets&lt;br /&gt;
:::::: characters &lt;br /&gt;
:::::::: character poses. One folder per character.&lt;br /&gt;
:::::: map &lt;br /&gt;
:::::::: map assets (locations and map background)&lt;br /&gt;
:::::: objects &lt;br /&gt;
:::::::: character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx &lt;br /&gt;
:::::::: special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages &lt;br /&gt;
:::::: third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3250</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3250"/>
		<updated>2019-01-04T15:48:28Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Directory Structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio : sfx and musics&lt;br /&gt;
:::: fonts : fonts for the game&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements : achievement-related images&lt;br /&gt;
:::::: cookie_jar : cookie jar buttons, popups and thumbnails&lt;br /&gt;
:::::: backgrounds : backgrounds and close-ups&lt;br /&gt;
:::::: boxes : popups&lt;br /&gt;
:::::: buttons : most minigame assets, menu buttons.&lt;br /&gt;
:::::: cellphone : cellphone images assets&lt;br /&gt;
:::::: characters : character poses. One folder per character.&lt;br /&gt;
:::::: map : map assets (locations and map background)&lt;br /&gt;
:::::: objects : character buttons, item buttons, doors etc&lt;br /&gt;
:::::: vfx : special visual effects (like the rain in roxxy&#039;s camping scene)&lt;br /&gt;
:::: python-packages : third party python modules&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3249</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3249"/>
		<updated>2019-01-04T09:16:44Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== JSON Data ==&lt;br /&gt;
&lt;br /&gt;
=== Items and inventory management ===&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
=== Text Messages ===&lt;br /&gt;
Text messages are stored in this format in the text_messages.json file. Once defined there, you can use the player.receive_message(message_id) for the player to receive the message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;mia02&amp;quot;: {&lt;br /&gt;
    &amp;quot;sender&amp;quot;: &amp;quot;mia&amp;quot;,&lt;br /&gt;
    &amp;quot;content_preview&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...&amp;quot;,&lt;br /&gt;
    &amp;quot;content&amp;quot;: &amp;quot;We can&#039;t find {b}my dad{/b}...\nCan you come help us please?&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;cellphone/cellphone_text_mia01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* mia02 : the message identifier. Must be unique. Message identifiers ending in &amp;quot;_pregnancy&amp;quot; or &amp;quot;_pregnancy_labor&amp;quot; are reserved for the pregnancy system&#039;s messages. &lt;br /&gt;
* sender : the name of the machine that sent this message.&lt;br /&gt;
* content_preview : the short text you see on the main messages screen on the cellphone.&lt;br /&gt;
* content : the actual message you see when clicking the message in the phone.&lt;br /&gt;
* image : the image used as a &amp;quot;profile picture&amp;quot; on the cellphone.&lt;br /&gt;
&lt;br /&gt;
=== Achievements ===&lt;br /&gt;
&lt;br /&gt;
Achievements are defined in &amp;quot;achievements.json&amp;quot;, here is an example of the data :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;angler&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;The Angler&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Catch one of every type of fish.&amp;quot;,&lt;br /&gt;
    &amp;quot;hidden&amp;quot;: false,&lt;br /&gt;
    &amp;quot;enabled&amp;quot;: true,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;achievements/cellphone_achieve_01.png&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* angler : the identifier of this achievement. Must be unique. The identifier is used to name the achievement variable. dashes are replaced with underscores. All achievements are prefixed with &amp;quot;A_&amp;quot;.&lt;br /&gt;
* id : a numeric id. Unused.&lt;br /&gt;
* name : the achievement&#039;s name&lt;br /&gt;
* description : the achievement&#039;s description. New lines are inserted every 30 characters, words are not split in the middle.&lt;br /&gt;
* hidden : whether it&#039;s a secret achievement or not.&lt;br /&gt;
* enabled : if the achievement can be achieved.&lt;br /&gt;
* image : the icon for this achievement. &lt;br /&gt;
&lt;br /&gt;
=== Dialogues ===&lt;br /&gt;
The dialogues.json file is used for Admiral Sploosh&#039;s dialogue lines, written by patreons.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
=== Adding to the game&#039;s json files ===&lt;br /&gt;
&lt;br /&gt;
Keys in the manifest named &amp;quot;items&amp;quot;, &amp;quot;achievements&amp;quot; and &amp;quot;text_messages&amp;quot; can be used to add data to the game&#039;s json files.&lt;br /&gt;
Each of these keys expects a full json dictionnary, formatted just like their respective models.&lt;br /&gt;
&lt;br /&gt;
=== Example of a manifest ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;:&amp;quot;ikarumod&amp;quot;,&lt;br /&gt;
    &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,&lt;br /&gt;
    &amp;quot;load_order&amp;quot;: &amp;quot;&amp;gt;3&amp;quot;,&lt;br /&gt;
    &amp;quot;main_function_name&amp;quot;: &amp;quot;ikarumod_main&amp;quot;,&lt;br /&gt;
    &amp;quot;init_label_name&amp;quot;:&amp;quot;ikarumod_init_label&amp;quot;,&lt;br /&gt;
    &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;item1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;item2&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;text_messages&amp;quot;:{&lt;br /&gt;
        &amp;quot;text_message1&amp;quot;:{&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;screen_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;upstairs_bedroom&amp;quot;:&amp;quot;upstairs_bedroom_ikarumod&amp;quot;,&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;label_hooks&amp;quot;:{&lt;br /&gt;
        &amp;quot;bedroom&amp;quot;:&amp;quot;bedroom_ikarumod&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3248</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3248"/>
		<updated>2019-01-04T08:50:07Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: /* Items and inventory management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
    &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
    &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
    &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
    &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
    &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3247</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3247"/>
		<updated>2019-01-04T08:42:51Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
:: &amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
:::: &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
:::: &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
:::: &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
:::: &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
:::: &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
:::: &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
:::: &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
:::: &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
:: }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
=== Preferred mod load order ===&lt;br /&gt;
&lt;br /&gt;
Adding a key named load_order to the manifest will allow your mod to be loaded after a specific amount of mods, or before.&lt;br /&gt;
The value of this key must be a string leading with either &amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot; or &amp;quot;=&amp;quot; followed by an integer. Additionnally, the values &amp;quot;inf&amp;quot; and &amp;quot;-inf&amp;quot; can be used to set the load order as last, and absolutely first. If several mods are found with the &amp;quot;-inf&amp;quot; load_order, a random order is chosen. This defaults at &amp;quot;inf&amp;quot;, which means the mods will be added last to the list in no particular order.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3246</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3246"/>
		<updated>2019-01-04T08:35:34Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
:: &amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
:::: &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
:::: &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
:::: &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
:::: &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
:::: &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
:::: &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
:::: &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
:::: &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
:: }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3245</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3245"/>
		<updated>2019-01-04T08:35:08Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
:: &amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
:::: &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
:::: &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
:::: &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
:::: &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
:::: &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
:::: &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
:::: &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
:::: &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
:: }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AltertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AlertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3244</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3244"/>
		<updated>2019-01-04T08:34:27Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Editing an FSM ===&lt;br /&gt;
&lt;br /&gt;
Editing a currently existing FSM is actually as simple as calling the &amp;lt;code&amp;gt;clear()&amp;lt;/code&amp;gt; method of the state you want to clear. It takes one argument, cleardelay, which defaults to False. If cleardelay is True, then the delay of the state will be cleared. If you don&#039;t want to edit the state, but just want to clear the delay, you can just set the State.delay attribute to 0 instead.&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve cleared the state, the state will be unlinked to the rest of the FSM, which means that story will block at that state, it&#039;s then up to you to link that state to the rest of the machine, with addtionnal states in the middle for your code.&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
:: &amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
:::: &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
:::: &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
:::: &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
:::: &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
:::: &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
:::: &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
:::: &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
:::: &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
:: }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
:: increase_str(int amount) : increase the strength by amount. Defaults to 1. Smilar methods exist for int, chr and dex.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
{{AltertWarn|This feature of the modding API is not complete as of version 0.18.0, the ModManager class is present, but no hooking of any kind can be done at the moment. This message will be deleted once everything is in place}}&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Manifest file ==&lt;br /&gt;
{{AltertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
The manifest file will tell the game in which labels your mod should hook into, and which screens. It will also define the name of the main function you wish to use to hook into the game.main() function, if any.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
{{AltertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
{{AltertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
{{AltertInfo|Not implemented at this time}}&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
	<entry>
		<id>https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3214</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.summertimesaga.com/index.php?title=Modding&amp;diff=3214"/>
		<updated>2019-01-02T07:21:22Z</updated>

		<summary type="html">&lt;p&gt;Dogeek: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{AlertInfo|This page was last updated as of Summertime Saga v0.18.0}}&lt;br /&gt;
&lt;br /&gt;
= Modding API =&lt;br /&gt;
&lt;br /&gt;
{{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}}&lt;br /&gt;
&lt;br /&gt;
== FSMs (Finite State Machines) ==&lt;br /&gt;
&lt;br /&gt;
FSMs control the flow of the game for a particular character. They are basically linked chains of events (which are called States). The progress is achieved via a Trigger.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;[[File:Fsm1.png]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot; style=&amp;quot;width: auto; margin-left: auto; margin-right: auto;&amp;quot;&amp;gt;&#039;&#039;A basic example of a FSM&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a FSM ===&lt;br /&gt;
Creating a FSM is done in 3 steps :&lt;br /&gt;
&lt;br /&gt;
* Create the states, triggers and a Machine instance, providing the necessary arguments to each constructor. Triggers should be created in an init python block of priority 0 or later.&lt;br /&gt;
&lt;br /&gt;
* Link the states together, with their &#039;&#039;&#039;State.add(Trigger t, State next_state)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
* Add all the states to the machine with the &#039;&#039;&#039;Machine.add(*State states)&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
State and machine definition and state linking should be done in a label named &amp;quot;character_fsm_init&amp;quot;, character being the character&#039;s name. Additionally, further edits to the machine (such as adding the states) should be done in a label named &amp;quot;character_machine_init&amp;quot;, there again, character being the name of the character.&lt;br /&gt;
&lt;br /&gt;
==== Machine specific ====&lt;br /&gt;
&lt;br /&gt;
The Machine constructor has plenty of arguments, here is the detail and what is expected :&lt;br /&gt;
&lt;br /&gt;
:: name : a name for the machine. Is used as a unique identifier for the machine. Will also be used to find the button dialogue for that machine.&lt;br /&gt;
:: default_loc : a 4x7 matrix of Locations to be used as the &amp;quot;schedule&amp;quot; for where a given machine should be at any point during the week. A 4x1 or 2x4 matrix may be passed as well, and internally will be converted to a 4x7 matrix. If a 1x4 matrix is passed, it is assumed that the location only varies by time of day, and the day of the week doesn&#039;t matter. A 2x4 matrix will split the two, the first 4-list is for weekdays, and the second for weekend days.&lt;br /&gt;
:: description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.&lt;br /&gt;
:: vars : A dictionnary containing variables (as strings, the keys of that dictionnary), and init values for those variables. These variables are used with the state actions (see below) and the &#039;&#039;&#039;get(string variable)&#039;&#039;&#039; and &#039;&#039;&#039;set(string variable, object value)&#039;&#039;&#039; methods of the Machine class. When a specific state doesn&#039;t apply, or you need a variable to change based on the progress with a given path. The &amp;quot;sex speed&amp;quot; variable is assumed to be used only for setting the speed of the animation for sex scenes.&lt;br /&gt;
&lt;br /&gt;
==== State specific ====&lt;br /&gt;
&lt;br /&gt;
At state creation, you may want to add a delay to that state using the delay optional argument. That delay is the number of days until that state is effectively reached once the trigger has been &amp;quot;pulled&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When linking states together, you may want to add &#039;&#039;&#039;state actions&#039;&#039;&#039; to be executed when the state is triggered. Those actions are as follows :&lt;br /&gt;
&lt;br /&gt;
:: [&#039;set&#039;,&#039;flag_1&#039;]  set&#039;s the value of flag_1 to True&lt;br /&gt;
:: [&#039;clear&#039;,&#039;flag_1&#039;] set&#039;s the value of flag_1 to False&lt;br /&gt;
:: [&#039;toggle&#039;,&#039;flag_1&#039;] toggle&#039;s the value of flag_1 between True and False&lt;br /&gt;
:: [&#039;assign&#039;,[&#039;v1&#039;,100]] sets the value of v1 to 100&lt;br /&gt;
:: [&#039;inc&#039;,&#039;v1&#039;] increase the value of v1 by 1&lt;br /&gt;
:: [&#039;dec&#039;,&#039;v1&#039;] decrease the value of v1 by 1&lt;br /&gt;
:: [&#039;triggeronzero&#039;:[&#039;v1&#039;,T_a_trigger]] sets v1 -= 1 and if&lt;br /&gt;
:::: v1 &amp;lt;= 0 it will fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;trigger&#039;,T_a_trigger], fire the Trigger T_a_trigger&lt;br /&gt;
:: [&#039;call&#039;,&#039;label&#039;], make a RenPy call to label. Label MUST return&lt;br /&gt;
:: [&#039;location&#039;, [machine, {&amp;quot;tod&amp;quot;:tod, &amp;quot;place&amp;quot;:place}]], set the forced location for the&lt;br /&gt;
:::: machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)&lt;br /&gt;
:: [&#039;force&#039;, [machine, {&amp;quot;tod&amp;quot;: list or int, &amp;quot;flag&amp;quot;: 4-list or bool}]]&lt;br /&gt;
::::  Says if the location is forced at tod or sets force flags according to the 4-list provided&lt;br /&gt;
:: [&#039;unforce&#039;, None/machine] unforce the locations for machine or the machine specified forced.&lt;br /&gt;
:: [&#039;exec&#039;, callable], calls the callable (function or method)&lt;br /&gt;
:: [&#039;exec&#039;, [callable, *args]], calls the callable and pass in the args specified&lt;br /&gt;
:: [&#039;condition&#039;, [condition_string, actions_list_true, actions_list_false, (optional) machine]], &lt;br /&gt;
:::: executes the actions in actions_list_true&lt;br /&gt;
:::: if condition_string evaluates to True, otherwise executes actions_list_false.&lt;br /&gt;
:::: conditions lists are assumed to be state actions.&lt;br /&gt;
:: [&#039;action&#039;, [target_machine, action, target]] Executes the state action on another machine.&lt;br /&gt;
:: [&#039;setdefaultloc&#039;, &amp;lt;nowiki&amp;gt;[[Location, Location, Location, Location]]&amp;lt;/nowiki&amp;gt;] Sets the default locations for the current machine. The argument is in the same format as the default_loc argument in the Machine constructor (1x4, 2x4 or 7x4 matrices)&lt;br /&gt;
&lt;br /&gt;
=== Using FSMs ===&lt;br /&gt;
&lt;br /&gt;
Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the &#039;&#039;&#039;is_state(State* states)&#039;&#039;&#039; method. Multiple states may be passed in that method, as well as a list of states. If the Machine is in any of the provided states, then the method will return True, and False otherwise. For convenience, other similar methods can be used. &#039;&#039;&#039;between_states(State state1, State state2)&#039;&#039;&#039; will return True if the Machine is in any state between state1 and state2 but is not in state state2. &#039;&#039;&#039;finished_state(State* states)&#039;&#039;&#039; will return True if the Machine has finished any of the provided states.&lt;br /&gt;
&lt;br /&gt;
To advance to the next state, the &#039;&#039;&#039;trigger(Trigger t)&#039;&#039;&#039; method of the Machine class is used. It will advance the Machine to the next state associated with that trigger if the provided trigger is in the current state&#039;s table, and won&#039;t do anything otherwise.&lt;br /&gt;
 &lt;br /&gt;
== Locations ==&lt;br /&gt;
&lt;br /&gt;
Locations handle all the locations in the game. They are represented as a tree, with the possibility of multiple parents (like Smith&#039;s Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Location ===&lt;br /&gt;
&lt;br /&gt;
Locations are very simple to create. It&#039;s as simple as instanciating the Location class, and providing a name for that location to the contructor (which is the only required argument). Locations are mutable, so they should be instantiated in a &amp;quot;modname_locations_init&amp;quot; label.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Locations have several optional arguments :&lt;br /&gt;
&lt;br /&gt;
:: name : the name for that location, as can be seen in the top-left corner of the UI. It&#039;s also the way to find and call the relevant location screen, as well as the location label.&lt;br /&gt;
:: unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.&lt;br /&gt;
:: background : the name of the background used for that location. The background name must follow several conventions to work properly.&lt;br /&gt;
:::: must be in images/backgrounds/&lt;br /&gt;
:::: name must start with location_&lt;br /&gt;
:::: name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)&lt;br /&gt;
:::: if the background is a halloween/christmas background, the strings &amp;quot;_halloween&amp;quot; and &amp;quot;_christmas&amp;quot; must be added before the &amp;quot;_day&amp;quot; (or &amp;quot;_night&amp;quot; etc). This will allow the game to find relevant backgrounds for the time period.&lt;br /&gt;
:::: Whatever is leftover should be provided in the background argument of the constructor. The full file path will be constructed by the background (resp. background_blur) properties.&lt;br /&gt;
:: parents : either a list of Location or a single Location instance. Will provide the parents of that Location. If left empty, the Location is assumed to be the root of the tree. The root should always be L_map (or L_NULL, but L_NULL should not have children)&lt;br /&gt;
:: locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.&lt;br /&gt;
:: label :  (to be deprecated) The label name for that location. the formatted_name property will be used later on.&lt;br /&gt;
&lt;br /&gt;
{{underline|&#039;&#039;&#039;Example :&#039;&#039;&#039;}} &amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;L_diane_barn = Location(&amp;quot;Diane&#039;s Barn&amp;quot;, unlock_popup=&amp;quot;popup_diane_barn&amp;quot;, background=&amp;quot;barn_frontyard&amp;quot;, parents=L_map, locked=True)&amp;lt;/syntaxhighlight&amp;gt; will define a location named &amp;quot;Diane&#039;s Barn&amp;quot; (formatted name being dianes_barn), child of L_map, that shows &amp;quot;popup_diane_barn&amp;quot; on unlock, and that is initially locked.&lt;br /&gt;
&lt;br /&gt;
The background is set as barn_frontyard, which means the game will look for files named &amp;quot;backgrounds/location_barn_frontyard_day.jpg&amp;quot; or &amp;quot;backgrounds/location_barn_frontyard_night.jpg&amp;quot; for instance.&lt;br /&gt;
&lt;br /&gt;
== User-defined Screen Actions ==&lt;br /&gt;
&lt;br /&gt;
These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.&lt;br /&gt;
&lt;br /&gt;
=== MoveTo ===&lt;br /&gt;
This action expects a Location to be passed. It will hide the current screen, move the player to that location, and call the corresponding screen as well as jump to the location label&lt;br /&gt;
&lt;br /&gt;
=== BuyItem ===&lt;br /&gt;
&lt;br /&gt;
This action expects an item, or item identifier string to be passed to it. When activated, will buy the item, and show the appropriate failing popups should the transaction fail. Optionally, you may add a callback label with the callback_label optionnal argument. If the transaction succeeds, the game will then call that label (useful if you want some story element to trigger after buying an item).&lt;br /&gt;
&lt;br /&gt;
=== TalkTo ===&lt;br /&gt;
&lt;br /&gt;
To be used to talk to character. Will hide the screen and start the conversation with the given character. It expects a Machine instance, or a string to identify it, in which case it will attempt to find the machine in the store.machines dictionnary.&lt;br /&gt;
&lt;br /&gt;
=== ClearPersistent ===&lt;br /&gt;
&lt;br /&gt;
Will reset the player&#039;s persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.&lt;br /&gt;
&lt;br /&gt;
=== GetItem ===&lt;br /&gt;
&lt;br /&gt;
Will get the item, and attempt to show the corresponding popup. No arguments required.&lt;br /&gt;
&lt;br /&gt;
== Items and inventory management ==&lt;br /&gt;
&lt;br /&gt;
The inventory manager is fully automatic, but you may want to add some items to the game. Items are stored in a json file called items.json in the scripts/data/ folder. A typical item definition will look like this :&lt;br /&gt;
&lt;br /&gt;
:: &amp;quot;birth_control_pills&amp;quot;: {&lt;br /&gt;
:::: &amp;quot;id&amp;quot;: &amp;quot;173&amp;quot;,&lt;br /&gt;
:::: &amp;quot;name&amp;quot;: &amp;quot;{b}Birth Control Pills:{/b}&amp;quot;,&lt;br /&gt;
:::: &amp;quot;cost&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
:::: &amp;quot;image&amp;quot;: &amp;quot;objects/item_pills3.png&amp;quot;,&lt;br /&gt;
:::: &amp;quot;description&amp;quot;: &amp;quot;Makes you temporarily sterile.&amp;quot;,&lt;br /&gt;
:::: &amp;quot;closeup&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
:::: &amp;quot;dialogue_label&amp;quot;: &amp;quot;birth_control_pills&amp;quot;,&lt;br /&gt;
:::: &amp;quot;popup_image&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
:: }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order :&lt;br /&gt;
* The item identifier.&lt;br /&gt;
* The item&#039;s id. Unused at this moment.&lt;br /&gt;
* The item&#039;s name, as seen in the backpack.&lt;br /&gt;
* The item&#039;s cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn&#039;t have sufficient money.&lt;br /&gt;
* The item&#039;s miniature image, as seen in the backpack.&lt;br /&gt;
* The item&#039;s description, as seen in the backpack.&lt;br /&gt;
* The item&#039;s closeup image, if there is one.&lt;br /&gt;
* The item&#039;s dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.&lt;br /&gt;
* The item&#039;s popup image. Shown when first acquiring the item, leave the string empty if there is none.&lt;br /&gt;
&lt;br /&gt;
FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.&lt;br /&gt;
&lt;br /&gt;
== Game manager class ==&lt;br /&gt;
&lt;br /&gt;
The Game manager class handles everything that is related to the gameplay itself, but is not planned to be extendable by mods. Its methods and attributes are still useable and should be used for your mod.&lt;br /&gt;
&lt;br /&gt;
:: language : a class-level attribute that sets the language of the game, which is used for translations. It defaults to &amp;quot;en&amp;quot; for english with other languages in the game untranslated (like spanish or french for instance)&lt;br /&gt;
:: cheat_mode : an attribute that is True if the game is currently in cheat mode (allowing minigames to be skipped)&lt;br /&gt;
:: CA_FILE : path to a certification file used to enable requests to websites. Is unused unless the player uses the &amp;quot;allow internet connection&amp;quot; checkbox in the options.&lt;br /&gt;
:: lock_ui(), unlock_ui() and ui_locked() : locks, unlocks and returns whether the ui is locked or not (i.e. grayed out)&lt;br /&gt;
:: dialog_select(string label_name) : classmethod that will choose a label based on its name and the language class attribute. To be used to split dialogues, and logic, and also allows your mod to be easily translated.&lt;br /&gt;
:: choose_label(string template) : classmethod that chooses a label at random that matches the template passed in the arguments.&lt;br /&gt;
:: main() : method that is to be called at the end of every label the player jumps to (and not &#039;&#039;&#039;called&#039;&#039;&#039; to). It calls the player&#039;s location screen, and checks for achievements and other stuff. This would be the only method expandable upon. It also clears the return stack, so that traceback are not undigestible. It may take two arguments, clear_return_stack to enable or not return stack clearing, and location, to call the screen of another location than the player&#039;s currently in.&lt;br /&gt;
:: is_christmas() and is_halloween() : classmethods that will check whether the system clock matches halloween/christmas.&lt;br /&gt;
&lt;br /&gt;
== Player class ==&lt;br /&gt;
&lt;br /&gt;
The Player class handles everything player related. It handles its inventory, grades, vehicle level and stats.&lt;br /&gt;
Notable methods :&lt;br /&gt;
&lt;br /&gt;
:: receive_message(string message_id) : player receives a message on the cellphone. Also sets up the alert icon on the UI.&lt;br /&gt;
:: has_item(string* items) : checks if the player has any of the items provided at this moment.&lt;br /&gt;
:: has_picked_up_item(string* items) : checks if the player has ever picked up any of the items provided.&lt;br /&gt;
:: get_item(string item), remove_item(string item) : gets the item, if the item&#039;s cost is no higher than the amount of money the player has. Conversely, removes an item by it&#039;s string id.&lt;br /&gt;
:: get_money(int money) and spend_money(int money) : adds and substract money from the player.&lt;br /&gt;
:: has_required_str(int min_str) : checks if the player has the required str (similar for chr, int and dex)&lt;br /&gt;
:: go_to(Location location) : goes to the given location.&lt;br /&gt;
:: go_to_previous() : goes to the first parent location of the player&#039;s current location.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions and classes ==&lt;br /&gt;
&lt;br /&gt;
KeepRefs : A class used everywhere to make sure to keep a reference to any object instantiated, making sure &#039;&#039;&#039;is&#039;&#039;&#039; checks are kept correct.&lt;br /&gt;
:: get_instances() : classmethod to get a generator of all the instances of this class&#039; subclass.&lt;br /&gt;
&lt;br /&gt;
LastUpdatedOrderedDict : A dictionnary-like structure that keeps its order, and store its items in the order the keys were last added (and not &#039;&#039;updated&#039;&#039;). This is a subclass of Python&#039;s OrderedDict from the collections package.&lt;br /&gt;
:: listvalues : returns a list of all the values of this dict&lt;br /&gt;
:: listkeys : returns a list of all the keys of this dict&lt;br /&gt;
:: lastkey : returns the last key added to this dict&lt;br /&gt;
:: lastvalue : returns the value of the last key added to this dict&lt;br /&gt;
:: isempty : returns whether the dict is empty&lt;br /&gt;
&lt;br /&gt;
format_seconds_to_dhm(int seconds) : returns a formatted string in the form (x)d (y)h (z)m from the number of seconds passed in the arguments.&lt;br /&gt;
&lt;br /&gt;
insert_newlines(string string_to_format, int every) : returns a new string based on the passed in string, with newlines inserted every &#039;&#039;every&#039;&#039; character. &#039;&#039;every&#039;&#039; defaults to 30. Differs from splice_string() in that it will not cut a word in the middle if possible. splice_string() will insert a newline every &#039;&#039;every&#039;&#039; characters without question. insert_newline() is much safer as it will not cut a variable substitution, but is much slower than splice_string.&lt;br /&gt;
&lt;br /&gt;
text_identity(string text) : returns text (unmodified), useful for config.say_menu_text_filter if it is None.&lt;br /&gt;
&lt;br /&gt;
replace_bracket(string text) : returns text without the [ and ] characters (renpy variable formatting syntax).&lt;br /&gt;
&lt;br /&gt;
gauss(float mean, float deviation, float lower, float upper) : returns a random integer number in a normal distribution, clamped between lower and upper.&lt;br /&gt;
&lt;br /&gt;
get_angle_speeds(int angle_width, Iterator angle_range, Iterator speed_range) : returns two lists, true angles and false angles which are lists of tuples (initial_angle, initial_speed) for which the result land in or out of the angle_width. Used in the pregnancy minigame and spin the bottle minigame for instance.&lt;br /&gt;
&lt;br /&gt;
= Hooking into the game =&lt;br /&gt;
&lt;br /&gt;
== Registration and Enabling of the mod ==&lt;br /&gt;
&lt;br /&gt;
In an init -9 python or later, use the class method &amp;quot;register&amp;quot; of the ModManager class to register your mod to the game.&lt;br /&gt;
This registration will make the mod show up in the (upcoming) Mods menu on the main menu of the game. From then, the player may or may not enable the mod for his game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register(&amp;quot;ikarumod&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the future, it may be necessary to create a manifest file named &amp;quot;modname_manifest.json&amp;quot; in the scripts/data folder. At this point in time, it is unnecessary, as the API is still being under developement.&lt;br /&gt;
&lt;br /&gt;
== Screens ==&lt;br /&gt;
&lt;br /&gt;
Create your screens with the following convention : modname + _ + in-game screen name (the renpy definition name).&lt;br /&gt;
Screens are being included into the main game screens with the use statement. If you wish to add new locations, you&#039;ll have to define a screen for it, in which case, you can inspire yourself with the existing screens in the game.&lt;br /&gt;
&lt;br /&gt;
To add the proper background, start with the statement &amp;quot;add player.location.background&amp;quot;, which will automatically show the proper background according to the time of day/period of the year. You can then add imagebuttons as you see fit. Please refer to the User-defined screen actions for more information on which screen actions the game defines.&lt;br /&gt;
&lt;br /&gt;
== Labels ==&lt;br /&gt;
&lt;br /&gt;
Only &amp;quot;main&amp;quot; labels can be hooked into. Those are labels that end in &amp;quot;$ game.main()&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Main function ==&lt;br /&gt;
&lt;br /&gt;
To hook into the main function, you must register your main function to the ModManager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
init python:&lt;br /&gt;
    ModManager.register_main(ikarumod_main)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above example, ikarumod_main is assumed to be a callable, which should be a python function. This function will be called with no arguments at the end of the game.main() method.&lt;br /&gt;
&lt;br /&gt;
Hooking into the main function is usually useful for code you want executed every time the game returns to a main screen, i.e. at the end of location labels for instance. This is where you can repeatedly check if the condition for an achievement has been fulfilled. If the provided function is not a callable, a ModLoaderError exception will be raised.&lt;br /&gt;
&lt;br /&gt;
= Imported modules and directory structure =&lt;br /&gt;
&lt;br /&gt;
== Third-party modules ==&lt;br /&gt;
&lt;br /&gt;
=== Platform agnostic ===&lt;br /&gt;
:: os&lt;br /&gt;
:: pygame&lt;br /&gt;
:: sys&lt;br /&gt;
:: from time : time, clock&lt;br /&gt;
:: from copy : copy, deepcopy&lt;br /&gt;
:: datetime&lt;br /&gt;
:: re&lt;br /&gt;
:: random&lt;br /&gt;
:: math&lt;br /&gt;
:: from collections : defaultdict, OrderedDict and Counter&lt;br /&gt;
:: weakref&lt;br /&gt;
:: codecs&lt;br /&gt;
:: hashlib&lt;br /&gt;
:: json&lt;br /&gt;
:: itertools&lt;br /&gt;
:: operator&lt;br /&gt;
:: textwrap&lt;br /&gt;
:: deuces&lt;br /&gt;
&lt;br /&gt;
=== Desktop builds ===&lt;br /&gt;
:: certifi&lt;br /&gt;
:: requests&lt;br /&gt;
&lt;br /&gt;
=== Mobile builds ===&lt;br /&gt;
:: android&lt;br /&gt;
:: pyjnius&lt;br /&gt;
&lt;br /&gt;
== Directory Structure ==&lt;br /&gt;
&lt;br /&gt;
:: game&lt;br /&gt;
:::: audio&lt;br /&gt;
:::: fonts&lt;br /&gt;
:::: images&lt;br /&gt;
:::::: achievements&lt;br /&gt;
:::::: backgrounds&lt;br /&gt;
:::::: boxes&lt;br /&gt;
:::::: buttons&lt;br /&gt;
:::::: cellphone&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::: map&lt;br /&gt;
:::::: objects&lt;br /&gt;
:::::: vfx&lt;br /&gt;
:::: python-packages&lt;br /&gt;
:::: scripts&lt;br /&gt;
:::::: characters&lt;br /&gt;
:::::::: One folder for each character, containing an fsm file, a character.rpy file for misc stuff, and a layeredimage definition file. May contain a file for the character&#039;s button and the according dialogues.&lt;br /&gt;
:::::: core&lt;br /&gt;
:::::::: core files are put there, mostly what has been documented in the Modding API section of this manifesto.&lt;br /&gt;
:::::: data&lt;br /&gt;
:::::::: JSON files that contain data about the game. Stuff like items, achievements, keymap or text messages are defined here.&lt;br /&gt;
:::::: defines&lt;br /&gt;
:::::::: General image definitions, transforms etc.&lt;br /&gt;
:::::: locations&lt;br /&gt;
:::::::: One folder for every location, sorted in a tree-like structure. Each location has a main file, a screen file and a dialogues file&lt;br /&gt;
:::::: minigames&lt;br /&gt;
:::::::: One folder for every minigame, the minigame dialogues and screen files are in that folder.&lt;br /&gt;
:::::: script.rpy&lt;br /&gt;
:::::: pregnancy_announcements.rpy&lt;br /&gt;
:::: changelog.txt&lt;br /&gt;
:::: pledge_list.txt&lt;/div&gt;</summary>
		<author><name>Dogeek</name></author>
	</entry>
</feed>