# Architecture ## Singletons (Autoloads) Never instantiate these — access only via the global handle. | Handle | Role | |---|---| | `SCENE` | Current scene state; `SCENE.setScene(SceneSingleton.SceneType.X)` to switch | | `TRANSITION` | Fade in/out; `TRANSITION.fade(FadeType, duration, color)` | | `BATTLE` | Battle state and fighter map | | `PARTY` | Party members (`PARTY.getFullParty()`) and `PARTY.BACKPACK` inventory | | `OVERWORLD` | Map switching with threaded loading | | `COOKING` | Cooking mini-game lifecycle | | `SAVE` | Persistence (stub) | | `SETTINGS` | Runtime settings — `invertCameraX:bool`, `invertCameraY:bool` | | `QUEST` | Quest management (stub) | | `CUTSCENE` | Cutscene global (stub) | | `DialogueManager` | godot_dialogue_manager v3.10.4 — parses and steps through `.dialogue` files | | `UI` | Root UI accessor — `UI.TEXTBOX`, `UI.DEBUG_MENU`, `UI.GAME_MENU` | ## Scene Graph ``` RootScene (Node3D) └─ overworld / battle / cooking / initial ← one shown at a time RootUI (Control, always visible) └─ VNTextbox, DebugMenu, PauseMenu, GameMenu ``` `RootScene` listens to `SCENE.sceneChanged` and shows/hides the correct sub-tree. ## Cutscene / Event Queue `Cutscene` is the universal sequencing engine. It holds an `Array[Dictionary]` queue; each entry has a `"function": Callable` plus arbitrary data keys. **Return codes from a callable:** - `Cutscene.CUTSCENE_CONTINUE` — advance to next item - `Cutscene.CUTSCENE_END` — stop the cutscene - An integer index — jump to that position **Insertion positions:** - `Cutscene.CUTSCENE_ADD_END` — append (default) - `Cutscene.CUTSCENE_ADD_NEXT` — insert immediately after current **Callable pattern** — every action class exposes a pair: ```gdscript # The actual callable (static, takes params:Dictionary, returns int) static func myCallable(params:Dictionary) -> int: ... return Cutscene.CUTSCENE_CONTINUE # Factory that builds the dictionary for addCallable() static func getMyCallable(arg) -> Dictionary: return { "function": myCallable, "myArg": arg } ``` ## Data Registry Pattern Static registries (Item, Recipe) follow this pattern: 1. `enum Id { NULL, ... }` — typed identifier 2. `static var DATA:Array = []` — indexed by Id value 3. `static func define(params) -> Dictionary` — called at class load to populate `DATA` 4. `static var FOO = define({...})` — registers the entry as a static var 5. `static func get*(id) -> *` — typed accessors ## `_init(params:Dictionary)` Pattern Non-Node data classes (`BattleFighter`, `BattleDecision`, `ItemStack`, etc.) use a single `params` dictionary constructor with `.get('key', default)` for optional fields.