# Idles - Systems Architecture Report ## Scope Covered This report covers all tracked files in the repository (62 total at time of analysis), including: 1. Project configuration. 2. Core runtime scripts. 3. Gameplay/economy systems. 4. Goal/unlock systems. 5. UI adapter scripts and scenes. 6. Data resources (`.tres`). 7. Technical docs and metadata/import files. The focus below is on behavior-bearing files and how they interact. ## Architecture Summary 1. Global startup and singleton wiring is defined in `project.godot`. 2. Two autoload services power the runtime: `CurrencyDatabase` and `GameState`. 3. `BigNumber` is the numeric backbone used by currency amounts, costs, goals, production, and persistence. 4. Generator behavior is runtime-driven by `CurrencyGenerator`, parameterized by `CurrencyGeneratorData` and `GeneratorBuffData` resources. 5. Goal-based progression uses reusable goal primitives (`GoalData`, `GoalRequirementData`) directly on generator data (`CurrencyGeneratorData.unlock_goal`). 6. UI scripts are thin adapters listening to `GameState` signals. ## Core Systems ### 1) Numeric System (`BigNumber`) File: `core/big_number.gd` `BigNumber` stores values as mantissa + exponent (scientific notation style), normalizes them, and provides: 1. Arithmetic operations (`add`, `subtract`, `multiply`, `divide`). 2. In-place fast accumulation (`add_in_place`) for frame-loop performance. 3. Safe comparisons (`compare_to`, `is_greater_than`, etc.). 4. Ratio conversion for progress UI (`get_ratio`). 5. Display formatting (`to_string_sci`, `to_string_suffix`). 6. JSON-friendly serialization/deserialization. This class is used everywhere currency values move. ### 2) Currency Catalog System Files: `core/currency/currency.gd`, `core/currency_database.gd`, `idles/currencies/*.tres` `CurrencyDatabase` scans `res://idles/currencies`, loads typed `Currency` resources, normalizes IDs, and resolves names/icons. Current data assets: 1. `idles/currencies/magic.tres` (`id = magic`). 2. `idles/currencies/knowledge.tres` (`id = knowledge`). This creates a data-driven currency catalog that `GameState`, goals, and UI can query consistently. ### 3) Global State + Persistence (`GameState`) File: `core/game_state.gd` `GameState` is the central state authority and signal bus. It owns: 1. Current currency map by currency ID. 2. Total acquired currency map by currency ID. 3. Generator states (`owned`, `purchased_count`, `unlocked`, `available`). 4. Generator buff levels. 5. Generator buff unlocked flags. 6. `last_save_time`. Important signals: 1. `currency_changed`. 2. `generator_state_changed`. 3. `generator_buff_level_changed`. 4. `generator_buff_unlocked_changed`. Persistence: 1. Save path: `user://idle_save.json`. 2. Save payload includes currencies, generator states, buff levels, buff unlocked map, and timestamp. 3. Load path includes defensive sanitization and backward-compatible defaulting. ### 4) Generator Economy Runtime Files: `core/generator/currency_generator.gd`, `core/generator/currency_generator_data.gd`, `core/generator/currency_generator.tscn` `CurrencyGenerator` implements active gameplay behavior: 1. Auto production cycles (`_process`, cycle accumulation). 2. Click/hover grants with cooldown. 3. Buy-one and buy-max generator purchases. 4. Buff purchase logic and buff effect application. 5. State registration and lookup through `GameState`. `CurrencyGeneratorData` provides formulas and tuning knobs: 1. Exponential cost growth. 2. Bulk-buy geometric cost. 3. Max-affordable estimate. 4. Milestone multipliers. 5. Purchased-count multiplier. 6. Production/cycle and production/second helpers. 7. ROI-like helpers (`payback_seconds`, `income_to_cost_ratio`). 8. Optional generator unlock goal (`unlock_goal`). ### 5) Buff System Files: `core/generator/generator_buff_data.gd`, `idles/buffs/*.tres` Buff kinds: 1. Auto production multiplier. 2. Manual click multiplier. 3. Resource purchase (instant grant on buff buy). Each buff resource defines: 1. Unlock rules (`unlocked` and optional `unlock_goal`). 2. Effect scaling (`base_effect`, `effect_increment`). 3. Cost scaling (`base_cost`, `cost_multiplier`). 4. Optional target currency and resource grant scaling. ### 6) Goals and Unlock Progression Files: 1. `core/goals/goal_requirement_data.gd` 2. `core/goals/goal_data.gd` 3. `core/generator/currency_generator_data.gd` 4. `core/generator/currency_generator.gd` 5. `idles/goals/*.tres` Key behavior: 1. Goal requirements validate currency + target amount. 2. Requirement completion checks **total acquired currency**, not current wallet. 3. Each `CurrencyGenerator` evaluates its own `data.unlock_goal` on startup and on `currency_changed`. 4. If the goal is met, it sets both `unlocked = true` and `available = true`, then emits `goal_achieved(generator_id, goal_id)`. ### 7) UI Adapter Layer Files: 1. `generator_container.gd` + `generator_container.tscn`. 2. `generator_buff_tile.gd` + `generator_buff_tile.tscn`. 3. `currency_label.gd` + `currency_tile.tscn`. 4. `big_number_progress_bar.gd` + `big_number_progress_bar.tscn`. 5. `core/generator-unlock-goals/goals_debug_ui.gd` + `.tscn`. These scripts primarily: 1. Subscribe to `GameState` and generator signals. 2. Convert runtime values to UI strings/states. 3. Trigger user actions (buy generator, buy buff, debug unlock). The architecture is mostly event-driven and avoids polling for state refresh. ## Scene Composition ### Active Gameplay Prototype File: `docs/museums/generator_museum.tscn` It composes: 1. `MagicGenerator` instance. 2. `KnowledgeGenerator` instance (initially hidden and starts locked via data). 3. Currency tiles for `magic` and `knowledge`. 4. Goals debug UI panel. ### Legacy/Secondary Museum Files: `docs/museums/big_number_museum.tscn`, `docs/museums/big_number_museum.gd` This appears to be an older/placeholder scene and not the current gameplay focus. ## Data-Driven Content Snapshot ### Generators 1. `primary_generator.tres`: `Magic Orb`, active from start, includes 3 buffs. 2. `secondary_generator.tres`: `Library`, starts locked/unavailable and unlocks via `magic_total_30` goal. ### Buffs (Magic) 1. `magic_auto_flux.tres`: auto-production buff, unlocked by default. 2. `magic_click_focus.tres`: manual-click buff. 3. `magic_supply_cache.tres`: resource-purchase buff. ### Goals 1. `magic_total_30.tres`: reach total magic 30. 2. `magic_total_1300.tres`: reach total magic 1300. ## End-to-End Runtime Flow 1. `project.godot` autoloads `CurrencyDatabase` and `GameState`. 2. `CurrencyDatabase` builds currency catalog from `idles/currencies`. 3. `GameState` initializes per-currency maps and loads save data. 4. Scene nodes initialize and connect to `GameState` and local gameplay signals. 5. Generators produce currency automatically and via click/hover paths. 6. Currency updates emit `currency_changed` and drive UI refresh + unlock checks. 7. Goal unlock evaluator may transition generator state to unlocked/available. 8. Generator and buff purchases route all balance/state mutations through `GameState`. ## Signal Guide (Emitters and Listeners) ### Custom Gameplay Signals | Signal | Declared In | Emitted By | Emitted When | Listeners | | --- | --- | --- | --- | --- | | `currency_changed(currency_id, new_amount)` | `core/game_state.gd` | `GameState.add_currency_by_id`, `GameState.spend_currency_by_id` | Any currency balance increases/decreases | `CurrencyGenerator._on_currency_changed`, `GeneratorPanel._on_currency_changed`, `CurrencyTile._on_currency_changed`, `BigNumberProgressBar._on_currency_changed`, `GoalsDebugUI._on_currency_changed` | | `generator_state_changed(generator_id, state)` | `core/game_state.gd` | `GameState.register_generator`, `GameState._set_generator_state` | Generator state created or changed (`owned`, `purchased_count`, `unlocked`, `available`) | `CurrencyGenerator._on_generated_state_changed`, `GeneratorPanel._on_generator_state_changed`, `GoalsDebugUI._on_generator_state_changed` | | `generator_buff_level_changed(generator_id, buff_id, new_level)` | `core/game_state.gd` | `GameState.register_generator_buff`, `GameState.set_generator_buff_level` | Buff level created/sanitized/updated | `GeneratorPanel._on_generator_buff_level_changed` | | `generator_buff_unlocked_changed(generator_id, buff_id, unlocked)` | `core/game_state.gd` | `GameState.register_generator_buff_unlocked`, `GameState.set_generator_buff_unlocked` | Buff unlock state created/sanitized/updated | `GeneratorPanel._on_generator_buff_unlocked_changed` | | `purchase_completed(amount, total_owned, total_purchased, total_cost)` | `core/generator/currency_generator.gd` | `CurrencyGenerator.buy` | Generator purchase succeeds | `GeneratorPanel._on_generator_updated` | | `purchase_failed(requested_amount, required_cost, available_currency)` | `core/generator/currency_generator.gd` | `CurrencyGenerator.buy` | Generator purchase fails for insufficient funds | `GeneratorPanel._on_generator_updated` | | `production_tick(amount, cycle_count, total_owned)` | `core/generator/currency_generator.gd` | `CurrencyGenerator._grant_cycle_income` | One or more automatic production cycles complete | `GeneratorPanel._on_generator_updated` | | `buff_purchased(buff_id, new_level, cost, cost_currency_id)` | `core/generator/currency_generator.gd` | `CurrencyGenerator.buy_buff` | Buff purchase succeeds | `GeneratorPanel._on_generator_updated` | | `buff_purchase_failed(buff_id, required_cost, cost_currency_id)` | `core/generator/currency_generator.gd` | `CurrencyGenerator.buy_buff` | Buff purchase fails for insufficient funds | `GeneratorPanel._on_generator_updated` | | `goal_achieved(generator_id, goal_id)` | `core/generator/currency_generator.gd` | `CurrencyGenerator._evaluate_generator_unlock_goal` | Generator unlock goal transitions that generator to unlocked+available | None currently (available for gameplay/UI hooks) | | `buy_pressed(buff_id)` | `generator_buff_tile.gd` | `GeneratorBuffTile._on_buy_button_pressed` | User presses buff buy button in a buff row | `GeneratorPanel._on_buy_buff_pressed` | ### Built-In Godot Signals Wired In This Project | Source Signal | Connected In | Listener Method | Purpose | | --- | --- | --- | --- | | `Area2D.mouse_entered` | `core/generator/currency_generator.tscn` | `CurrencyGenerator._on_area_2d_mouse_entered` | Enter generator hover zone; mark hover true and show generator panel | | `Area2D.mouse_exited` | `core/generator/currency_generator.tscn` | `CurrencyGenerator._on_area_2d_mouse_exited` | Exit generator hover zone; mark hover false and hide generator panel | | `BuyOneButton.pressed` | `generator_container.tscn` | `GeneratorPanel._on_buy_pressed` | Buy one generator | | `BuyMaxButton.pressed` | `generator_container.tscn` | `GeneratorPanel._on_buy_max_pressed` | Buy max affordable generators | | `GeneratorContainer.mouse_entered` | `generator_container.tscn` | `GeneratorPanel._on_mouse_entered` | Intended hover hook on panel container (method currently missing) | | `GeneratorContainer.mouse_exited` | `generator_container.tscn` | `GeneratorPanel._on_mouse_exited` | Intended hover hook on panel container (method currently missing) | | `BuyButton.pressed` | `generator_buff_tile.tscn` | `GeneratorBuffTile._on_buy_button_pressed` | Emit tile-level `buy_pressed` custom signal | | `DebugIncomeButton.pressed` | `currency_tile.tscn` | `CurrencyTile._on_debug_income_button_pressed` | Add debug income to the tile currency | | `Button.pressed` (runtime-created unlock button) | `core/generator-unlock-goals/goals_debug_ui.gd` | `GoalsDebugUI._on_unlock_pressed` (bound with goal id) | Manual debug unlock when a goal is ready | ### Common Signal Chains 1. Currency gain/spend chain: generator or debug action mutates `GameState` currency, `GameState` emits `currency_changed`, UI widgets and unlock systems recompute and redraw. 2. Generator purchase chain: panel button triggers `CurrencyGenerator.buy`, generator updates `GameState` state, generator emits purchase signal, panel refreshes stats and buttons. 3. Buff purchase chain: buff tile emits `buy_pressed`, panel calls `CurrencyGenerator.buy_buff`, generator updates buff level/unlock and optionally grants currency, `GameState` emits buff/currency/state signals, panel and other listeners refresh. 4. Goal unlock chain: `currency_changed` triggers generator-local unlock evaluator, evaluator sets generator `unlocked/available`, emits `goal_achieved(generator_id, goal_id)`, `GameState` emits `generator_state_changed`, generator and UI become interactable/visible. ## Key Findings and Risks 1. `project.godot` has no explicit `run/main_scene` entry, so startup scene is not pinned in tracked config. 2. Save/load is only partially wired: `load_game()` runs at startup, but `save_game()` is not invoked anywhere else in the repository. 3. `currency_label.gd` and `big_number_progress_bar.gd` reference `GameState.GOLD_CURRENCY_ID`, but that constant does not exist in `core/game_state.gd`. 4. `generator_container.tscn` connects `mouse_entered`/`mouse_exited` to methods that do not exist in `generator_container.gd`. 5. Generator unlock goals now assume the target generator exists in-scene and owns its own `unlock_goal`. 6. `KnowledgeGenerator` visibility logic may be inconsistent because `currency_generator.gd` sets `visible = true` whenever its generator state changes. 7. Two buffs are configured locked with no unlock-goal path, so they remain permanently inaccessible under current logic. 8. `core/generator-unlock-goals/TECH_SPEC.md` contains some outdated assumptions relative to current `.tres`-based implementation. ## Additional Notes 1. `.uid` files are identity metadata used by Godot and contain no runtime logic. 2. `icon.svg` and `icon.svg.import` are standard icon/import metadata. 3. Root config files (`.editorconfig`, `.gitattributes`, `.gitignore`) are minimal and conventional.