# Idles — Godot 4.6 Idle Game A modular idle/incremental game prototype featuring a decoupled buff system, multi-target buffs with wildcard support, goal-based progression, prestige resets, and production-driven research. ## Quick Start ```bash # Run the project "$GODOT_BIN" --path . # Headless mode (lint/smoke test) "$GODOT_BIN" --headless --path . --quit # Check single script syntax "$GODOT_BIN" --headless --check-only --script res://core/big_number.gd ``` ## Architecture Overview ### Core Systems | System | Location | Purpose | |--------|----------|---------| | **BigNumber** | `core/big_number.gd` | Handles huge numbers (mantissa + exponent) for idle game math | | **LevelGameState** | `core/level_game_state.gd` | Central state authority — currencies, generators, buffs, goals, research, persistence | | **Currency** | `core/currency/`, `core/currency_catalogue.gd` | Catalog system for all in-game currencies | | **Generators** | `core/generator/` | Production mechanics (auto cycles, clicks, purchases) | | **Buffs** | `core/generator/generator_buff_data.gd` | Global, multi-target buffs applied to generators | | **Goals** | `core/goals/` | Unlock conditions and achievement tracking | | **Prestige** | `core/prestige/` | Reset-with-bonus mechanics | | **Research** | `core/research/` | XP-based progression with production multipliers | ### Key Nodes | Node | Script | Description | |------|--------|-------------| | `LevelGameState` | `core/level_game_state.gd` | Central state management, save/load, catalogs, all signals | | `PrestigeManager` | `core/prestige/prestige_manager.gd` | Prestige calculation, reset orchestration | | `CurrencyGenerator` | `core/generator/currency_generator.gd` | Per-generator production, purchasing, buff interaction | | `GeneratorPanel` | `core/generator/generator_container.gd` | UI panel for a single generator | **Important:** There are **no autoload singletons**. `LevelGameState` and `PrestigeManager` are regular nodes instantiated in the scene (e.g., `docs/gyms/tiny_sword/tiny_sword.tscn`). All code accesses them through `@export` references or `get_node()`, never through an autoload name like `/root/GameState`. ### Data Directory Structure All gameplay resources (`.tres` files) live under: ``` docs/gyms/tiny_sword/ ├── currencies/ # Currency resources (gold, food, wood, worker, etc.) ├── buildings/ # Generator configuration data │ ├── farm/ # farm_generator.tres │ ├── forestry/ # forestry_generator.tres │ ├── gold_mine/ # gold_mine_generator.tres │ ├── monastery/ # monastery_generator.tres │ └── alchemy_tower/ # alchemy_tower_data.tres + recipes/ ├── buffs/ # Buff definitions with target_ids ├── goals/ # Unlock goal definitions ├── prestige/ # Prestige configuration (primary_prestige.tres) ├── research/ # Research track data └── test/ # (reserved for tests) ``` Game art assets live separately in: ``` sandbox/tiny_swords/ ├── Buildings/ # Building sprites ├── Terrain/ # Tilesets and decorations ├── UI Elements/ # UI assets └── Units/ # Unit sprites ``` ## Core Documentation Each `core/` subsystem has its own detailed README: | Module | Documentation | |--------|--------------| | Core overview | `core/README.md` | | Currency system | `core/currency/README.md` | | Generator system | `core/generator/README.md` | | Goals system | `core/goals/README.md` | | Prestige system | `core/prestige/README.md` | | Research system | `core/research/README.md` | ## Buff System Buffs are **globally registered** and **multi-target capable**: - **Global Levels**: Each buff has a single level shared across all generators it targets. - **Multi-Target**: A single buff resource can affect multiple generators. Controlled by the `target_ids` array on `GeneratorBuffData`. - **Wildcards**: A `target_ids` value of `["*"]` applies the buff to all current AND future generators. - **Catalog-Based Loading**: Buffs are defined in a `BuffCatalogue` resource (`@export var buff_catalogue: BuffCatalogue` on `LevelGameState`). No runtime directory scanning is performed. - **Goal-Based Activation**: Buffs with an `unlock_goal` automatically unlock when their goal is completed. - **Multiplicative Stacking**: Multiple buffs of the same kind on a generator stack multiplicatively (`buff1 × buff2 × …`). - **Buff Kinds**: `AUTO_PRODUCTION_MULTIPLIER`, `MANUAL_CLICK_MULTIPLIER`, `RESOURCE_PURCHASE`, `RESEARCH_XP_MULTIPLIER` ### Lifecycle | Event | What happens | |-------|-------------| | **Default state** | Inactive (locked) until its unlock goal is met | | **Goal met** | Buff auto-unlocks, becomes purchasable | | **Purchased** | Level increments, effect applies to all target generators | | **Prestige reset** | All buff levels reset to 0, all buffs re-locked | ### API (on LevelGameState) ```gdscript LevelGameState.register_buff(buff: GeneratorBuffData) LevelGameState.get_buff(buff_id: StringName) -> GeneratorBuffData LevelGameState.get_buff_level(buff_id: StringName) -> int LevelGameState.get_buffs_for_generator(generator_id: StringName) -> Array[GeneratorBuffData] LevelGameState.get_effective_multiplier(generator_id: StringName, kind: int) -> float LevelGameState.set_buff_level(buff_id: StringName, level: int) LevelGameState.is_buff_active(buff_id: StringName) -> bool ``` ## Goals System Goals track player progress and unlock generators or buffs when requirements are met. - **Automatic or Manual**: Goals define their own `unlock_behavior` (`AUTOMATIC` or `MANUAL`). - **Logarithmic Progress**: Progress bars use log-scale for visual feedback on huge numbers. - **Prestige Reset**: All goals are reset to incomplete on prestige. Previously unlocked generators re-lock until their goal is met again. ### Signals on LevelGameState ```gdscript goal_completed(goal_id: StringName) goal_progress_changed(goal_id: StringName, progress: float) ``` ## Prestige System Prestige resets run progress in exchange for a permanent production multiplier. - **Configuration**: `PrestigeConfig` resource at `docs/gyms/tiny_sword/prestige/primary_prestige.tres` - **Basis types**: `LIFETIME_TOTAL` (single currency), `RUN_TOTAL`, `RUN_MAX`, `ALL_CURRENCIES` (sum of all tracked currencies) - **Formula types**: `POWER` (`scale × ratio^exponent`) or `TRIANGULAR_INVERSE` - **Multiplier modes**: `ADDITIVE` or `MULTIPLICATIVE_POWER` ### What gets reset on prestige | State | Behavior | |-------|----------| | **Current currency balances** | Reset to 0 (except prestige currency if configured) | | **Generator states** (owned, unlocked) | Cleared | | **Buff levels** | All reset to 0, all re-locked | | **Goals** | All reset to incomplete | | **Research XP and levels** | All cleared to 0 | | **Lifetime currency totals** | Preserved | | **All-time currency acquired** | Preserved | | **Prestige points earned** | Preserved (permanent) | ## Research System XP-based progression tied to generator output. Research tracks level up automatically, granting permanent production multipliers to their associated generator. - **XP Formula**: `XP = currency_produced × xp_per_currency_produced × buff_multiplier` - **Level Formula**: `xp_required(n) = base_xp_required × growth_multiplier^(n-1)` - **Buffs**: The `RESEARCH_XP_MULTIPLIER` buff kind increases XP gain for a research track. - **Prestige Reset**: All research XP and levels reset to 0. ## Save Format **Version 5 (current):** ```json { "save_format_version": 5, "currencies": { "": { "current": {"m": 1.0, "e": 0}, "total": {"m": 1.0, "e": 0}, "all_time": {"m": 1.0, "e": 0} } }, "generator_states": { "": { "owned": 0, "purchased_count": 0, "unlocked": false, "available": false } }, "buff_levels": { "": 0 }, "buff_unlocked": { "": false }, "buff_active": { "": false }, "goals": { "completed": [""] }, "research_xp": { "": {"m": 0.0, "e": 0} }, "research_levels": { "": 0 }, "research_workers": 0, "prestige_state": { … }, "last_save_time": 1234567890 } ``` Notes: - All large numbers are serialized as `{"m": mantissa_float, "e": exponent_int}` (BigNumber format). - `prestige_state` is an external section managed by `PrestigeManager`, not by `LevelGameState` directly. - `research_workers` tracks workers assigned to research across all tracks. - Save file is written to `user://level_save.json`. ## Save/Load - **Save**: `LevelGameState.save_game()` serializes all state to JSON. Called on prestige reset (via `PrestigeManager`) and when manually triggered. - **Load**: `LevelGameState.load_game()` deserializes from disk during `_ready()`. Handles version migration from v2+. - **External sections**: Other systems (e.g. `PrestigeManager`) can attach their data via `set_external_save_data()` / `get_external_save_data()`. ## Development ### Adding New Content All gameplay resources go under `docs/gyms/tiny_sword/` (not `sandbox/` — that's for art assets only). **New Currency:** 1. Create `res://docs/gyms/tiny_sword/currencies/.tres` (extend `Currency`) 2. Set `id`, `display_name`, `icon` 3. Add to the `CurrencyCatalogue` resource (`ts_currency_catalogue.tres`) **New Generator:** 1. Create `res://docs/gyms/tiny_sword/buildings//_generator.tres` (extend `CurrencyGeneratorData`) 2. Configure production stats, costs, purchase currency, optional `unlock_goal` 3. Add a `CurrencyGenerator` node to the scene referencing this data **New Buff:** 1. Create `res://docs/gyms/tiny_sword/buffs/.tres` (extend `GeneratorBuffData`) 2. Set `target_ids` (e.g., `["farm", "forestry"]` or `["*"]` for all generators) 3. Configure `kind`, `effect_increment`, cost, and optional `unlock_goal` 4. Add to the `BuffCatalogue` resource (`ts_buff_catalogue.tres`) **New Research:** 1. Create `res://docs/gyms/tiny_sword/research/.tres` (extend `ResearchData`) 2. Link to a generator via `generator_id` 3. Configure `xp_per_currency_produced`, `base_xp_required`, `xp_growth_multiplier`, `multiplier_per_level` 4. Add to the `ResearchCatalogue` resource (`ts_research_catalogue.tres`) ### BigNumber System - **Representation**: `mantissa: float` × `10^exponent: int` - **Range**: Values up to ~10^308 before float precision loss - **Operations**: `add()`, `subtract()`, `multiply()`, `divide()`, `compare_to()`, `add_in_place()` - **Serialization**: `.serialize()` → `{"m": float, "e": int}`; `BigNumber.deserialize(dict)` → `BigNumber` - **Display**: `.to_string_suffix(decimals: int)` → `"1.50K"`, `"3.21M"`, etc. ### Production Formulas ``` Cost for N items: base × coefficient^owned × (coefficient^n − 1) / (coefficient − 1) Max affordable: floor(log(currency × (coefficient − 1) / (base × coefficient^owned) + 1) / log(coefficient)) Production/cycle: initial_productivity × owned × run_mult × milestone_mult × purchased_mult Production/second: production/cycle / initial_time ``` ## Project Structure ``` core/ # Engine code (all .gd scripts) ├── big_number.gd # BigNumber class ├── level_game_state.gd # Central state manager (LevelGameState node) ├── buff_catalogue.gd # Buff catalogue resource ├── currency_catalogue.gd # Currency catalogue resource ├── goal_catalogue.gd # Goal catalogue resource ├── currency/ # Currency resource definition ├── generator/ # Generator, buff data, UI panel, research buff calculator ├── goals/ # Goal/requirement resources ├── prestige/ # Prestige manager, config, panel └── research/ # Research catalogue, panel, row UI docs/gyms/tiny_sword/ # Playable game content (.tres resources) ├── currencies/ # Currency definitions ├── buildings/ # Generator configs ├── buffs/ # Buff definitions ├── goals/ # Goal definitions ├── prestige/ # Prestige config ├── research/ # Research configs └── test/ # (reserved for tests) sandbox/tiny_swords/ # Art assets (sprites, tilesets, UI textures) └── Buildings/, Terrain/, UI Elements/, Units/ docs/museums/ # Prototype/demo scenes (big_number_museum) ``` ## Known Issues / TODOs - [ ] Periodic auto-save not implemented (saves only on prestige and manual trigger) - [ ] No automated test suite - [ ] Some buffs may be configured with no unlock path ## Technical Details ### Buff Multiplier Stacking Multiple buffs of the same kind on the same generator stack **multiplicatively**: ``` total_multiplier = buff1_effect(level) × buff2_effect(level) × buff3_effect(level) × … ``` ### Prestige Multiplier Application Generators apply prestige multipliers automatically. The prestige multiplier is fetched from `PrestigeManager.get_total_multiplier()` and multiplied into the effective production rate alongside research and buff multipliers. ## License Internal prototype — no external license applied. --- *Godot version: 4.6*