Modding

From Summertime Saga Wiki
Revision as of 18:55, 29 December 2018 by Dogeek (talk | contribs) (Created page with "= Modding API = {{AlertWarn|The API for Summertime Saga is currently under development, and this page is subject to many changes}} == FSMs (Finite State Machines) == FSMs c...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Modding API

The API for Summertime Saga is currently under development, and this page is subject to many changes

FSMs (Finite State Machines)

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.

Fsm1.png
A basic example of a FSM

Creating a FSM

Creating a FSM is done in 3 steps :

  • 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.
  • Link the states together, with their State.add(Trigger t, State next_state) method.
  • Add all the states to the machine with the Machine.add(*State states) method.

State and machine definition and state linking should be done in a label named "character_fsm_init", character being the character's name. Additionnally, further edits to the machine (such as adding the states) should be done in a label named "character_machine_init", there again, character being the name of the character.

Machine specific

The Machine constructor has plenty of arguments, here is the detail and what is expected :

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.
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 is 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.
description, states : (to be deprecated) alternate ways to add states to the machine, and a description that is never used anywhere.
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 get(string variable) and set(string variable, object value) 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 "sex speed" variable is assumed to be used only for setting the speed of the animation for sex scenes.

State specific

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 "pulled"

When linking states together, you may want to add state actions to be executed when the state is triggered. Those actions are as follows :

['set','flag_1'] set's the value of flag_1 to True
['clear','flag_1'] set's the value of flag_1 to False
['toggle','flag_1'] toggle's the value of flag_1 between True and False
['assign',['v1',100]] sets the value of v1 to 100
['inc','v1'] increase the value of v1 by 1
['dec','v1'] decrease the value of v1 by 1
['triggeronzero':['v1',T_a_trigger]] sets v1 -= 1 and if
v1 <= 0 it will fire the Trigger T_a_trigger
['trigger',T_a_trigger], fire the Trigger T_a_trigger
['call','label'], make a RenPy call to label. Label MUST return
['location', [machine, {"tod":tod, "place":place}]], set the forced location for the
machine to place (Moves the NPC). tod is 1-indexed (1=morning, 4=night)
['force', [machine, {"tod": list or int, "flag": 4-list or bool}]]
Says if the location is forced at tod or sets force flags according to the 4-list provided
['unforce', None/machine] unforce the locations for machine or the machine specified forced.
['exec', callable], calls the callable (function or method)
['exec', [callable, *args]], calls the callable and pass in the args specified
['condition', [condition_string, actions_list_true, actions_list_false, (optional) machine]],
executes the actions in actions_list_true
if condition_string evaluates to True, otherwise executes actions_list_false.
['action', [target_machine, action, target]] Executes the action on another machine.
['setdefaultloc', Location, Location, Location, Location] Sets the default locations for the current machine.

Using FSMs

Using FSMs is suprisingly easy. In your location labels, you can just test the state a Machine is in with the is_state(State* states) 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. between_states(State state1, State state2) will return True if the Machine is in any state between state1 and state2 but is not in state state2. finished_state(State* states) will return True if the Machine has finished any of the provided states.

To advance to the next state, the trigger(Trigger t) 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's table, and won't do anything otherwise.

Locations

Locations handle all the locations in the game. They are represented as a binary tree, with the possibility of multiple parents (like Smith's Bedroom, which has the frontyard and the hallway as its parents). A required attribute is the location name.

Creating a Location

Locations are very simple to create. It'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 "modname_locations_init" label.

Furthermore, Locations have several optionnal arguments :

name : the name for that location, as can be seen in the top-left corner of the UI. It's also the way to find and call the relevant location screen, as well as the location label.
unlock_popup : the name of a renpy-defined displayable for the popup that should show up when the location is unlocked.
background : the name of the background used for that location. The background name must follow several conventions to work properly.
must be in images/backgrounds/
name must start with location_
name must end with _day.jpg. Variants may be made for night (_night.jpg) and evening (_evening.jpg)
if the background is a halloween/christmas background, the strings "_halloween" and "_christmas" must be added before the "_day" (or "_night" etc). This will allow the game to find relevant backgrounds for the time period.
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.
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)
locked : defaults to False. Whether the Location should be initially locked, and unaccessible at the beginning of the game.
label : (to be deprecated) The label name for that location. the formatted_name property will be used later on.

User-defined Screen Actions

These screen actions are specific to Summertime Saga, and should be used to keep the flow consistent.

MoveTo

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

BuyItem

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).

TalkTo

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.

ClearPersistent

Will reset the player's persistent data (cookie jar, time spent playing, achievements etc). No arguments expected.

GetItem

Will get the item, and attempt to show the corresponding popup. No arguments required.

Items and inventory management

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 :

"birth_control_pills": {
"id": "173",
"name": "{b}Birth Control Pills:{/b}",
"cost": "0",
"image": "objects/item_pills3.png",
"description": "Makes you temporarily sterile.",
"closeup": "",
"dialogue_label": "birth_control_pills",
"popup_image": ""
}


In order :

  • The item identifier.
  • The item's id. Unused at this moment.
  • The item's name, as seen in the backpack.
  • The item's cost. Will be cast as an integer, and will prevent the player from picking up the item if he doesn't have sufficient money.
  • The item's miniature image, as seen in the backpack.
  • The item's description, as seen in the backpack.
  • The item's closeup image, if there is one.
  • The item's dialogue label, which will trigger if it exists, on clicking the item. The label should absolutely return, and take an item argument.
  • The item's popup image. Shown when first acquiring the item, leave the string empty if there is none.

FUTURE : Put your items in a file named modname_items.json, in a scripts/data folder.