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
# 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_idsarray onGeneratorBuffData. - Wildcards: A
target_idsvalue of["*"]applies the buff to all current AND future generators. - Catalog-Based Loading: Buffs are defined in a
BuffCatalogueresource (@export var buff_catalogue: BuffCatalogueonLevelGameState). No runtime directory scanning is performed. - Goal-Based Activation: Buffs with an
unlock_goalautomatically 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)
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(AUTOMATICorMANUAL). - 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
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:
PrestigeConfigresource atdocs/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) orTRIANGULAR_INVERSE - Multiplier modes:
ADDITIVEorMULTIPLICATIVE_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_MULTIPLIERbuff kind increases XP gain for a research track. - Prestige Reset: All research XP and levels reset to 0.
Save Format
Version 5 (current):
{
"save_format_version": 5,
"currencies": {
"<currency_id>": {
"current": {"m": 1.0, "e": 0},
"total": {"m": 1.0, "e": 0},
"all_time": {"m": 1.0, "e": 0}
}
},
"generator_states": {
"<generator_id>": {
"owned": 0,
"purchased_count": 0,
"unlocked": false,
"available": false
}
},
"buff_levels": { "<buff_id>": 0 },
"buff_unlocked": { "<buff_id>": false },
"buff_active": { "<buff_id>": false },
"goals": { "completed": ["<goal_id>"] },
"research_xp": { "<research_id>": {"m": 0.0, "e": 0} },
"research_levels": { "<research_id>": 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_stateis an external section managed byPrestigeManager, not byLevelGameStatedirectly.research_workerstracks 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 (viaPrestigeManager) 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 viaset_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:
- Create
res://docs/gyms/tiny_sword/currencies/<name>.tres(extendCurrency) - Set
id,display_name,icon - Add to the
CurrencyCatalogueresource (ts_currency_catalogue.tres)
New Generator:
- Create
res://docs/gyms/tiny_sword/buildings/<name>/<name>_generator.tres(extendCurrencyGeneratorData) - Configure production stats, costs, purchase currency, optional
unlock_goal - Add a
CurrencyGeneratornode to the scene referencing this data
New Buff:
- Create
res://docs/gyms/tiny_sword/buffs/<name>.tres(extendGeneratorBuffData) - Set
target_ids(e.g.,["farm", "forestry"]or["*"]for all generators) - Configure
kind,effect_increment, cost, and optionalunlock_goal - Add to the
BuffCatalogueresource (ts_buff_catalogue.tres)
New Research:
- Create
res://docs/gyms/tiny_sword/research/<name>.tres(extendResearchData) - Link to a generator via
generator_id - Configure
xp_per_currency_produced,base_xp_required,xp_growth_multiplier,multiplier_per_level - Add to the
ResearchCatalogueresource (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