> For the complete documentation index, see [llms.txt](https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/world/rooms-and-saves.md).

# Rooms and saves

## Moving between rooms

`Rooms` moves between screens as the game does: a fade to black, the room changer's events, then the next room. Each call returns `false`, doing nothing, when it can't be done now: another room change is under way (`IsChanging`), or it isn't the screen for it.

```csharp
// Go into the room you're in again, as a door to it would: the room saved, a fade, rebuilt from its save.
if (Gm.InGame && !Game.IsBusy)
    Rooms.Change(Rooms.Current);
```

| `Rooms`                            |                                                                                                                                              |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `Current`, `CurrentName`           | The room the game is in (`"r_globalmap_forest"`).                                                                                            |
| `InMainMenu`, `IsChanging`         |                                                                                                                                              |
| `Change(room, saveLocation, fade)` | Another room of the game being played, as a door does. The room being left is saved first, unless `saveLocation` is false. By index or name. |
| `ToMainMenu(save)`                 | Back to the main menu, as the Esc menu's Exit does - or, with `save`, through the game's own Save and Exit (so mods hooking it see it).      |
| `LoadSave(save)`                   | Load a save, as the save menu does (from the main menu, or from a game, left without saving).                                                |
| `StartNew(prologue, permadeath)`   | A new game, from the main menu, as its New Game buttons do.                                                                                  |

### Entering and leaving rooms

```csharp
Rooms.OnEntered(context, room => context.Log($"Entered {Rooms.CurrentName}"));
Rooms.OnLeaving(context, room => context.Log("Leaving"));
```

`Rooms.OnEntered` runs once the game has gone into a room of the game being played, on the frame after it started, its instances all set up. `Rooms.OnLeaving` runs as the game leaves one: its instances are still there, and the place is already saved if it's saved. Each floor of a dungeon counts, since it's the same room started again.

## Saves on disk: SaveSlots

`SaveSlots` reads the saved games on disk, as the game's save menu shows them: character folders (slots, `"character_1"` up to 10), newest first, each with its info and its saves.

```csharp
using System.Linq;

foreach (var slot in SaveSlots.All)
{
    context.Log($"{slot.Name}: {slot.Info?.CharacterName ?? "?"}, saved {slot.Info?.SavedAt}, {slot.Saves.Count} save(s)");
    foreach (var save in slot.Saves)
        context.Log($"  {save.Name} ({save.Kind}): {save.Info?.LocationTitleKey}");
}

// Load the newest save:
var newest = SaveSlots.All.SelectMany(slot => slot.Saves.Take(1)).FirstOrDefault();
if (newest != null)
    Rooms.LoadSave(newest);
```

