Update READMEs
This commit is contained in:
319
README.md
319
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Idles - Godot 4.6 Idle Game
|
# Idles — Godot 4.6 Idle Game
|
||||||
|
|
||||||
A modular idle/incremental game prototype featuring a decoupled buff system, multi-target buffs with wildcard support, and goal-based progression.
|
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
|
## Quick Start
|
||||||
|
|
||||||
@@ -22,11 +22,11 @@ A modular idle/incremental game prototype featuring a decoupled buff system, mul
|
|||||||
| System | Location | Purpose |
|
| System | Location | Purpose |
|
||||||
|--------|----------|---------|
|
|--------|----------|---------|
|
||||||
| **BigNumber** | `core/big_number.gd` | Handles huge numbers (mantissa + exponent) for idle game math |
|
| **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 |
|
| **Currency** | `core/currency/`, `core/currency_catalogue.gd` | Catalog system for all in-game currencies |
|
||||||
| **LevelGameState** | `core/level_game_state.gd` | Central state authority (currencies, generators, buffs, persistence, research) |
|
|
||||||
| **Generators** | `core/generator/` | Production mechanics (auto cycles, clicks, purchases) |
|
| **Generators** | `core/generator/` | Production mechanics (auto cycles, clicks, purchases) |
|
||||||
| **Buffs** | `core/generator/generator_buff_data.gd` | Global multipliers with multi-target support |
|
| **Buffs** | `core/generator/generator_buff_data.gd` | Global, multi-target buffs applied to generators |
|
||||||
| **Goals** | `core/goals/` | Unlock conditions for generators and buffs |
|
| **Goals** | `core/goals/` | Unlock conditions and achievement tracking |
|
||||||
| **Prestige** | `core/prestige/` | Reset-with-bonus mechanics |
|
| **Prestige** | `core/prestige/` | Reset-with-bonus mechanics |
|
||||||
| **Research** | `core/research/` | XP-based progression with production multipliers |
|
| **Research** | `core/research/` | XP-based progression with production multipliers |
|
||||||
|
|
||||||
@@ -34,165 +34,280 @@ A modular idle/incremental game prototype featuring a decoupled buff system, mul
|
|||||||
|
|
||||||
| Node | Script | Description |
|
| Node | Script | Description |
|
||||||
|------|--------|-------------|
|
|------|--------|-------------|
|
||||||
| `LevelGameState` | `core/level_game_state.gd` | Central state management, save/load |
|
| `LevelGameState` | `core/level_game_state.gd` | Central state management, save/load, catalogs, all signals |
|
||||||
| `CurrencyCatalogue` | `core/currency_catalogue.gd` | Currency catalog resource |
|
| `PrestigeManager` | `core/prestige/prestige_manager.gd` | Prestige calculation, reset orchestration |
|
||||||
| `PrestigeManager` | `core/prestige/prestige_manager.gd` | Prestige system |
|
| `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
|
### Data Directory Structure
|
||||||
|
|
||||||
|
All gameplay resources (`.tres` files) live under:
|
||||||
|
|
||||||
```
|
```
|
||||||
sandbox/
|
docs/gyms/tiny_sword/
|
||||||
├── currencies/ # Currency resources (gold, food, wood, worker, etc.)
|
├── currencies/ # Currency resources (gold, food, wood, worker, etc.)
|
||||||
├── generators/ # Generator configuration (.tres files)
|
├── buildings/ # Generator configuration data
|
||||||
├── buffs/ # Buff definitions with target_ids
|
│ ├── farm/ # farm_generator.tres
|
||||||
├── goals/ # Unlock goal definitions
|
│ ├── forestry/ # forestry_generator.tres
|
||||||
└── prestige/ # Prestige configuration
|
│ ├── 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)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Current Architecture (Post-Refactoring)
|
Game art assets live separately in:
|
||||||
|
|
||||||
### Decoupled Buff System
|
```
|
||||||
|
sandbox/tiny_swords/
|
||||||
|
├── Buildings/ # Building sprites
|
||||||
|
├── Terrain/ # Tilesets and decorations
|
||||||
|
├── UI Elements/ # UI assets
|
||||||
|
└── Units/ # Unit sprites
|
||||||
|
```
|
||||||
|
|
||||||
Buffs are now **globally registered** and **multi-target capable**:
|
## Core Documentation
|
||||||
|
|
||||||
- **Global Levels**: Buff levels are shared across all targets
|
Each `core/` subsystem has its own detailed README:
|
||||||
- **Multi-Target**: A single buff resource can affect multiple generators
|
|
||||||
- **Wildcards**: `target_ids: ["*"]` applies to all current + future generators
|
|
||||||
- **Auto-Discovery**: Buffs loaded from `res://sandbox/buffs/` at runtime
|
|
||||||
- **Goal-Based Activation**: Buffs unlock automatically when goals are met
|
|
||||||
|
|
||||||
### Key Design Decisions
|
| 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` |
|
||||||
|
|
||||||
| Feature | Implementation |
|
## Buff System
|
||||||
|---------|----------------|
|
|
||||||
| **Buff Levels** | Global (shared across all targets) |
|
|
||||||
| **Buff Registry** | Auto-discovered from `res://sandbox/buffs/` |
|
|
||||||
| **Wildcards** | `["*"]` matches all current AND future generators |
|
|
||||||
| **Default State** | Inactive until goal met |
|
|
||||||
| **Persistence** | Buff definitions serialized to save |
|
|
||||||
| **Prestige** | All buff levels reset to 0 |
|
|
||||||
| **Activation** | Automatic via goals, no manual toggle |
|
|
||||||
|
|
||||||
### API Changes
|
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)
|
||||||
|
|
||||||
**Old API (per-generator state):**
|
|
||||||
```gdscript
|
```gdscript
|
||||||
GameState.register_generator_buff(generator_id, buff_id, level)
|
LevelGameState.register_buff(buff: GeneratorBuffData)
|
||||||
GameState.get_generator_buff_level(generator_id, buff_id)
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
**New API (global buff state):**
|
## 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
|
```gdscript
|
||||||
GameState.register_buff(buff: GeneratorBuffData)
|
goal_completed(goal_id: StringName)
|
||||||
GameState.get_buff(buff_id) -> GeneratorBuffData
|
goal_progress_changed(goal_id: StringName, progress: float)
|
||||||
GameState.get_buffs_for_generator(generator_id) -> Array[GeneratorBuffData]
|
|
||||||
GameState.get_effective_multiplier(generator_id, kind) -> 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
|
## Save Format
|
||||||
|
|
||||||
**Version 5 (current):**
|
**Version 5 (current):**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"save_format_version": 5,
|
"save_format_version": 5,
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"<currency_id>": {
|
"<currency_id>": {
|
||||||
"current": {"m": float, "e": int},
|
"current": {"m": 1.0, "e": 0},
|
||||||
"total": {"m": float, "e": int},
|
"total": {"m": 1.0, "e": 0},
|
||||||
"all_time": {"m": float, "e": int}
|
"all_time": {"m": 1.0, "e": 0}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator_states": { ... },
|
"generator_states": {
|
||||||
"buff_levels": { "farm_flux": 5 },
|
"<generator_id>": {
|
||||||
"buff_unlocked": { "farm_flux": true },
|
"owned": 0,
|
||||||
"buff_active": { "farm_flux": true },
|
"purchased_count": 0,
|
||||||
"goals": { "completed": ["goal_id"] },
|
"unlocked": false,
|
||||||
"research_xp": { "<research_id>": {"m": float, "e": int} },
|
"available": false
|
||||||
"research_levels": { "<research_id>": int },
|
}
|
||||||
|
},
|
||||||
|
"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
|
"last_save_time": 1234567890
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Save format version 5 includes research XP as BigNumber serialization.
|
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
|
## Development
|
||||||
|
|
||||||
### Adding New Content
|
### Adding New Content
|
||||||
|
|
||||||
|
All gameplay resources go under `docs/gyms/tiny_sword/` (not `sandbox/` — that's for art assets only).
|
||||||
|
|
||||||
**New Currency:**
|
**New Currency:**
|
||||||
1. Create `res://sandbox/currencies/<name>.tres` (Currency resource)
|
1. Create `res://docs/gyms/tiny_sword/currencies/<name>.tres` (extend `Currency`)
|
||||||
2. Set `id`, `display_name`, `icon`
|
2. Set `id`, `display_name`, `icon`
|
||||||
3. Add to `CurrencyCatalogue` resource
|
3. Add to the `CurrencyCatalogue` resource (`ts_currency_catalogue.tres`)
|
||||||
|
|
||||||
**New Generator:**
|
**New Generator:**
|
||||||
1. Create `res://sandbox/generators/<name>.tres` (CurrencyGeneratorData)
|
1. Create `res://docs/gyms/tiny_sword/buildings/<name>/<name>_generator.tres` (extend `CurrencyGeneratorData`)
|
||||||
2. Configure production stats, costs, purchase currency
|
2. Configure production stats, costs, purchase currency, optional `unlock_goal`
|
||||||
3. Optionally add `unlock_goal`
|
3. Add a `CurrencyGenerator` node to the scene referencing this data
|
||||||
4. Add `CurrencyGenerator` node to scene
|
|
||||||
|
|
||||||
**New Buff:**
|
**New Buff:**
|
||||||
1. Create `res://sandbox/buffs/<name>.tres` (GeneratorBuffData)
|
1. Create `res://docs/gyms/tiny_sword/buffs/<name>.tres` (extend `GeneratorBuffData`)
|
||||||
2. Set `target_ids` (e.g., `["farm", "forestry"]` or `["*"]`)
|
2. Set `target_ids` (e.g., `["farm", "forestry"]` or `["*"]` for all generators)
|
||||||
3. Configure effect, cost, unlock goal
|
3. Configure `kind`, `effect_increment`, cost, and optional `unlock_goal`
|
||||||
4. Add to `BuffCatalogue` resource
|
4. Add to the `BuffCatalogue` resource (`ts_buff_catalogue.tres`)
|
||||||
|
|
||||||
**New Research:**
|
**New Research:**
|
||||||
1. Create `res://sandbox/research/<name>.tres` (ResearchData)
|
1. Create `res://docs/gyms/tiny_sword/research/<name>.tres` (extend `ResearchData`)
|
||||||
2. Link to generator via `generator_id`
|
2. Link to a generator via `generator_id`
|
||||||
3. Configure XP and multiplier parameters
|
3. Configure `xp_per_currency_produced`, `base_xp_required`, `xp_growth_multiplier`, `multiplier_per_level`
|
||||||
4. Add to `ResearchCatalogue` resource
|
4. Add to the `ResearchCatalogue` resource (`ts_research_catalogue.tres`)
|
||||||
|
|
||||||
### Testing
|
### BigNumber System
|
||||||
|
|
||||||
```bash
|
- **Representation**: `mantissa: float` × `10^exponent: int`
|
||||||
# Run project and test manually
|
- **Range**: Values up to ~10^308 before float precision loss
|
||||||
"$GODOT_BIN" --path .
|
- **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.
|
||||||
|
|
||||||
# No automated test framework committed yet
|
### Production Formulas
|
||||||
# (GUT not included in repository)
|
|
||||||
|
```
|
||||||
|
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
|
## Known Issues / TODOs
|
||||||
|
|
||||||
- [ ] Manual save triggers not implemented (auto-save needed)
|
- [ ] Periodic auto-save not implemented (saves only on prestige and manual trigger)
|
||||||
- [ ] `GeneratorPanel` has missing `mouse_entered`/`mouse_exited` handlers
|
|
||||||
- [ ] Some buffs configured locked with no unlock path
|
|
||||||
- [ ] No automated test suite
|
- [ ] No automated test suite
|
||||||
|
- [ ] Some buffs may be configured with no unlock path
|
||||||
## Current Status
|
|
||||||
|
|
||||||
Research system fully implemented with:
|
|
||||||
- XP-based progression tied to production
|
|
||||||
- Auto-leveling with BigNumber support
|
|
||||||
- Buff multipliers for XP gain
|
|
||||||
- Save format version 5 with research persistence
|
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
### BigNumber System
|
|
||||||
- **Representation**: Mantissa (float) + Exponent (int)
|
|
||||||
- **Range**: Handles values up to ~10^308 (float precision limit)
|
|
||||||
- **Operations**: Add, subtract, multiply, divide, compare
|
|
||||||
- **Optimization**: `add_in_place()` for performance-critical loops
|
|
||||||
|
|
||||||
### Production Formulas
|
|
||||||
```
|
|
||||||
Cost for N items: base * ratio^k * ((ratio^n - 1) / (ratio - 1))
|
|
||||||
Max affordable: log((currency*(ratio-1)/(base*ratio^k)) + 1) / log(ratio)
|
|
||||||
Production: base_productivity * owned * run_mult * milestone_mult * purchased_mult
|
|
||||||
```
|
|
||||||
|
|
||||||
### Buff Multiplier Stacking
|
### Buff Multiplier Stacking
|
||||||
Multiple buffs of the same kind stack **multiplicatively**:
|
|
||||||
|
Multiple buffs of the same kind on the same generator stack **multiplicatively**:
|
||||||
|
|
||||||
```
|
```
|
||||||
total_multiplier = buff1_effect * buff2_effect * buff3_effect * ...
|
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
|
## License
|
||||||
|
|
||||||
Internal prototype - no external license applied.
|
Internal prototype — no external license applied.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: Refactoring plan documented*
|
|
||||||
*Godot version: 4.6*
|
*Godot version: 4.6*
|
||||||
|
|||||||
135
core/README.md
135
core/README.md
@@ -37,6 +37,141 @@ core/
|
|||||||
4. **Goal Check**: Currency changed → goals evaluated → buffs unlocked
|
4. **Goal Check**: Currency changed → goals evaluated → buffs unlocked
|
||||||
5. **Save**: `LevelGameState.save_game()` → JSON to `user://level_save.json`
|
5. **Save**: `LevelGameState.save_game()` → JSON to `user://level_save.json`
|
||||||
|
|
||||||
|
## Production Multiplier Chain
|
||||||
|
|
||||||
|
All multipliers compose multiplicatively from callee to caller. The entry point is
|
||||||
|
`_grant_cycle_income()` in `CurrencyGenerator`.
|
||||||
|
|
||||||
|
### Entry: `CurrencyGenerator._grant_cycle_income()` (`currency_generator.gd:134`)
|
||||||
|
|
||||||
|
```
|
||||||
|
var effective = get_effective_auto_run_multiplier()
|
||||||
|
var per_cycle = data.production_per_cycle(owned, effective, purchased_count)
|
||||||
|
var produced = per_cycle × cycle_count
|
||||||
|
```
|
||||||
|
|
||||||
|
### Layer 1 — `CurrencyGeneratorData.production_per_cycle()` (`currency_generator_data.gd:117`)
|
||||||
|
|
||||||
|
```
|
||||||
|
production_per_cycle = initial_productivity × owned × run_multiplier × milestone_mult × purchased_mult
|
||||||
|
```
|
||||||
|
|
||||||
|
| Sub-multiplier | Method | Formula |
|
||||||
|
|---|---|---|
|
||||||
|
| **milestone_mult** | `milestone_multiplier_total(owned)` | `milestone_multiplier ^ floor(owned / milestone_step)` |
|
||||||
|
| **purchased_mult** | `purchased_multiplier(purchased)` | `1.0 + purchased × (purchased_boost_percent / 100)` |
|
||||||
|
|
||||||
|
### Layer 2 — `CurrencyGenerator.get_effective_auto_run_multiplier()` (`currency_generator.gd:357`)
|
||||||
|
|
||||||
|
This is the `run_multiplier` value passed into Layer 1 above:
|
||||||
|
|
||||||
|
```
|
||||||
|
effective_run_multiplier = run_multiplier × research_multiplier × auto_production_buffs × prestige_multiplier
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2a. `run_multiplier`
|
||||||
|
|
||||||
|
Exported `float` on the `CurrencyGenerator` node. Default `1.0`. A scene-level tweak.
|
||||||
|
|
||||||
|
#### 2b. `research_multiplier` → `LevelGameState.get_research_multiplier(id)` (`level_game_state.gd:488`) → `ResearchData.get_multiplier_for_level(level)` (`research/research_data.gd:52`)
|
||||||
|
|
||||||
|
```
|
||||||
|
research_multiplier = base_multiplier + (multiplier_per_level × research_level)
|
||||||
|
```
|
||||||
|
|
||||||
|
Level is auto-calculated from accumulated BigNumber XP. Both constants are exports on `ResearchData`.
|
||||||
|
|
||||||
|
#### 2c. `auto_production_buffs` → `LevelGameState.get_effective_multiplier(generator_id, AUTO_PRODUCTION_MULTIPLIER)` (`level_game_state.gd:441`)
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# For every active buff of kind AUTO_PRODUCTION_MULTIPLIER targeting this generator:
|
||||||
|
mult = 1.0
|
||||||
|
for buff in buffs:
|
||||||
|
if buff.active and buff.kind == AUTO_PRODUCTION_MULTIPLIER:
|
||||||
|
mult *= buff.get_effect_multiplier(level)
|
||||||
|
```
|
||||||
|
|
||||||
|
`GeneratorBuffData.get_effect_multiplier(level)` (`generator_buff_data.gd:97`):
|
||||||
|
|
||||||
|
```
|
||||||
|
buff_effect = base_effect + (effect_increment × level)
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple buffs of the same kind stack **multiplicatively**: `∏ (base_effect_i + increment_i × level_i)`.
|
||||||
|
|
||||||
|
#### 2d. `prestige_multiplier` → `PrestigeManager.get_total_multiplier()` (`prestige_manager.gd:107`)
|
||||||
|
|
||||||
|
Configured via `PrestigeConfig.multiplier_mode`:
|
||||||
|
|
||||||
|
| Mode | Formula |
|
||||||
|
|---|---|
|
||||||
|
| `ADDITIVE` | `base + prestige_points × multiplier_per_prestige` |
|
||||||
|
| `MULTIPLICATIVE_POWER` | `base × (1 + multiplier_per_prestige) ^ (prestige_points ^ exponent)` |
|
||||||
|
|
||||||
|
### Layer 3 — Production per second
|
||||||
|
|
||||||
|
```
|
||||||
|
production_per_second = production_per_cycle / maxf(initial_time, 0.0001)
|
||||||
|
```
|
||||||
|
|
||||||
|
(`currency_generator_data.gd:128`)
|
||||||
|
|
||||||
|
### Full Formula (one production cycle)
|
||||||
|
|
||||||
|
```
|
||||||
|
produced = initial_productivity × owned
|
||||||
|
|
||||||
|
# --- effective_run_multiplier ---
|
||||||
|
× run_multiplier
|
||||||
|
× (base_multiplier + multiplier_per_level × research_level)
|
||||||
|
× ∏(base_effect_i + effect_increment_i × buff_level_i) [auto-production buffs]
|
||||||
|
× prestige_multiplier [from PrestigeManager]
|
||||||
|
|
||||||
|
# --- milestone & purchased ---
|
||||||
|
× milestone_multiplier ^ floor(owned / milestone_step)
|
||||||
|
× (1.0 + purchased_count × purchased_boost_percent / 100)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Click Formula (separate path)
|
||||||
|
|
||||||
|
`_try_grant_click_currency()` (`currency_generator.gd:460`):
|
||||||
|
|
||||||
|
```
|
||||||
|
click_reward = (click_mantissa × 10^click_exponent) × ∏ buff_effect_i [MANUAL_CLICK_MULTIPLIER buffs]
|
||||||
|
```
|
||||||
|
|
||||||
|
Uses the same `get_effective_multiplier()` loop filtered to `BuffKind.MANUAL_CLICK_MULTIPLIER`.
|
||||||
|
Research, prestige, milestone, and purchased multipliers are **not** applied to clicks.
|
||||||
|
|
||||||
|
### Research XP Awarded (production side-effect)
|
||||||
|
|
||||||
|
Awarded inside `_grant_cycle_income()` when the generator has an associated `ResearchData`:
|
||||||
|
|
||||||
|
```
|
||||||
|
base_xp = produced_currency × xp_per_currency_produced
|
||||||
|
scaled_xp = base_xp × (1.0 + research_workers × worker_scaling_factor)
|
||||||
|
actual_xp = scaled_xp × ∏ buff_effect_i [RESEARCH_XP_MULTIPLIER buffs]
|
||||||
|
```
|
||||||
|
|
||||||
|
Buff multiplier for XP is applied later in `LevelGameState.add_research_xp()`
|
||||||
|
via `ResearchBuffCalculator.apply_buffs()` (`core/generator/research_buff_calculator.gd`).
|
||||||
|
|
||||||
|
### Cascade Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ run_multiplier (node export) │
|
||||||
|
│ research_multiplier (XP level) │─── effective_run_multiplier ──┐
|
||||||
|
│ auto-production buffs (∏) │ │
|
||||||
|
│ prestige_multiplier │ │
|
||||||
|
└─────────────────────────────────┘ │
|
||||||
|
▼
|
||||||
|
production_per_cycle = initial_productivity × owned × effective_run_multiplier × milestone × purchased
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
production_per_second = production_per_cycle / initial_time
|
||||||
|
```
|
||||||
|
|
||||||
## Save Format
|
## Save Format
|
||||||
|
|
||||||
**Version**: 5
|
**Version**: 5
|
||||||
|
|||||||
Reference in New Issue
Block a user