Files
shweets-sim/MODDING.md
T

333 lines
21 KiB
Markdown

# Modding Shweet's Sim
Want to add characters or modify existing ones or mod Shweet's Sim in general or otherwise want to know how the game works? Here's how.
# Animation Format
Shweet's Sim uses ".anm2" files for tweened character animations, sourced from spritesheets. The format comes from the game _The Binding of Isaac: Rebirth_ (a game I mod on my own time), but the game reads the JSON flavor of it saved by my own animation editor, [Anm2Ed](https://github.com/ShweetsStuff/anm2ed). In Anm2Ed, turn on Save as JSON (Settings → Configure → Serialization), or convert an existing file with `anm2ed convert file.anm2 --format json`. Keep the `.anm2` extension. Isaac's own editor can't open these.
Anm2Ed has "Regions", which let you set spritesheet regions (areas in the spritesheet that can be repurposed) to quickly reference in animations; previously, one would have to manually create a perfectly spaced spritesheet and then manually set values; this is no longer the case, so using "Regions" is recommended.
My process for making characters is that they're typically comprised of many "cells" (small graphics). I make these cells their own file, and then in the editor, I drag them onto "Spritesheets" and then right click -> merge them, with the "Make Spritesheet Regions" option enabled. Then, right click -> Pack on a spritesheet to optimize it all nice for one big spritesheet atlas with everything in one place. It won't produce a very comprehensible spritesheet, but it works just fine (not my problem). Make sure to save the spritesheets you're using once you're done. You can sort regions around by clicking, holding and moving them around.
If you'd like a quick primer on how to use the editor, check either of [these](https://www.youtube.com/watch?v=qU_GMo2l7NY) [videos](https://www.youtube.com/watch?v=QiXVM6Gwzlw) out. They're a little out of date, but much of it still applies.
The game plays spritesheets, regions, layers, nulls, layer groups, events, trigger sounds, and the position, crop, pivot, scale, rotation, tint, color offset, visibility and easing of keyframes. It doesn't play skew, depth, blur, custom shaders or animation layers. Animation groups (the editor's folders) are fine; the game just looks animations up by name, so keep those unique.
Stage-specific character animations end with the stage's name. The first stage uses no ending.
Example:
- stage 1: `Look`
- stage 2: `LookStage2`
- stage 5: `LookStage5`
Animation names in the JSON files should still use just the base name like `Look`, `Neutral`, or `Eat`. The game appends the current stage's suffix automatically.
Know that despite Anm2Ed supporting sounds for animations, don't expect these to work in context based on names; use the JSON sound lists when applicable. You can add sounds for fluff, though (trigger sounds play).
# Resources
There's two folders inside resources; "characters" and "font".
"font" holds the one font the whole game uses (Mali, under the SIL Open Font License; see its LICENSE.txt).
"common" holds files characters share (sounds, particles, the cursor and so on). Whenever a character names a file, the game looks in the character's folder first, then in "common", so a character can use anything there as is, or replace it by having its own file at the same path. This includes the taskbar's icons, `gfx/ui/icons.anm2`: one region per icon, named after its button (`talk`, `mood`, `spawn`, `autofeed`, `home`, `stats`, `catalog`, `settings`, `cheats`, `help`, `credits`, plus whatever `icon`s the interaction types name). A character with its own `gfx/ui/icons.anm2` gets its own icons.
EVERYTHING ELSE is stored inside character folders in the "characters" folder; one folder per character, named however you like (the folder name is also the name of its save file). This has all data associated with characters. Think of characters more as tailored game experiences rather than literally being just the characters. Not only is there the character graphics, but backgrounds, items, parameters, etc. These are intensely customizable to suit whatever experience you'd like (within the confines of the engine, of course).
Shweet's Sim uses [JSON](https://en.wikipedia.org/wiki/JSON) files for its data; make sure to brush up on the format. A character folder holds these files:
- character.json
- items.json
- dialogue.json
`character.json` is required; a folder without one isn't listed. The other two are optional, but most real characters will want both.
Every path in these files is relative to the character's folder (e.g. `"sfx/blip.ogg"`), looked for there and then in "common". Paths inside an .anm2 are relative to the .anm2, and looked for the same way. Anything left out takes its default, so only write what you need.
Wherever sounds are listed, one is picked at random each time. A list can also be a single path, and a path with a `*` stands for every file it matches, e.g. `"sfx/gurgle*.ogg"`; drop a new variant in the folder and it's included.
Times are in seconds and chances in percent. The game warns (in its log) about keys it doesn't know, which are usually typos, and files it can't find.
If you're making your own character, your best bet would probably be just to copy the Mini character and edit it based on your needs, just as a helpful start.
## Fixed files and names
Some things aren't set in the data, they're always found at the same place or by the same name:
| What | Where |
|---|---|
| The character's anm2 | `gfx/character/character.anm2` |
| Select screen render and portrait | `gfx/preview/render.png` and `gfx/preview/portrait.png` (both optional) |
| The background | `gfx/areas/area.anm2`, with the world's bounds in its `Bounds` null and where items spawn in its `ItemSpawn` null |
| The cursor | `gfx/cursor/cursor.anm2`, with the animations `Default`, `Click`, `Hover` (over an item), `Grab` (an item), `Pan` (with middle mouse), `Zoom` (with the mouse wheel) and `Dispose` (right clicking an item) |
| Stage names | Stages are named `Stage1`, `Stage2` and so on. Past the first, the stage's name is added to every animation's name, and each stage's "How are you feeling?" dialogue is the pool of its name. |
| Dialogue when over capacity | An interaction plays its pool with `Full` added (e.g. `BellyRubFull`) instead, if there is one. |
# character.json
This is the main character file where much of the functionality is stored. It's read over `common/character.json`, which holds the defaults (the body's numbers, sounds, particles, the interaction types and so on), so a character only writes what it changes. Objects merge key by key (e.g. `"blink": {"destination": "Head"}` keeps the default `source`, and `"interactTypes": {"Smack": {"scaleAmplitude": 5}}` keeps the rest of Smack), while lists are replaced whole.
```json
{
"name": "Princess Mini",
"color": [0.188, 0.651, 0.424],
"weight": 40,
"weightMax": 100,
"capacity": 1250,
"stages": [45, 60, 70, 90],
"expandAreas": [{"layer": "Torso", "null": "Belly", "scaleMax": 2.5}],
"interactAreas": [{"type": "Rub", "null": "Head", "dialoguePool": "HeadRub"}]
}
```
| Key | Type | Meaning |
|---|---|---|
| `id` | string | What the character's save is named after. Defaults to the folder name; set it to keep the save when renaming the folder. |
| `name` | string | Name of the character; will appear in dialogue, stats, etc. Defaults to the folder name. |
| `description` | string | A general description of the character; will show in the Select screen. |
| `credits` | string | Credits text shown in the Select screen's Credits tab. |
| `color` | [r, g, b], 0-1 | UI accent color for the character. |
| `weight` | float, kg | The character's starting weight. |
| `weightMax` | float, kg | Maximum weight the character can reach. |
| `capacity` | float, kcal | The character's starting capacity, and the least it can go down to. |
| `capacityMax` | float, kcal | The most capacity can grow to. |
| `overstuffedMultiplier` | float | The character can eat past capacity up to capacity times this. |
| `overstuffedDigestBonus` | float | Additional capacity gained on digest when the character was over capacity (scaled by how far over). |
| `caloriesToKilogram` | float | How many kilograms each calorie digested becomes. |
| `digestionRate` | float, %/second | The base digestion rate. |
| `digestionRateMin`, `digestionRateMax` | float, %/second | The range the digestion rate stays within. |
| `digestionTime` | float, seconds | When digesting, the digestion bar will count down, and then when it hits 0, the current calories will be digested. This determines how long this takes. |
| `blinkChance` | float, % | Chance each tick to blink. |
| `gurgleChance` | float, % | Chance each tick of a gurgle (see `sounds`), scaled by how full the character is. |
| `gurgleCapacityMultiplier` | float | Multiplies the gurgle chance at full capacity. Higher capacity = higher gurgle chance. |
### alternate
The alternate spritesheet of the character, if applicable (in Pokemon terms, the "shiny").
| Key | Type | Meaning |
|---|---|---|
| `texture` | path | The alternate spritesheet texture. |
| `sound` | path | Plays when the spritesheet is set to alternate (either on new game, or with an item that has `isToggleSpritesheet`). |
| `spritesheet` | int | The spritesheet of the character's anm2 it replaces. Defaults to 0. |
| `chance` | float, % | Chance of rolling the alternate spritesheet when starting a new game. |
### stages
A "stage" represents each visual change of the character as the weight increases. There's always a first stage (`Stage1`). This is a list of the weights (in kg) at which each stage after it (`Stage2`, `Stage3`...) is reached.
### animations
The character's animations. Know that a lot of character animations are typically easily played through dialogue; this is just for animations that aren't reliant on that system. These are just the base names.
| Key | Meaning |
|---|---|
| `start` | Plays first when starting a new game; used for like a character's introduction. |
| `idle` | The idle animation that the character will regularly return to. |
| `idleFull` | When over capacity, this idle animation will be used instead. |
| `stageUp` | When going to a new stage after digestion goes over a stage's threshold, this animation will play. |
### talk, blink
"talk" and "blink" are animations tweaked by the game for effect. Typically, each animation will have an invisible blinking/talking layer (just the graphic that blinks), which will change when called for. All that's sourced is just the spritesheet crop in these cases; so don't worry about how the blink/talk layers are set up.
| Key | Meaning |
|---|---|
| `source` | The layer in the animation which will be sourced. |
| `destination` | The layer in the animation which the source will be applied to. |
### eatAreas
An "eat area" is where the food should be dragged to. I'm pretty much expecting this to only be a mouth for most characters but hey maybe you want the character to also eat through their butt or something.
| Key | Meaning |
|---|---|
| `null` | The null in the animation where food will be checked for. |
| `animation` | The animation that will play when food is dragged to it. |
| `event` | The event that will be checked for, determining the time the food is actually eaten/chewed. |
### expandAreas
The areas which will expand based on how full the character is and their progress to the next stage (50/50); usually a stomach. This adds scale onto a layer and a null of every animation.
| Key | Meaning |
|---|---|
| `layer` | The layer that will expand. |
| `null` | The null that will expand. |
| `scaleMax` | The scale (in percent) that will be added at maximum. Know that a scale of 100 is the normal scale of an animation. |
### interactTypes, interactAreas
`interactTypes` is an object of interaction types by name, giving each type's defaults. Rub, Smack, Kiss and Turn Around come from common. A type gets a button on the taskbar only if one of the character's areas uses it. `interactAreas` is a list of the concrete areas on a character which can be interacted with; usually for belly rubs, kisses, etc. Each area names its `type` and takes all of that type's settings, changing whichever it gives itself.
| Key | Type | Meaning |
|---|---|---|
| `type` | string | (Areas only) The interaction type to use. |
| `null` | string | (Areas) The null in which the interact area can be triggered. |
| `layer` | string | The layer that the scale effect (e.g. smacks) applies to. |
| `icon` | string | The region of `gfx/ui/icons.anm2` shown on this type's taskbar button. |
| `isHold` | bool | If true, the interaction is held rather than clicked once. |
| `cursorHover` | string | The animation the cursor will play when hovering over the interact area. |
| `cursorActive` | string | The animation the cursor will play when interacting. |
| `animation` | string | A character animation to play on interacting, when the area has no dialogue pool. |
| `idleOnEnd` | string | The idle animation the character uses after interacting (e.g. turning around). |
| `dialoguePool` | string | The dialogue pool which will be drawn from when interacting. Over capacity, the same pool with `Full` added is used, if there is one. |
| `dialogueCooldown` | float, seconds | Time before interacting can start new dialogue again. |
| `digestionClick` | float, % | Digestion added each click. |
| `digestionHover` | float, %/second | Digestion added while the cursor moves, held. |
| `scaleAmplitude` | float, % | Size of the scale effect on clicking. |
| `scaleCycles` | float | How many oscillations the scale effect performs. Defaults to 1. |
| `scaleTime` | float, seconds | How long the scale effect lasts. Defaults to a third of a second. |
| `sounds` | paths | Sounds played when interacting. |
| `particles` | strings | Particles (see `particles`) spawned when interacting. |
### sounds
| Key | Meaning |
|---|---|
| `digest` | Plays when the character begins digesting (digestion bar full). |
| `gurgle` | Ambient sounds that play randomly based on capacity; see `gurgleChance`. |
### area
How items move in the background (`gfx/areas/area.anm2`): `gravity` (applied to items' velocities per tick), `friction` (applied when items are grounded or hit walls) and `airResistance`.
### cursor
The cursor's sounds and particles. Its look is `gfx/cursor/cursor.anm2` (see "Fixed files and names").
| Key | Meaning |
|---|---|
| `sounds` | `grab` (grabbing an item), `release` (letting go) and `throw` (letting go while dragging quickly). |
| `particles` | `grab`: particles spawned when grabbing an item. |
### menu
The UI's sounds.
| Key | Meaning |
|---|---|
| `sounds` | `open` and `close` (the taskbar or one of its windows), `hover` and `select` (a widget), and `cheats` (after entering a special code to activate cheats). |
### particles
An object of particles by name, each with the `anm2` and `animation` it plays once where spawned.
# items.json
Has all items and their parameters, alongside additional behavior. Items share one anm2, whose spritesheet holds every item as a region named after it (pack them in Anm2Ed with "Make Spritesheet Regions"). Each item shows its region in place of whatever the anm2's frames show, with the region's own size and pivot.
```json
{
"anm2": "gfx/items/item.anm2",
"spawnDelay": 10,
"rarities": {"Common": {"weight": 1, "sound": "sfx/common.ogg"}},
"items": [
{"name": "Apple", "category": "Food", "use": "edible", "rarity": "Common", "calories": 95}
]
}
```
| Key | Type | Meaning |
|---|---|---|
| `anm2` | path | The anm2 that items use. |
| `spritesheet` | int | The spritesheet of the anm2 holding the items' regions. Defaults to 0. |
| `spawnDelay` | float, seconds | Base cooldown before another item can be spawned. |
| `spawnDelayMultiplier` | float | Multiplies the spawn delay once per character stage. Values below `1.0` make item spawning faster as stage increases. |
| `spawnLimit` | int | Maximum number of items in the world at once. |
| `sounds` | | `bounce` (an item hitting a floor/wall/ceiling), `dispose` (an item disposed of), `summon` (an item spawned) and `newItem` (an item found for the first time). |
| `particles` | | `dispose` and `summon`. |
| `rarities` | object | Rarities, by name. Each has a `weight` (relative chance of spawning) and a `sound` that plays when one spawns. |
### items
| Key | Type | Meaning |
|---|---|---|
| `name` | string | The name of the item. |
| `id` | string | What saves keep the item by. Defaults to its name; set it to keep saves when renaming the item. |
| `description` | string | Flavor text for the item. |
| `region` | string | The region of the items' spritesheet it shows. Defaults to its name. |
| `anm2` | path | An anm2 of its own, if it animates differently. |
| `category` | string | The item's category, shown in the Catalog. |
| `use` | string | `edible` (food that can be eaten) or `tool`. |
| `rarity` | string | The item's rarity. |
| `flavor` | string | Flavor text (for food); honestly has no meaning but whatever. |
| `calories` | float | The amount of calories the item has (if food). |
| `capacityBonus` | float | Capacity increase granted as the item is eaten. |
| `digestionBonus` | float, %/second | The digestion rate added as the item is eaten. |
| `gravity` | float | The item's gravity, in pixels per tick (a 60th of a second); will use the area's if not given. |
| `color` | [r, g, b], 0-1 | Optional UI color for the item. |
| `isToggleSpritesheet` | bool | When used as a tool on the character, will toggle the character's spritesheet (in Pokemon terms, toggling normal/shiny palettes). |
# dialogue.json
The collection of character dialogue; likely the biggest file, depending on your needs.
```json
{
"speed": 30,
"blipEvery": 2,
"blip": "sfx/blip.ogg",
"pauses": {".": {"delay": 0.08}},
"hooks": {"Start": "Intro"},
"entries": {
"Intro": {
"isScene": true,
"lines": [
{"animation": "Appear"},
{"text": "Hey there, [shake]human[/shake]!", "animation": "Smug"}
],
"choices": [{"text": "Hi!", "next": "Hello"}]
},
"Eat1": {
"pools": ["Eat"],
"lines": [{"text": "[big]Yum![/big]"}]
}
}
}
```
| Key | Type | Meaning |
|---|---|---|
| `speed` | float | How many characters are revealed per second. |
| `blipEvery` | int | How many characters pass between blip sounds. `3` means every third character. |
| `blip` | sounds | Dialogue blip sounds, played periodically while text reveals. |
| `pauses` | object | Extra `delay` (in seconds) after particular characters. With `isSilent`, talking and blips also pause during it. |
| `hooks` | object | Gameplay events play the pool (or else the entry) named after them: `Start`, `End`, `Help`, `StageUp`, `Random`, `Feed`, `FeedFull`, `Eat`, `EatFull`, `Full`, `Throw`, `LowCapacity`, `Digest`, `FoodTaken` and `FoodTakenFull`. Hooks only lists ones that play something else. `Random` and `Help` add the "Let's chat!" and "Help" buttons. |
| `entries` | object | Each bit of dialogue is referred to as an "entry", by its label. |
### entries
An entry is lines played in order, after which it offers its choices or moves on to the next entry.
| Key | Type | Meaning |
|---|---|---|
| `lines` | list | Each with its `text` and an `animation` (base name) that plays as it starts. A line without text just plays its animation, moving on once it ends. |
| `choices` | list | Dialogue can be branching; each choice has its `text` (shown as a button after the last line) and the `next` entry it leads to. |
| `next` | string | The entry that follows the last line. With neither choices nor next, the dialogue ends there. |
| `pools` | strings | The pools (lists of entries picked from at random) the entry is in. |
| `isScene` | bool | Hides windows and items and disables interaction until the dialogue reaches the end. A scene started in the middle of another is ignored. |
### markup
Effects go right in a line's text, as tags. A tag over part of the text has a closing tag: `[shake]too bad[/shake]`. The rest happen where they stand: `[screenshake]BOOM`. `[[` is a plain `[`.
| Tag | Meaning |
|---|---|
| `[color=r g b]` | Colors the text (0-1 each), e.g. `[color=1 0.25 0.25]`. |
| `[big]`, `[small]` | Fixed text scales. |
| `[wave]`, `[shake]` | Moves the text, with engine defaults. |
| `[silent]` | Suppresses blips and character talking. |
| `[screenshake]` | Shakes the screen. |
| `[sound=path]` | Plays a sound. |
| `[animation=Name]` | Plays a character animation. |
| `[delay=seconds]` | Changes the reveal speed to one character per this many seconds from here on. |
# Saves
Outside of resources, Shweet's Sim also has a few files it writes outside of the game. You will find these in %AppData%/shweets-sim on Windows and ~/.local/share/shweets-sim on Linux. Each is a plain text file of `key=value` lines.
## settings.txt
Stores general game settings and configuration; beyond individual characters.
| Key | Meaning |
|---|---|
| `measurement` | `0` for metric (kg/g), `1` for imperial (lb/oz). |
| `volume` | Master volume, in percent. |
| `mute` | `1` if all audio is muted. |
| `color` | Red, green and blue (0-1) of the menu color. |
| `character_color` | `1` to use the character's color while playing. |
| `width`, `height` | Window size. |
| `x`, `y` | Window position. |
| `last_character` | The character being played at exit, which the game continues on start. |
| `console` | `1` enables the developer console (the grave key). |
## saves/<character id>.txt
A character's progress: their weight, calories, capacity, digestion, totals and playtime, the camera, and the items found (`discovered=` lines) and lying in the world (`item=` lines, as position, velocity, rotation and id).