| `SaveSlots`                                  |                                                                                      |
| -------------------------------------------- | ------------------------------------------------------------------------------------ |
| `All`                                        | Every character folder, newest first.                                                |
| `Current`, `CurrentSave`                     | The folder and save of the game being played (`null` if never saved).                |
| `Get(name)`                                  | A folder by name.                                                                    |
| `OnInfoSaving(context, (slot, info) => ...)` | Add values of your own to a folder's info as the game writes it, each time it saves. |
| `SetTitle(context, slot => ...)`             | Give folders a header of your own in the save menu (`null` keeps the game's).        |

`SaveSlot` has `Name`, `Number`, `Exists`, `Info` (`SlotInfo`: `CharacterName`, `IsPermadeath`, `IsPrologue`, `SavedAt`, and any value by name) and `Saves`. Each `SaveFile` has `Slot`, `Name`, `Kind` (`SaveKind.Manual`, `Auto` or `Exit`) and `Info` (`SaveInfo`: `CharacterName`, `LocationTitleKey`, `Avatar`, `SavedAt`, `IsValid`...).

A mod's values in the save menu - here, how many saves were made with the mod on:

```csharp
SaveSlots.OnInfoSaving(context, (slot, info) =>
    info["example_saves"] = (slot.Info?["example_saves"] is { Kind: GmKind.Real } count ? count.AsInt : 0) + 1);

SaveSlots.SetTitle(context, slot => slot.Info is { } info && info["example_saves"] is { Kind: GmKind.Real } count
    ? $"{info.CharacterName ?? "?"} - {count.AsInt} save(s) with Example Mod"
    : null);
```

## The game being played: SaveData

`SaveData` is the save data of the game being played (the game's `global.saveDataMap`): everything a save writes, in sections. It's live: the game keeps changing it and writes it to disk as it saves. It's there only in a game: check `SaveData.Available`.

```csharp
if (SaveData.Available)
{
    context.Log($"Sections: {string.Join(", ", SaveData.Sections)}");
    string? character = SaveData.CharacterJson();   // who's playing, without their world
}
```

| `SaveData`                                        |                                                                                                                                                                          |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Available`, `Map`                                | The save data itself (the game's: never destroy it).                                                                                                                     |
| `Sections`, `CharacterSections`, `WorldSections`  | Section names: the character's (who they are, stats, skills, inventory, scrolls, cleared fog) and the world's (the map, locations, quests, contracts, time, weather...). |
| `Section(name)`, `SectionList(name)`              | A section as a map (`"gameDataMap"`) or list (`"inventoryDataList"`).                                                                                                    |
| `ToJson()`, `ToJson(sections)`, `CharacterJson()` | As JSON, as the game writes it.                                                                                                                                          |
| `ModData(context)`                                | Your mod's own values in the save data, under keys only it uses.                                                                                                         |
| `ModMap(key)`                                     | A map of your own in the save data, saved and loaded with the game.                                                                                                      |
| `Save(kind)`                                      | Runs the game's save step now: the character collected into the save data, then the save written as `SaveKind.Auto` (or another kind). No fade, no room change.          |
| `WriteTo(save)`                                   | Writes the save data as it is now over a save already on disk (its data only), to add to one just made.                                                                  |

### Keeping a mod's own data in saves

```csharp
var mine = SaveData.ModData(context);           // values only this mod uses
mine["gold"] = mine["gold"].AsInt + 10;

DsMap stash = SaveData.ModMap("mymod_stash");   // a whole map of your own, made empty the first time
stash["gold"] = stash.Get("gold", 0) + 10;
```

`SaveData.ModData` keeps values under keys only your mod uses (see [ModData](/stoneforgeteam-docs/core-concepts/mod-context.md#values-of-your-own-moddata)). With `ModMap`, use a key of your mod's own: the game's sections are the save data's other keys.

### When saves are read and written

```csharp
SaveData.OnLoaded(context, save => context.Log($"Loaded {save.Name}"));
SaveData.OnSaving(context, save => SaveData.ModData(context)["saved_at"] = Time.Turns);
```

|                                           |                                                                                                                            |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `SaveData.OnLoaded(context, save => ...)` | A save has been read: its data is the save data now, before the game sets itself up from it. Not when it couldn't be read. |
| `SaveData.OnSaving(context, save => ...)` | A save is about to be written (saving, an autosave, an exit save): what's in the save data then goes to disk.              |

The world map's fog and paper are written into the save data only as the game saves. Call `WorldMap.Save()` before handing the save data to anything that will load it (see [the world map](/stoneforgeteam-docs/world/time-and-map.md#the-world-map)).

## Save backups

StoneForge backs up every save before the game writes over it or deletes it: see [Save backups](/stoneforgeteam-docs/getting-started/save-backups.md).

```csharp
// Keep the save being played, for good, before something risky.
if (SaveBackups.Keep("mymod-before-import") is { } where)
    context.Log($"Kept a copy in {where}");
```

| `SaveBackups` |                                                                                                                                                                                |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Keep(label)` | Copies the save being played (the last one loaded or made) as `<label>_<time>_<save>`, never deleted with the other backups. Where it went; `null` if there's no save to keep. |
| `Folder`      | Where backups are: a folder for each character.                                                                                                                                |
| `Kept`        | 20: how many of each character's backups are kept (the newest).                                                                                                                |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/world/rooms-and-saves.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
