From 85bbe519565feba3009f1bfdef45fb99b7de2671 Mon Sep 17 00:00:00 2001 From: Michele Rossi Date: Sun, 29 Mar 2026 15:24:13 +0200 Subject: [PATCH] Cleanup and planning --- README.md | 449 ++++++++++------------- REFACTORING.md | 433 ++++++++++++++++++++++ core/generator-unlock-goals/TECH_SPEC.md | 58 --- core/generator/currency_generator.tscn | 4 - core/generator/generator_buff_data.gd | 13 + docs/gyms/generator_gym.tscn | 78 ---- idles/buffs/bigger_forest.tres | 18 - idles/buffs/library_auto_flux.tres | 18 - idles/buffs/orb_auto_flux.tres | 18 - idles/buffs/orb_click_focus.tres | 19 - idles/buffs/orb_summon_spirit.tres | 20 - idles/currencies/knowledge.tres | 10 - idles/currencies/magic.tres | 10 - idles/currencies/spirit.tres | 9 - idles/currencies/wood.tres | 10 - idles/generators/forestry.tres | 23 -- idles/generators/library.tres | 25 -- idles/generators/monastery.tres | 12 - idles/generators/orb.tres | 19 - idles/generators/spirit_factory.tres | 18 - idles/goals/magic_350k_wood_20k.tres | 24 -- idles/goals/magic_total_1300.tres | 16 - idles/goals/magic_total_13k.tres | 16 - idles/goals/magic_total_30.tres | 15 - idles/prestige/primary_prestige.tres | 25 -- 25 files changed, 635 insertions(+), 725 deletions(-) create mode 100644 REFACTORING.md delete mode 100644 core/generator-unlock-goals/TECH_SPEC.md delete mode 100644 docs/gyms/generator_gym.tscn delete mode 100644 idles/buffs/bigger_forest.tres delete mode 100644 idles/buffs/library_auto_flux.tres delete mode 100644 idles/buffs/orb_auto_flux.tres delete mode 100644 idles/buffs/orb_click_focus.tres delete mode 100644 idles/buffs/orb_summon_spirit.tres delete mode 100644 idles/currencies/knowledge.tres delete mode 100644 idles/currencies/magic.tres delete mode 100644 idles/currencies/spirit.tres delete mode 100644 idles/currencies/wood.tres delete mode 100644 idles/generators/forestry.tres delete mode 100644 idles/generators/library.tres delete mode 100644 idles/generators/monastery.tres delete mode 100644 idles/generators/orb.tres delete mode 100644 idles/generators/spirit_factory.tres delete mode 100644 idles/goals/magic_350k_wood_20k.tres delete mode 100644 idles/goals/magic_total_1300.tres delete mode 100644 idles/goals/magic_total_13k.tres delete mode 100644 idles/goals/magic_total_30.tres delete mode 100644 idles/prestige/primary_prestige.tres diff --git a/README.md b/README.md index 188cc30..bb52871 100644 --- a/README.md +++ b/README.md @@ -1,261 +1,190 @@ -# Idles - Systems Architecture Report +# 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. + +## 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 | +| **Currency** | `core/currency/`, `core/currency_database.gd` | Catalog system for all in-game currencies | +| **GameState** | `core/game_state.gd` | Central state authority (currencies, generators, buffs, persistence) | +| **Generators** | `core/generator/` | Production mechanics (auto cycles, clicks, purchases) | +| **Buffs** | `core/generator/generator_buff_data.gd` | Global multipliers with multi-target support | +| **Goals** | `core/goals/` | Unlock conditions for generators and buffs | +| **Prestige** | `core/prestige/` | Reset-with-bonus mechanics | + +### Autoload Singletons + +| Autoload | Script | Description | +|----------|--------|-------------| +| `GameState` | `core/game_state.gd` | Central state management, save/load | +| `CurrencyDatabase` | `core/currency_database.gd` | Currency catalog discovery | +| `PrestigeManager` | `core/prestige/prestige_manager.gd` | Prestige system | + +### Data Directory Structure + +``` +sandbox/ +├── currencies/ # Currency resources (gold, food, wood, worker, etc.) +├── generators/ # Generator configuration (.tres files) +├── buffs/ # Buff definitions with target_ids +├── goals/ # Unlock goal definitions +└── prestige/ # Prestige configuration +``` + +## Current Architecture (Post-Refactoring) + +### Decoupled Buff System + +Buffs are now **globally registered** and **multi-target capable**: + +- **Global Levels**: Buff levels are shared across all targets +- **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 + +| Feature | Implementation | +|---------|----------------| +| **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 + +**Old API (per-generator state):** +```gdscript +GameState.register_generator_buff(generator_id, buff_id, level) +GameState.get_generator_buff_level(generator_id, buff_id) +``` + +**New API (global buff state):** +```gdscript +GameState.register_buff(buff: GeneratorBuffData) +GameState.get_buff(buff_id) -> GeneratorBuffData +GameState.get_buffs_for_generator(generator_id) -> Array[GeneratorBuffData] +GameState.get_effective_multiplier(generator_id, kind) -> float +``` + +## Save Format + +**Version 2 (current):** +```json +{ + "save_format_version": 2, + "currencies": { ... }, + "generator_states": { ... }, + "buff_definitions": { ... }, + "buff_levels": { "farm_flux": 5 }, + "buff_unlocked": { "farm_flux": true }, + "buff_active": { "farm_flux": true }, + "last_save_time": 1234567890 +} +``` + +**Note**: Breaking change from v1 - old saves are incompatible. + +## Development + +### Adding New Content + +**New Currency:** +1. Create `res://sandbox/currencies/.tres` (Currency resource) +2. Set `id`, `display_name`, `icon` +3. Auto-discovered at runtime + +**New Generator:** +1. Create `res://sandbox/generators/.tres` (CurrencyGeneratorData) +2. Configure production stats, costs, purchase currency +3. Optionally add `unlock_goal` +4. Add `CurrencyGenerator` node to scene + +**New Buff:** +1. Create `res://sandbox/buffs/.tres` (GeneratorBuffData) +2. Set `target_ids` (e.g., `["farm", "forestry"]` or `["*"]`) +3. Configure effect, cost, unlock goal +4. Auto-registered at runtime + +### Testing + +```bash +# Run project and test manually +"$GODOT_BIN" --path . + +# No automated test framework committed yet +# (GUT not included in repository) +``` + +## Known Issues / TODOs + +- [ ] Manual save triggers not implemented (auto-save needed) +- [ ] `CurrencyTile` references `GameState.GOLD_CURRENCY_ID` (constant missing) +- [ ] `GeneratorPanel` has missing `mouse_entered`/`mouse_exited` handlers +- [ ] Some buffs configured locked with no unlock path +- [ ] No automated test suite + +## Refactoring Status + +See `REFACTORING.md` for: +- Complete refactoring plan (8 phases) +- Implementation timeline (15-23 hours estimated) +- Testing checklist +- Rollback procedures + +### Completed Phases +- Phase 1: GeneratorBuffData with target_ids support + +### Pending Phases +- Phase 2-8: GameState extension, save format update, data migration + +## 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 +Multiple buffs of the same kind stack **multiplicatively**: +``` +total_multiplier = buff1_effect * buff2_effect * buff3_effect * ... +``` + +## License + +Internal prototype - no external license applied. + +--- -## 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. +*Last updated: Refactoring plan documented* +*Godot version: 4.6* diff --git a/REFACTORING.md b/REFACTORING.md new file mode 100644 index 0000000..83a36ae --- /dev/null +++ b/REFACTORING.md @@ -0,0 +1,433 @@ +# Refactoring Plan: Decoupled Buff System + +## Overview +Decouple buffs from generators to enable: +- Global buff levels shared across all targets +- Multi-target buffs (including wildcards for all current + future generators) +- Automatic buff activation via goal achievement +- Clean separation between buff registry and generator state +- Flexible UI patterns (global buff shop, per-generator panels, debug controls) + +## Current State (Problem) +- Buffs stored in `CurrencyGeneratorData.buffs` array (tight coupling) +- Buff levels tracked per-generator in `GameState.generator_buff_levels[generator_id][buff_id]` +- Buff resources have no `target_ids` - don't know which generators they affect +- Cannot create global buffs or multi-target buffs +- Buff logic scattered across `CurrencyGenerator` and `GameState` + +## Target State (Solution) +- Buff registry in `GameState._buff_definitions` (global, auto-discovered from `res://sandbox/buffs/`) +- Buff levels stored globally: `GameState._buff_levels[buff_id]` +- Buff resources have `target_ids: Array[StringName]` (supports `["*"]` for wildcards) +- Generators query `GameState.get_buffs_for_generator(generator_id)` for applicable buffs +- Multipliers calculated in `GameState.get_effective_multiplier(generator_id, kind)` + +--- + +## Implementation Phases + +### Phase 1: Enhance GeneratorBuffData (Safe, Non-Breaking) +**File**: `core/generator/generator_buff_data.gd` + +**Add:** +```gdscript +@export var target_ids: Array[StringName] = [] + +func targets_generator(generator_id: StringName) -> bool: + if target_ids.is_empty(): + return false + if "*" in target_ids: + return true + return generator_id in target_ids + +func get_target_generators() -> Array[StringName]: + return target_ids.duplicate() +``` + +**Timeline**: 1-2 hours +**Risk**: Low (additive change, backward compatible) +**Testing**: Verify existing buffs work with empty target_ids + +--- + +### Phase 2: Extend GameState with Buff Registry +**File**: `core/game_state.gd` + +**Add state variables:** +```gdscript +var _buff_definitions: Dictionary = {} # buff_id → GeneratorBuffData +var _buff_levels: Dictionary = {} # buff_id → int +var _buff_unlocked: Dictionary = {} # buff_id → bool +var _buff_active: Dictionary = {} # buff_id → bool (auto-set when unlocked) + +signal buff_unlocked_changed(buff_id: StringName, unlocked: bool) +signal buff_level_changed(buff_id: StringName, new_level: int) +``` + +**Add registry methods:** +```gdscript +func register_buff(buff: GeneratorBuffData) -> void +func get_buff(buff_id: StringName) -> GeneratorBuffData +func get_all_buffs() -> Array[GeneratorBuffData] +func get_buff_level(buff_id: StringName) -> int +func set_buff_level(buff_id: StringName, level: int) -> void +func is_buff_unlocked(buff_id: StringName) -> bool +func set_buff_unlocked(buff_id: StringName, unlocked: bool) -> void +func is_buff_active(buff_id: StringName) -> bool +func get_generators_targeted_by(buff_id: StringName) -> Array[StringName] +func get_buffs_for_generator(generator_id: StringName) -> Array[GeneratorBuffData] +func get_effective_multiplier(generator_id: StringName, kind: int) -> float +``` + +**Add goal evaluation helper:** +```gdscript +func _try_unlock_buff_from_goal(buff: GeneratorBuffData) -> void +``` + +**Timeline**: 4-6 hours +**Risk**: High (core state management) +**Testing**: Unit tests for each method, verify goal-based unlocks + +--- + +### Phase 3: Update Save/Load System +**File**: `core/game_state.gd` + +**New save format (v2):** +```json +{ + "save_format_version": 2, + "currencies": { ... }, + "generator_states": { ... }, + "buff_definitions": { ... }, + "buff_levels": { ... }, + "buff_unlocked": { ... }, + "buff_active": { ... }, + "last_save_time": 1234567890 +} +``` + +**Add serialization helpers:** +```gdscript +func _serialize_buff_definitions() -> Dictionary +func _serialize_buff_data(buff: GeneratorBuffData) -> Dictionary +func _deserialize_buff_definitions(raw: Variant) -> void +``` + +**Version check in load_game():** +```gdscript +if version < 2: + push_error("Save file version %d too old. Please start fresh." % version) + return +``` + +**Timeline**: 3-4 hours +**Risk**: High (data loss if bugs exist) +**Testing**: Save/load cycles, verify buff state persists, test version rejection + +--- + +### Phase 4: Update CurrencyGenerator +**File**: `core/generator/currency_generator.gd` + +**Changes:** +```gdscript +# Replace: +func get_buffs() -> Array[GeneratorBuffData] # Now queries GameState + +func _get_multiplier_for_buff_kind(kind: int) -> float: # Delegates to GameState + return GameState.get_effective_multiplier(_generator_id, kind) + +# Update _register_buffs() to only evaluate unlock goals +func _register_buffs() -> void: + for buff in get_buffs(): + if buff == null: + continue + var buff_id: StringName = buff.id + if not GameState.get_buff(buff_id): + GameState.register_buff(buff) + _try_unlock_buff_from_goal(buff) +``` + +**Timeline**: 2-3 hours +**Risk**: Medium (runtime behavior change) +**Testing**: Verify production multipliers, buff purchases, goal unlocks + +--- + +### Phase 5: Update PrestigeManager +**File**: `core/prestige/prestige_manager.gd` + +**Add buff reset logic:** +```gdscript +func perform_prestige() -> bool: + # ... existing logic ... + GameState.reset_for_prestige(true, false) + _reset_all_buff_levels() + # ... rest of logic ... + +func _reset_all_buff_levels() -> void: + for buff_id in GameState._buff_levels.keys(): + GameState.set_buff_level(buff_id, 0) + GameState.set_buff_unlocked(buff_id, false) +``` + +**Timeline**: 1-2 hours +**Risk**: Low +**Testing**: Verify buff levels reset after prestige + +--- + +### Phase 6: Update UI Components +**File**: `core/generator/generator_container.gd` + +**Minimal changes needed** - `GeneratorPanel._build_buff_rows()` should work automatically since it uses `_generator.get_buffs()`. + +**Optional: Add Global Buff Panel** +Create `res://ui/global_buff_panel.gd` for testing/future UI: +```gdscript +extends PanelContainer + +func _build_buff_list() -> void: + for buff in GameState.get_all_buffs(): + if GameState.is_buff_hidden(buff.id): + continue + # Create UI row showing buff state +``` + +**Timeline**: 1-2 hours (optional) +**Risk**: Low +**Testing**: Verify buff UI updates on level/unlock changes + +--- + +### Phase 7: Data Migration (One-Time Manual) +**Manual steps:** + +1. **Update `res://sandbox/buffs/*.tres`:** + - Open each buff in Godot editor + - Add `target_ids` array (e.g., `["farm", "forestry"]` or `["*"]`) + +2. **Update `res://sandbox/generators/*.tres`:** + - Remove `buffs` array field + - (Optional) Add `expected_buff_ids` for documentation + +3. **Delete old saves:** + - `user://idle_save.json` - starts fresh with v2 format + +**Timeline**: 1 hour +**Risk**: Low (data files only) +**Testing**: Load game, verify all buffs work correctly + +--- + +### Phase 8: Buff Auto-Discovery System (Bonus Feature) +**New file**: `core/buff_database.gd` + +```gdscript +extends Node + +const BUFF_DIRECTORY_PATH: String = "res://sandbox/buffs" + +var _buff_by_id: Dictionary = {} +var _initialized: bool = false + +func _ready() -> void: + _initialize_buff_catalog() + +func _initialize_buff_catalog() -> void: + _buff_by_id.clear() + var dir: DirAccess = DirAccess.open(BUFF_DIRECTORY_PATH) + if dir == null: + push_warning("Unable to open buff directory: %s" % BUFF_DIRECTORY_PATH) + return + + dir.list_dir_begin() + var entry_name: String = dir.get_next() + while not entry_name.is_empty(): + if not dir.current_is_dir() and entry_name.ends_with(".tres"): + var path: String = "%s/%s" % [BUFF_DIRECTORY_PATH, entry_name] + var buff: GeneratorBuffData = load(path) as GeneratorBuffData + if buff != null: + GameState.register_buff(buff) + entry_name = dir.get_next() + dir.list_dir_end() + +func get_all_buffs() -> Array[GeneratorBuffData]: + return _buff_by_id.values() + +func get_buff(buff_id: StringName) -> GeneratorBuffData: + return _buff_by_id.get(buff_id) +``` + +**Add `BuffDatabase` to project.godot autoloads** + +**Timeline**: 2-3 hours +**Risk**: Low +**Testing**: Verify all buffs auto-load at runtime + +--- + +## Timeline Summary + +| Phase | Duration | Risk | +|-------|----------|------| +| Phase 1: GeneratorBuffData | 1-2h | Low | +| Phase 2: GameState Extension | 4-6h | High | +| Phase 3: Save/Load Update | 3-4h | High | +| Phase 4: CurrencyGenerator | 2-3h | Medium | +| Phase 5: PrestigeManager | 1-2h | Low | +| Phase 6: UI Updates | 1-2h | Low | +| Phase 7: Data Migration | 1h | Low | +| Phase 8: Buff Auto-Discovery | 2-3h | Low | +| **Total** | **15-23 hours** | | + +--- + +## Testing Checklist + +- [ ] Buff with `target_ids: ["farm", "forestry"]` applies to both +- [ ] Buff with `target_ids: ["*"]` applies to all current + future generators +- [ ] Buying a buff level increases global level (not per-generator) +- [ ] Buff unlock goal automatically activates buff when met +- [ ] Generator production reflects active buff multipliers +- [ ] Save/load preserves buff levels and unlock states +- [ ] Prestige resets all buff levels to 0 +- [ ] Adding new generator auto-includes wildcard buffs +- [ ] Multiple buff kinds stack multiplicatively +- [ ] Inactive (locked) buffs don't apply multipliers +- [ ] Buff definitions auto-load from `res://sandbox/buffs/` +- [ ] New buff resources appear in registry without code changes + +--- + +## Rollback Plan + +If issues arise: + +1. **Revert code changes** - Use git to restore previous state +2. **Delete user://idle_save.json** - Start fresh with v1 format +3. **Restore buff/generator .tres files** - Remove target_ids, restore buffs arrays +4. **Remove GameState buff methods** - Restore original API + +**Note**: No save migration code - breaking change requires fresh starts + +--- + +## Success Criteria + +- [ ] All generators produce correct amounts with active buffs +- [ ] Buff UI can display global buff list or per-generator view +- [ ] Save files load correctly and preserve buff state +- [ ] Prestige resets buff levels as expected +- [ ] New buffs can be added by dropping .tres files in sandbox/buffs/ +- [ ] Wildcard buffs auto-apply to new generators +- [ ] No performance degradation in _process loop + +--- + +## Future Enhancements (Post-Implementation) + +1. **Buff synergies**: "If you have X buff, Y buff gets +10%" +2. **Buff tiers**: Common/rare/legendary classification +3. **Conditional buffs**: "Only active if generator_ownership > 10" +4. **Buff stacking rules**: Additive vs multiplicative vs highest-only +5. **Prestige-only buffs**: Permanent buffs unlocked via prestige currency +6. **Buff UI shop**: Global buff purchase interface +7. **Buff preview**: Show "what-if" calculations before purchase + +--- + +## Technical Notes + +### Architecture Decisions + +| Decision | Implementation | +|----------|----------------| +| **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/unlocked = false, auto-activates on goal met | +| **Persistence** | Buff definitions serialized to save (by id) | +| **Prestige** | All buff levels reset to 0 | +| **Activation** | Automatic via goals, no manual toggle | + +### Key API Changes + +**Old API (per-generator state):** +```gdscript +GameState.register_generator_buff(generator_id, buff_id, level) +GameState.get_generator_buff_level(generator_id, buff_id) +GameState.is_generator_buff_unlocked(generator_id, buff_id) +``` + +**New API (global buff state):** +```gdscript +GameState.register_buff(buff: GeneratorBuffData) +GameState.get_buff(buff_id) -> GeneratorBuffData +GameState.get_buff_level(buff_id) -> int +GameState.is_buff_unlocked(buff_id) -> bool +GameState.get_buffs_for_generator(generator_id) -> Array[GeneratorBuffData] +GameState.get_effective_multiplier(generator_id, kind) -> float +``` + +### Save Format Migration + +**Version 1 (old - incompatible):** +```json +{ + "currencies": { ... }, + "generator_states": { ... }, + "generator_buff_levels": { "farm": { "farm_flux": 5 } }, + "generator_buff_unlocked": { "farm": { "farm_flux": true } } +} +``` + +**Version 2 (new):** +```json +{ + "save_format_version": 2, + "currencies": { ... }, + "generator_states": { ... }, + "buff_definitions": { "farm_flux": { ... } }, + "buff_levels": { "farm_flux": 5 }, + "buff_unlocked": { "farm_flux": true }, + "buff_active": { "farm_flux": true } +} +``` + +--- + +## Dependencies + +- Godot 4.6+ (current project version) +- Existing `BigNumber` system for currency math +- Existing `GameState` autoload +- Existing `GoalData` and `GoalRequirementData` for unlock conditions + +--- + +## Risks & Mitigations + +| Risk | Mitigation | +|------|------------| +| Save format incompatibility | Clear version check, error on old saves | +| Performance in _process loop | Cache multiplier calculations, only recalc on buff changes | +| Buff definition loading failures | Graceful degradation, warn but continue | +| Wildcard expansion at runtime | Explicit registration in generator _ready() | +| Multiple buffs of same kind | Multiplicative stacking (document clearly) | + +--- + +## Approval Status + +- [ ] Architecture approved +- [ ] Implementation phases reviewed +- [ ] Timeline accepted +- [ ] Risks understood +- [ ] Ready to begin Phase 1 + +--- + +*Last updated: Initial planning document* +*Status: Pending implementation approval* diff --git a/core/generator-unlock-goals/TECH_SPEC.md b/core/generator-unlock-goals/TECH_SPEC.md deleted file mode 100644 index ee8d4d8..0000000 --- a/core/generator-unlock-goals/TECH_SPEC.md +++ /dev/null @@ -1,58 +0,0 @@ -# Generator-Embedded Unlock Goals - Technical Specification - -## Document Status -- Version: 2.0 -- Date: 2026-03-21 -- Scope: Unlock generators from `CurrencyGeneratorData.unlock_goal` when goal thresholds are reached. - -## Problem Statement -Generator unlock progression should be authored where generator behavior lives: `CurrencyGeneratorData`. -The previous scene-level target mapping layer increased setup complexity and created mismatch risk between goal targets and scene content. - -## Current Baseline -1. Generator state persists in `GameState.generator_states` (`owned`, `purchased_count`, `unlocked`, `available`). -2. `CurrencyGenerator` already gates interactions using `is_available_to_player()`. -3. Goal primitives remain reusable and data-driven: - - `GoalRequirementData` - - `GoalData` -4. Generator data now owns unlock definition via `unlock_goal: GoalData`. - -## Functional Requirements -1. A generator may define one optional unlock goal (`CurrencyGeneratorData.unlock_goal`). -2. Goal completion uses logical AND across requirements. -3. Requirement checks use total acquired currency (`GameState.get_total_currency_acquired_by_id`). -4. Unlock evaluation runs: - - once on generator `_ready()` - - on every `GameState.currency_changed` -5. When a goal is met, runtime sets: - - `GameState.set_generator_unlocked(generator_id, true)` - - `GameState.set_generator_available(generator_id, true)` -6. Unlock transitions are idempotent. -7. Unlock completion emits `CurrencyGenerator.goal_achieved(generator_id, goal_id)` for hooks/UI. - -## Runtime Design -1. `CurrencyGeneratorData` exposes: - - `has_unlock_goal()` - - `is_unlock_goal_met()` - - `get_unlock_goal_id()` -2. `CurrencyGenerator` executes `_evaluate_generator_unlock_goal()`. -3. No scene-level unlock controller is required. -4. Goals debug UI discovers goals from scene generators instead of external target-mapping resources. - -## Data Authoring Rules -1. Configure locked generators with `starts_unlocked = false` and `starts_available = false`. -2. Set `unlock_goal` directly on that generator `.tres` resource. -3. Keep `GoalData.id` unique and stable. -4. Goal data can still be shared across systems (generator unlocks, buff unlocks). - -## Save/Load Behavior -1. Unlock persistence remains unchanged because `GameState` stores `unlocked/available`. -2. Re-evaluation after load is safe due to idempotent state writes. - -## Validation -1. Run headless parse: `"$GODOT_BIN" --headless --path . --quit` -2. Manual smoke test in `generator_museum`: - - verify locked generator starts unavailable - - grant required currency - - verify generator unlocks automatically - - verify state persists after restart diff --git a/core/generator/currency_generator.tscn b/core/generator/currency_generator.tscn index 3d87283..c34cb64 100644 --- a/core/generator/currency_generator.tscn +++ b/core/generator/currency_generator.tscn @@ -1,10 +1,6 @@ [gd_scene format=3 uid="uid://jeoiinukrrsp"] [ext_resource type="Script" uid="uid://dtbxopw6ulhl8" path="res://core/generator/currency_generator.gd" id="1_4n4ca"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_5tmvy"] -[ext_resource type="Resource" uid="uid://co0mcc2kvcpo5" path="res://idles/generators/orb.tres" id="3_wx13b"] [node name="CurrencyGenerator" type="Node2D" unique_id=967969064] script = ExtResource("1_4n4ca") -currency = ExtResource("2_5tmvy") -data = ExtResource("3_wx13b") diff --git a/core/generator/generator_buff_data.gd b/core/generator/generator_buff_data.gd index 916b94c..535ea83 100644 --- a/core/generator/generator_buff_data.gd +++ b/core/generator/generator_buff_data.gd @@ -10,6 +10,7 @@ enum BuffKind { const HUGE_EXPONENT: int = 1000000 @export var id: StringName = &"" +@export var target_ids: Array[StringName] = [] @export var kind: BuffKind = BuffKind.AUTO_PRODUCTION_MULTIPLIER @export_multiline var text: String = "" @export var icon: Texture2D @@ -35,6 +36,18 @@ const HUGE_EXPONENT: int = 1000000 @export var resource_purchase_base_exponent: int = 0 @export var resource_purchase_increment_multiplier: float = 1.2 +func targets_generator(generator_id: StringName) -> bool: + if target_ids.is_empty(): + return false + + if target_ids.has("*"): + return true + + return target_ids.has(generator_id) + +func get_target_generators() -> Array[StringName]: + return target_ids.duplicate() + func has_unlock_goal() -> bool: if unlock_goal == null: return false diff --git a/docs/gyms/generator_gym.tscn b/docs/gyms/generator_gym.tscn deleted file mode 100644 index 5354038..0000000 --- a/docs/gyms/generator_gym.tscn +++ /dev/null @@ -1,78 +0,0 @@ -[gd_scene format=3 uid="uid://cfryecxmcg8hw"] - -[ext_resource type="PackedScene" uid="uid://jeoiinukrrsp" path="res://core/generator/currency_generator.tscn" id="1_6pne4"] -[ext_resource type="Resource" uid="uid://bnhqk8b31mm4e" path="res://idles/currencies/knowledge.tres" id="2_8qilt"] -[ext_resource type="Resource" uid="uid://l0pn6mlcer7t" path="res://idles/currencies/spirit.tres" id="2_jlqd0"] -[ext_resource type="Resource" uid="uid://04pmc034qupd" path="res://idles/generators/library.tres" id="3_4ly0e"] -[ext_resource type="Resource" uid="uid://cythfovqgqlyh" path="res://idles/currencies/wood.tres" id="4_2xpf5"] -[ext_resource type="PackedScene" uid="uid://btkxru2gdjsgc" path="res://currency_tile.tscn" id="4_6ri4a"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="5_dl3gy"] -[ext_resource type="Resource" uid="uid://df5k58yu1g6rf" path="res://idles/generators/forestry.tres" id="5_u3cug"] -[ext_resource type="PackedScene" uid="uid://dirvi76rkoowf" path="res://goals_debug_ui.tscn" id="7_7i63j"] -[ext_resource type="PackedScene" path="res://core/prestige/prestige_panel.tscn" id="9_q5vce"] - -[node name="GeneratorGym" type="Node2D" unique_id=1219373683] - -[node name="MagicGenerator" parent="." unique_id=967969064 instance=ExtResource("1_6pne4")] -position = Vector2(262, 301) - -[node name="KnowledgeGenerator" parent="." unique_id=2139088546 instance=ExtResource("1_6pne4")] -visible = false -position = Vector2(262, 626) -currency = ExtResource("2_8qilt") -data = ExtResource("3_4ly0e") -press_buys_generator = false - -[node name="WoodGenerator" parent="." unique_id=29858558 instance=ExtResource("1_6pne4")] -visible = false -position = Vector2(1046, 626) -currency = ExtResource("4_2xpf5") -data = ExtResource("5_u3cug") -press_buys_generator = false - -[node name="UI" type="Control" parent="." unique_id=452530906] -layout_mode = 3 -anchors_preset = 0 -offset_right = 40.0 -offset_bottom = 40.0 - -[node name="MagicCurrencyTile" parent="UI" unique_id=1440583137 instance=ExtResource("4_6ri4a")] -layout_mode = 0 -offset_right = 160.0 -offset_bottom = 31.0 -currency = ExtResource("5_dl3gy") - -[node name="SpiritCurrencyTile" parent="UI" unique_id=797237056 instance=ExtResource("4_6ri4a")] -layout_mode = 0 -offset_top = 32.0 -offset_right = 160.0 -offset_bottom = 63.0 -currency = ExtResource("2_jlqd0") - -[node name="KnowledgeCurrencyTile" parent="UI" unique_id=1977342362 instance=ExtResource("4_6ri4a")] -layout_mode = 0 -offset_top = 63.0 -offset_right = 160.0 -offset_bottom = 94.0 -currency = ExtResource("2_8qilt") - -[node name="WoodCurrencyTile" parent="UI" unique_id=1210103101 instance=ExtResource("4_6ri4a")] -layout_mode = 0 -offset_top = 94.0 -offset_right = 160.0 -offset_bottom = 125.0 -currency = ExtResource("4_2xpf5") - -[node name="GoalsDebugUI" parent="UI" unique_id=4710697 instance=ExtResource("7_7i63j")] -layout_mode = 1 -offset_left = 1253.0 -offset_top = 817.0 -offset_right = 1913.0 -offset_bottom = 1076.0 - -[node name="PrestigePanel" parent="UI" unique_id=401213142 instance=ExtResource("9_q5vce")] -layout_mode = 0 -offset_left = 12.0 -offset_top = 822.0 -offset_right = 432.0 -offset_bottom = 1028.0 diff --git a/idles/buffs/bigger_forest.tres b/idles/buffs/bigger_forest.tres deleted file mode 100644 index 5b4050e..0000000 --- a/idles/buffs/bigger_forest.tres +++ /dev/null @@ -1,18 +0,0 @@ -[gd_resource type="Resource" script_class="GeneratorBuffData" format=3 uid="uid://mvgfe3nc7uwa"] - -[ext_resource type="Resource" uid="uid://bnhqk8b31mm4e" path="res://idles/currencies/knowledge.tres" id="1_1db6v"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_pg1j1"] -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="3_t80he"] -[ext_resource type="Resource" uid="uid://bmlhoeasl7xor" path="res://idles/goals/magic_total_13k.tres" id="4_83vra"] - -[resource] -script = ExtResource("3_t80he") -id = &"bigger_forest" -text = "Bigger Forest" -max_level = 10 -unlock_goal = ExtResource("4_83vra") -effect_increment = 1.0 -cost_currency = ExtResource("1_1db6v") -base_cost_mantissa = 250.0 -cost_multiplier = 1.7 -resource_target_currency = ExtResource("2_pg1j1") diff --git a/idles/buffs/library_auto_flux.tres b/idles/buffs/library_auto_flux.tres deleted file mode 100644 index 7608580..0000000 --- a/idles/buffs/library_auto_flux.tres +++ /dev/null @@ -1,18 +0,0 @@ -[gd_resource type="Resource" script_class="GeneratorBuffData" format=3 uid="uid://tu63jy51yigb"] - -[ext_resource type="Resource" uid="uid://bnhqk8b31mm4e" path="res://idles/currencies/knowledge.tres" id="1_78qkq"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_b57xf"] -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="3_nc8nr"] -[ext_resource type="Resource" uid="uid://bmlhoeasl7xor" path="res://idles/goals/magic_total_13k.tres" id="4_78qkq"] - -[resource] -script = ExtResource("3_nc8nr") -id = &"library_auto_flux" -text = "Library Dynamo" -max_level = 10 -unlock_goal = ExtResource("4_78qkq") -effect_increment = 1.0 -cost_currency = ExtResource("1_78qkq") -base_cost_mantissa = 100.0 -cost_multiplier = 1.7 -resource_target_currency = ExtResource("2_b57xf") diff --git a/idles/buffs/orb_auto_flux.tres b/idles/buffs/orb_auto_flux.tres deleted file mode 100644 index 858388e..0000000 --- a/idles/buffs/orb_auto_flux.tres +++ /dev/null @@ -1,18 +0,0 @@ -[gd_resource type="Resource" script_class="GeneratorBuffData" format=3 uid="uid://ceugcxmassmpk"] - -[ext_resource type="Resource" uid="uid://bnhqk8b31mm4e" path="res://idles/currencies/knowledge.tres" id="1_lnp8f"] -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_r7ak1"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_h3we5"] -[ext_resource type="Resource" uid="uid://qyxct5gbrxwa" path="res://idles/goals/magic_total_30.tres" id="4_000a0"] - -[resource] -script = ExtResource("1_r7ak1") -id = &"magic_auto_flux" -text = "Arcane Dynamo" -max_level = 10 -unlock_goal = ExtResource("4_000a0") -effect_increment = 1.0 -cost_currency = ExtResource("1_lnp8f") -base_cost_mantissa = 25.0 -cost_multiplier = 1.7 -resource_target_currency = ExtResource("2_h3we5") diff --git a/idles/buffs/orb_click_focus.tres b/idles/buffs/orb_click_focus.tres deleted file mode 100644 index ddb1209..0000000 --- a/idles/buffs/orb_click_focus.tres +++ /dev/null @@ -1,19 +0,0 @@ -[gd_resource type="Resource" script_class="GeneratorBuffData" format=3 uid="uid://6i3fcygusuqf"] - -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_1wyaq"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_0j56j"] -[ext_resource type="Resource" uid="uid://qyxct5gbrxwa" path="res://idles/goals/magic_total_30.tres" id="3_bsqao"] - -[resource] -script = ExtResource("1_1wyaq") -id = &"magic_click_focus" -kind = 1 -text = "Apprentice Gloves" -max_level = 4 -unlock_goal = ExtResource("3_bsqao") -effect_increment = 1.0 -cost_currency = ExtResource("2_0j56j") -base_cost_mantissa = 2.5 -base_cost_exponent = 1 -cost_multiplier = 2.0 -resource_target_currency = ExtResource("2_0j56j") diff --git a/idles/buffs/orb_summon_spirit.tres b/idles/buffs/orb_summon_spirit.tres deleted file mode 100644 index e160870..0000000 --- a/idles/buffs/orb_summon_spirit.tres +++ /dev/null @@ -1,20 +0,0 @@ -[gd_resource type="Resource" script_class="GeneratorBuffData" format=3 uid="uid://coi7k1cx4p4hr"] - -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="1_aawxd"] -[ext_resource type="Resource" uid="uid://l0pn6mlcer7t" path="res://idles/currencies/spirit.tres" id="2_0eqxt"] -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="3_0ov1n"] -[ext_resource type="Resource" uid="uid://qyxct5gbrxwa" path="res://idles/goals/magic_total_30.tres" id="4_ifsqd"] - -[resource] -script = ExtResource("3_0ov1n") -id = &"summon_spirit" -kind = 2 -text = "Summon Spirit" -unlock_goal = ExtResource("4_ifsqd") -effect_increment = 1.0 -cost_currency = ExtResource("1_aawxd") -base_cost_mantissa = 200.0 -cost_multiplier = 1.15 -resource_target_currency = ExtResource("2_0eqxt") -resource_purchase_base_mantissa = 1.0 -resource_purchase_increment_multiplier = 1.0 diff --git a/idles/currencies/knowledge.tres b/idles/currencies/knowledge.tres deleted file mode 100644 index 0164e38..0000000 --- a/idles/currencies/knowledge.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://bnhqk8b31mm4e"] - -[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="1_72iuq"] -[ext_resource type="Texture2D" uid="uid://bgtt3wu43tajh" path="res://icon.svg" id="2_x2h5x"] - -[resource] -script = ExtResource("1_72iuq") -id = &"knowledge" -display_name = "Knowledge" -icon = ExtResource("2_x2h5x") diff --git a/idles/currencies/magic.tres b/idles/currencies/magic.tres deleted file mode 100644 index 5b7d307..0000000 --- a/idles/currencies/magic.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://brqaojindcxa5"] - -[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="1_x4uiu"] -[ext_resource type="Texture2D" uid="uid://bgtt3wu43tajh" path="res://icon.svg" id="2_52ar0"] - -[resource] -script = ExtResource("1_x4uiu") -id = &"magic" -display_name = "Magic" -icon = ExtResource("2_52ar0") diff --git a/idles/currencies/spirit.tres b/idles/currencies/spirit.tres deleted file mode 100644 index 6497a2b..0000000 --- a/idles/currencies/spirit.tres +++ /dev/null @@ -1,9 +0,0 @@ -[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://l0pn6mlcer7t"] - -[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="1_m14p5"] - -[resource] -script = ExtResource("1_m14p5") -id = &"spirit" -display_name = "Spirit" -metadata/_custom_type_script = "uid://dtgqjf3bl7pm8" diff --git a/idles/currencies/wood.tres b/idles/currencies/wood.tres deleted file mode 100644 index 41b6ffa..0000000 --- a/idles/currencies/wood.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://cythfovqgqlyh"] - -[ext_resource type="Texture2D" uid="uid://bgtt3wu43tajh" path="res://icon.svg" id="1_t8m5x"] -[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="2_137dc"] - -[resource] -script = ExtResource("2_137dc") -id = &"wood" -display_name = "Wood" -icon = ExtResource("1_t8m5x") diff --git a/idles/generators/forestry.tres b/idles/generators/forestry.tres deleted file mode 100644 index 13f3e9d..0000000 --- a/idles/generators/forestry.tres +++ /dev/null @@ -1,23 +0,0 @@ -[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://df5k58yu1g6rf"] - -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_ffn26"] -[ext_resource type="Resource" uid="uid://mvgfe3nc7uwa" path="res://idles/buffs/bigger_forest.tres" id="2_rptf4"] -[ext_resource type="Resource" uid="uid://l0pn6mlcer7t" path="res://idles/currencies/spirit.tres" id="3_rptf4"] -[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="5_43n1y"] -[ext_resource type="Resource" uid="uid://bmlhoeasl7xor" path="res://idles/goals/magic_total_13k.tres" id="6_ffn26"] - -[resource] -script = ExtResource("5_43n1y") -id = &"Wood" -name = "Forestry" -starts_unlocked = false -starts_available = false -initial_owned = 1 -purchase_currency = ExtResource("3_rptf4") -unlock_goal = ExtResource("6_ffn26") -unlock_goal_behavior = 1 -initial_cost = 1.0 -coefficient = 1.0 -initial_productivity = 20.0 -buffs = Array[ExtResource("1_ffn26")]([ExtResource("2_rptf4")]) -metadata/_custom_type_script = "uid://b00tqsuhxdy0d" diff --git a/idles/generators/library.tres b/idles/generators/library.tres deleted file mode 100644 index 0e5100a..0000000 --- a/idles/generators/library.tres +++ /dev/null @@ -1,25 +0,0 @@ -[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://04pmc034qupd"] - -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_jemvk"] -[ext_resource type="Resource" uid="uid://tu63jy51yigb" path="res://idles/buffs/library_auto_flux.tres" id="2_fcbji"] -[ext_resource type="Resource" uid="uid://l0pn6mlcer7t" path="res://idles/currencies/spirit.tres" id="3_fcbji"] -[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="3_xj12v"] -[ext_resource type="Resource" uid="uid://c4mkxj4ubhsi0" path="res://idles/goals/magic_total_1300.tres" id="4_1h03m"] - -[resource] -script = ExtResource("3_xj12v") -id = &"Knowledge" -name = "Library" -starts_unlocked = false -starts_available = false -initial_owned = 1 -purchase_currency = ExtResource("3_fcbji") -unlock_goal = ExtResource("4_1h03m") -unlock_goal_behavior = 1 -initial_cost = 1.0 -coefficient = 1.0 -initial_time = 3.0 -initial_revenue = 60.0 -initial_productivity = 20.0 -buffs = Array[ExtResource("1_jemvk")]([ExtResource("2_fcbji")]) -metadata/_custom_type_script = "uid://b00tqsuhxdy0d" diff --git a/idles/generators/monastery.tres b/idles/generators/monastery.tres deleted file mode 100644 index bc56e5c..0000000 --- a/idles/generators/monastery.tres +++ /dev/null @@ -1,12 +0,0 @@ -[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://nfq4erycp7vy"] - -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_s017t"] -[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="2_2rq43"] - -[resource] -script = ExtResource("2_2rq43") -id = &"monastery" -name = "Monastery" -starts_unlocked = false -starts_available = false -metadata/_custom_type_script = "uid://b00tqsuhxdy0d" diff --git a/idles/generators/orb.tres b/idles/generators/orb.tres deleted file mode 100644 index 0420434..0000000 --- a/idles/generators/orb.tres +++ /dev/null @@ -1,19 +0,0 @@ -[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://co0mcc2kvcpo5"] - -[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="1_c6y77"] -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_t6lg0"] -[ext_resource type="Resource" uid="uid://ceugcxmassmpk" path="res://idles/buffs/orb_auto_flux.tres" id="2_x505b"] -[ext_resource type="Resource" uid="uid://6i3fcygusuqf" path="res://idles/buffs/orb_click_focus.tres" id="3_fsxdm"] -[ext_resource type="Resource" uid="uid://coi7k1cx4p4hr" path="res://idles/buffs/orb_summon_spirit.tres" id="4_5v0af"] -[ext_resource type="Resource" uid="uid://l0pn6mlcer7t" path="res://idles/currencies/spirit.tres" id="4_jpwus"] - -[resource] -script = ExtResource("1_c6y77") -id = &"Magic" -name = "Magic Orb" -purchase_currency = ExtResource("4_jpwus") -initial_cost = 1.0 -coefficient = 1.0 -initial_productivity = 20.0 -buffs = Array[ExtResource("1_t6lg0")]([ExtResource("2_x505b"), ExtResource("3_fsxdm"), ExtResource("4_5v0af")]) -metadata/_custom_type_script = "uid://b00tqsuhxdy0d" diff --git a/idles/generators/spirit_factory.tres b/idles/generators/spirit_factory.tres deleted file mode 100644 index 61ab4b3..0000000 --- a/idles/generators/spirit_factory.tres +++ /dev/null @@ -1,18 +0,0 @@ -[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://ri1ggb756753"] - -[ext_resource type="Script" uid="uid://dnhocfsuvmeyb" path="res://core/generator/generator_buff_data.gd" id="1_tgm58"] -[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="2_1qpvc"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_chq14"] -[ext_resource type="Resource" uid="uid://qyxct5gbrxwa" path="res://idles/goals/magic_total_30.tres" id="4_tj1lt"] - -[resource] -script = ExtResource("2_1qpvc") -id = &"spirit_factory" -name = "Spirit Factory" -starts_unlocked = false -starts_available = false -purchase_currency = ExtResource("2_chq14") -unlock_goal = ExtResource("4_tj1lt") -unlock_goal_behavior = 1 -initial_cost = 200.0 -metadata/_custom_type_script = "uid://b00tqsuhxdy0d" diff --git a/idles/goals/magic_350k_wood_20k.tres b/idles/goals/magic_350k_wood_20k.tres deleted file mode 100644 index 227e33a..0000000 --- a/idles/goals/magic_350k_wood_20k.tres +++ /dev/null @@ -1,24 +0,0 @@ -[gd_resource type="Resource" script_class="GoalData" format=3 uid="uid://oh1a4tneuons"] - -[ext_resource type="Script" uid="uid://r4js5eajolio" path="res://core/goals/goal_requirement_data.gd" id="1_pj6se"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_lsxf0"] -[ext_resource type="Script" uid="uid://dx4kmh33rrkpy" path="res://core/goals/goal_data.gd" id="3_hyry2"] -[ext_resource type="Resource" uid="uid://cythfovqgqlyh" path="res://idles/currencies/wood.tres" id="3_lsxf0"] - -[sub_resource type="Resource" id="Resource_tvl3d"] -script = ExtResource("1_pj6se") -currency = ExtResource("2_lsxf0") -amount_mantissa = 3.5 -amount_exponent = 5 - -[sub_resource type="Resource" id="Resource_hyry2"] -script = ExtResource("1_pj6se") -currency = ExtResource("3_lsxf0") -amount_mantissa = 2.0 -amount_exponent = 4 -metadata/_custom_type_script = "uid://r4js5eajolio" - -[resource] -script = ExtResource("3_hyry2") -id = &"magic_350k_wood_20k" -requirements = Array[ExtResource("1_pj6se")]([SubResource("Resource_tvl3d"), SubResource("Resource_hyry2")]) diff --git a/idles/goals/magic_total_1300.tres b/idles/goals/magic_total_1300.tres deleted file mode 100644 index 49e8568..0000000 --- a/idles/goals/magic_total_1300.tres +++ /dev/null @@ -1,16 +0,0 @@ -[gd_resource type="Resource" script_class="GoalData" format=3 uid="uid://c4mkxj4ubhsi0"] - -[ext_resource type="Script" uid="uid://dx4kmh33rrkpy" path="res://core/goals/goal_data.gd" id="1_b11ou"] -[ext_resource type="Script" uid="uid://r4js5eajolio" path="res://core/goals/goal_requirement_data.gd" id="2_d507t"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="3_tu3fx"] - -[sub_resource type="Resource" id="Resource_tvl3d"] -script = ExtResource("2_d507t") -currency = ExtResource("3_tu3fx") -amount_mantissa = 1.3 -amount_exponent = 3 - -[resource] -script = ExtResource("1_b11ou") -id = &"magic_total_1300" -requirements = Array[ExtResource("2_d507t")]([SubResource("Resource_tvl3d")]) diff --git a/idles/goals/magic_total_13k.tres b/idles/goals/magic_total_13k.tres deleted file mode 100644 index c2eb65e..0000000 --- a/idles/goals/magic_total_13k.tres +++ /dev/null @@ -1,16 +0,0 @@ -[gd_resource type="Resource" script_class="GoalData" format=3 uid="uid://bmlhoeasl7xor"] - -[ext_resource type="Script" uid="uid://r4js5eajolio" path="res://core/goals/goal_requirement_data.gd" id="1_185pw"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="2_ox6xg"] -[ext_resource type="Script" uid="uid://dx4kmh33rrkpy" path="res://core/goals/goal_data.gd" id="3_ef7ki"] - -[sub_resource type="Resource" id="Resource_tvl3d"] -script = ExtResource("1_185pw") -currency = ExtResource("2_ox6xg") -amount_mantissa = 1.3 -amount_exponent = 4 - -[resource] -script = ExtResource("3_ef7ki") -id = &"magic_total_13k" -requirements = Array[ExtResource("1_185pw")]([SubResource("Resource_tvl3d")]) diff --git a/idles/goals/magic_total_30.tres b/idles/goals/magic_total_30.tres deleted file mode 100644 index bf525b4..0000000 --- a/idles/goals/magic_total_30.tres +++ /dev/null @@ -1,15 +0,0 @@ -[gd_resource type="Resource" script_class="GoalData" format=3 uid="uid://qyxct5gbrxwa"] - -[ext_resource type="Script" uid="uid://dx4kmh33rrkpy" path="res://core/goals/goal_data.gd" id="1_rh4uj"] -[ext_resource type="Script" uid="uid://r4js5eajolio" path="res://core/goals/goal_requirement_data.gd" id="2_58n5q"] -[ext_resource type="Resource" uid="uid://brqaojindcxa5" path="res://idles/currencies/magic.tres" id="3_qm5e7"] - -[sub_resource type="Resource" id="Resource_v4v16"] -script = ExtResource("2_58n5q") -currency = ExtResource("3_qm5e7") -amount_mantissa = 30.0 - -[resource] -script = ExtResource("1_rh4uj") -id = &"magic_total_30" -requirements = Array[ExtResource("2_58n5q")]([SubResource("Resource_v4v16")]) diff --git a/idles/prestige/primary_prestige.tres b/idles/prestige/primary_prestige.tres deleted file mode 100644 index 19a8794..0000000 --- a/idles/prestige/primary_prestige.tres +++ /dev/null @@ -1,25 +0,0 @@ -[gd_resource type="Resource" script_class="PrestigeConfig" format=3] - -[ext_resource type="Script" path="res://core/prestige/prestige_config.gd" id="1_3tg3a"] - -[resource] -script = ExtResource("1_3tg3a") -id = &"ascension" -display_name = "Ascension" -prestige_currency_id = &"ascension" -source_currency_id = &"magic" -basis = 0 -formula = 0 -threshold_mantissa = 1.0 -threshold_exponent = 4 -scale = 1.0 -exponent = 0.5 -flat_bonus = 0.0 -minimum_gain = 0 -rounding_mode = 0 -allow_prestige_without_gain = false -multiplier_mode = 0 -base_multiplier = 1.0 -multiplier_per_prestige = 0.05 -multiplier_exponent = 1.0 -metadata/_custom_type_script = "res://core/prestige/prestige_config.gd"