Files
idle/README.md
2026-05-06 23:37:52 +02:00

314 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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": {
"<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_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/<name>.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/<name>/<name>_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/<name>.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/<name>.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*