diff --git a/README.md b/README.md index bb52871..de83f65 100644 --- a/README.md +++ b/README.md @@ -22,20 +22,22 @@ A modular idle/incremental game prototype featuring a decoupled buff system, mul | 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) | +| **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) | | **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 | +| **Research** | `core/research/` | XP-based progression with production multipliers | -### Autoload Singletons +### Key Nodes -| Autoload | Script | Description | -|----------|--------|-------------| -| `GameState` | `core/game_state.gd` | Central state management, save/load | -| `CurrencyDatabase` | `core/currency_database.gd` | Currency catalog discovery | +| Node | Script | Description | +|------|--------|-------------| +| `LevelGameState` | `core/level_game_state.gd` | Central state management, save/load | +| `CurrencyCatalogue` | `core/currency_catalogue.gd` | Currency catalog resource | | `PrestigeManager` | `core/prestige/prestige_manager.gd` | Prestige system | +| `ResearchXPTracker` | `core/research/research_xp_tracker.gd` | Research XP accumulation | ### Data Directory Structure @@ -90,21 +92,29 @@ GameState.get_effective_multiplier(generator_id, kind) -> float ## Save Format -**Version 2 (current):** +**Version 5 (current):** ```json { - "save_format_version": 2, - "currencies": { ... }, + "save_format_version": 5, + "currencies": { + "": { + "current": {"m": float, "e": int}, + "total": {"m": float, "e": int}, + "all_time": {"m": float, "e": int} + } + }, "generator_states": { ... }, - "buff_definitions": { ... }, "buff_levels": { "farm_flux": 5 }, "buff_unlocked": { "farm_flux": true }, "buff_active": { "farm_flux": true }, + "goals": { "completed": ["goal_id"] }, + "research_xp": { "": {"m": float, "e": int} }, + "research_levels": { "": int }, "last_save_time": 1234567890 } ``` -**Note**: Breaking change from v1 - old saves are incompatible. +**Note**: Save format version 5 includes research XP as BigNumber serialization. ## Development @@ -113,7 +123,7 @@ GameState.get_effective_multiplier(generator_id, kind) -> float **New Currency:** 1. Create `res://sandbox/currencies/.tres` (Currency resource) 2. Set `id`, `display_name`, `icon` -3. Auto-discovered at runtime +3. Add to `CurrencyCatalogue` resource **New Generator:** 1. Create `res://sandbox/generators/.tres` (CurrencyGeneratorData) @@ -125,7 +135,13 @@ GameState.get_effective_multiplier(generator_id, kind) -> float 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 +4. Add to `BuffCatalogue` resource + +**New Research:** +1. Create `res://sandbox/research/.tres` (ResearchData) +2. Link to generator via `generator_id` +3. Configure XP and multiplier parameters +4. Add to `ResearchCatalogue` resource ### Testing @@ -140,24 +156,17 @@ GameState.get_effective_multiplier(generator_id, kind) -> float ## 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 +## Current 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 +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 diff --git a/core/README.md b/core/README.md index 144c40a..8645767 100644 --- a/core/README.md +++ b/core/README.md @@ -5,42 +5,45 @@ The `core/` directory contains the fundamental systems for the idle game. It provides: - **Numeric Foundation**: `BigNumber` for handling huge idle game values -- **Game State Management**: `GameState` autoload for all persistent state -- **Currency System**: Database and tracking for multiple currency types +- **Game State Management**: `LevelGameState` for all persistent state +- **Currency System**: `CurrencyCatalogue` and tracking for multiple currency types - **Generator System**: Automated resource production with scaling costs - **Buff System**: Upgrades that modify generator behavior - **Goal System**: Achievement tracking and unlock triggers - **Prestige System**: Rebirth mechanics with permanent multipliers +- **Research System**: XP-based progression with production multipliers ## Architecture ``` core/ ├── big_number.gd # Core numeric API -├── game_state.gd # Main state management autoload -├── buff_database.gd # Buff registration system -├── currency_database.gd # Currency registration system -├── currency/ # Currency data structures +├── level_game_state.gd # Main state management (Node) +├── currency/ # Currency data structures + CurrencyCatalogue +├── currency_catalogue.gd # Currency catalogue resource +├── buff_catalogue.gd # Buff catalogue resource +├── goal_catalogue.gd # Goal catalogue resource ├── generator/ # Generator logic and data ├── goals/ # Goal/achievement system -└── prestige/ # Prestige/rebirth system +├── prestige/ # Prestige/rebirth system +└── research/ # Research XP and progression ``` ## Data Flow -1. **Game Start**: `GameState._ready()` initializes currencies, loads save -2. **Player Action**: Generator bought → `GameState` updated → signals emitted +1. **Game Start**: `LevelGameState._ready()` initializes currencies, loads save +2. **Player Action**: Generator bought → `LevelGameState` updated → signals emitted 3. **UI Reaction**: Listeners respond to signals → update display 4. **Goal Check**: Currency changed → goals evaluated → buffs unlocked -5. **Save**: `GameState.save_game()` → JSON to `user://idle_save.json` +5. **Save**: `LevelGameState.save_game()` → JSON to `user://level_save.json` ## Save Format -**Version**: 3 +**Version**: 5 ```json { - "save_format_version": 3, + "save_format_version": 5, "currencies": { "": { "current": {"m": float, "e": int}, @@ -68,6 +71,12 @@ core/ "goals": { "completed": ["", ...] }, + "research_xp": { + "": {"m": float, "e": int} + }, + "research_levels": { + "": int + }, "last_save_time": unix_timestamp } ``` @@ -97,7 +106,7 @@ var restored = BigNumber.deserialize(dict) ### Adding a New Currency 1. Create `res://sandbox/currencies/.tres` extending `Currency` 2. Set `id`, `display_name`, and `icon` -3. Auto-discovered by `CurrencyDatabase` +3. Add to `CurrencyCatalogue` resource assigned to `LevelGameState` ### Adding a New Generator 1. Create `res://sandbox/generators/.tres` extending `CurrencyGeneratorData` @@ -107,7 +116,12 @@ var restored = BigNumber.deserialize(dict) ### Adding a New Buff 1. Create `res://sandbox/buffs/.tres` extending `GeneratorBuffData` 2. Set `target_ids`, `kind`, `effect_increment`, and `cost` -3. Auto-discovered by `BuffDatabase` +3. Add to `BuffCatalogue` resource assigned to `LevelGameState` + +### Adding New Research +1. Create `res://sandbox/research/.tres` extending `ResearchData` +2. Link to a generator via `generator_id` +3. Add to `ResearchCatalogue` resource assigned to `LevelGameState` ## See Also diff --git a/core/currency/README.md b/core/currency/README.md index a215267..6737f8d 100644 --- a/core/currency/README.md +++ b/core/currency/README.md @@ -41,21 +41,17 @@ icon = ExtResource("uid://...") ### Accessing Currencies +Currencies are defined in a `CurrencyCatalogue` resource that holds an array of `Currency` resources. + ```gdscript -# Get all known currencies -var currencies: Array[Currency] = CurrencyDatabase.get_known_currencies() +# Get all known currency IDs from the catalogue +var ids: Array[StringName] = currency_catalogue.get_all_ids() -# Get currency by ID -var gold: Currency = CurrencyDatabase.get_currency_resource(&"gold") - -# Check if currency exists -var is_valid: bool = CurrencyDatabase.is_known_currency_id(&"gems") - -# Get display name -var name: String = CurrencyDatabase.get_currency_name(&"gold") +# Get currency resource by ID +var gold: Currency = currency_catalogue.get_currency_by_id(&"gold") ``` -## Integration with GameState +## Integration with LevelGameState Currencies are tracked in three ways: 1. **current**: Current balance (resets on prestige) @@ -64,21 +60,52 @@ Currencies are tracked in three ways: ```gdscript # Add currency -GameState.add_currency(gold_resource, BigNumber.new(100.0, 0)) +level_game_state.add_currency(gold_resource, BigNumber.new(100.0, 0)) + +# Add by ID +level_game_state.add_currency_by_id(&"gold", BigNumber.new(100.0, 0)) # Get balance -var balance: BigNumber = GameState.get_currency_amount_by_id(&"gold") +var balance: BigNumber = level_game_state.get_currency_amount_by_id(&"gold") # Spend currency (returns false if insufficient) -var success: bool = GameState.spend_currency_by_id(&"gold", BigNumber.new(50.0, 0)) +var success: bool = level_game_state.spend_currency_by_id(&"gold", BigNumber.new(50.0, 0)) + +# Check if currency exists +var is_valid: bool = level_game_state.is_known_currency_id(&"gems") + +# Get currency resource +var gold: Currency = level_game_state.get_currency_resource(&"gold") + +# Get display name +var name: String = level_game_state.get_currency_name(&"gold") ``` -## Auto-Discovery +## CurrencyCatalogue Class -`CurrencyDatabase` automatically scans `res://sandbox/currencies/` for `.tres` and `.res` files on startup. +```gdscript +class_name CurrencyCatalogue +extends Resource + +@export var currencies: Array[Currency] = [] + +func get_currency_by_id(id: StringName) -> Currency +func get_all_ids() -> Array[StringName] +``` + +The `CurrencyCatalogue` is a resource that holds all defined currencies and is assigned to `LevelGameState` via the `currency_catalogue` export variable. + +## Signals + +`LevelGameState` emits `currency_changed(currency_id: StringName, new_amount: BigNumber)` whenever a currency balance changes. ## See Also -- `core/game_state.gd` - Currency state management +- `core/level_game_state.gd` - Currency state management - `core/big_number.gd` - Large number handling -- `generator/currency_generator_data.gd` - Generator purchase currency +- `core/currency/currency_catalogue.gd` - Currency catalogue resource +- `core/generator/currency_generator_data.gd` - Generator purchase currency + + + +/home/mikymod/work/jmp/idle/core/currency/README.md \ No newline at end of file diff --git a/core/generator/README.md b/core/generator/README.md index 5e544c8..10b3409 100644 --- a/core/generator/README.md +++ b/core/generator/README.md @@ -190,14 +190,14 @@ UI component showing generator information. ## Goal-Based Unlock -Generators with `unlock_goal` automatically listen to `GameState.goal_completed` signal: +Generators with `unlock_goal` automatically listen to `LevelGameState.goal_completed` signal: - When goal completes, generator unlocks automatically - Goal's `unlock_behavior` (AUTOMATIC/MANUAL) controls when goal completes - Manual goals require player to click "Unlock" button first ```gdscript # In CurrencyGenerator._ready(): -GameState.goal_completed.connect(_on_goal_completed) +level_game_state.goal_completed.connect(_on_goal_completed) func _on_goal_completed(goal_id: StringName) -> void: if data.has_unlock_goal() and data.get_unlock_goal_id() == goal_id: @@ -211,14 +211,15 @@ Generators automatically apply prestige multipliers: effective_multiplier = run_multiplier * buff_multiplier * prestige_multiplier ``` -On prestige: -1. `reset_runtime_state_for_prestige()` called +On prestige via `LevelGameState.reset_for_prestige()`: +1. Current currencies reset to 0 2. `cycle_progress_seconds` reset 3. Buff levels reset to 0 -4. Unlocks re-evaluated from goals +4. Goal completion state cleared and re-initialized +5. Research XP and levels reset to 0 ## See Also -- `core/game_state.gd` - Generator state storage -- `goals/goal_data.gd` - Unlock conditions -- `prestige/prestige_manager.gd` - Multiplier application +- `core/level_game_state.gd` - Generator state storage +- `core/goals/goal_data.gd` - Unlock conditions +- `core/prestige/prestige_manager.gd` - Multiplier application diff --git a/core/goals/README.md b/core/goals/README.md index 027d5b2..ae5a0fe 100644 --- a/core/goals/README.md +++ b/core/goals/README.md @@ -43,7 +43,7 @@ func is_valid() -> bool # Has valid id and requirements func get_requirements() -> Array[GoalRequirementData] # Access requirements ``` -**Note:** State-dependent methods (`is_met()`, `get_progress()`, `get_summary_text()`) have been moved to `LevelGameState` for proper decoupling. +**Note:** State-dependent methods (`is_goal_met()`, `get_goal_progress()`, `get_goal_requirement_summary()`) are implemented in `LevelGameState` for proper decoupling. ## GoalRequirementData @@ -68,7 +68,7 @@ func get_amount() -> BigNumber # Required amount func has_valid_amount() -> bool # Amount is non-negative ``` -**Note:** State-dependent methods (`is_met()`, `get_progress()`, `get_summary_text()`) have been moved to `LevelGameState` for proper decoupling. +**Note:** State-dependent methods (`is_met()`, `get_progress()`, `get_summary_text()`) are implemented in `LevelGameState` for proper decoupling. ### Progress Calculation @@ -93,7 +93,7 @@ This means reaching 50% progress on a 1e100 goal requires ~1e50 currency. ```gdscript func _on_currency_changed(currency_id, new_amount): - game_state.evaluate_all_goals() + evaluate_all_goals() ``` ### Completion Flow @@ -167,8 +167,8 @@ signal goal_progress_changed(goal_id: StringName, progress: float) ## Integration Points -### With GameState -- Goals auto-discovered from `res://sandbox/goals/` +### With LevelGameState +- Goals registered from `GoalCatalogue` assigned to `LevelGameState` - Completion state saved to JSON - Buff unlock goals checked automatically @@ -178,15 +178,15 @@ signal goal_progress_changed(goal_id: StringName, progress: float) @export var unlock_goal: GoalData # When goal completes, buff auto-unlocks: -GameState._try_unlock_buff_from_goal(buff) +level_game_state._try_unlock_buff_from_goal(buff) ``` ### With Prestige - Goal completion state persists through prestige -- Reset via `GameState.reset_for_prestige()` +- Reset via `LevelGameState.reset_for_prestige()` ## See Also -- `core/game_state.gd` - Goal state management -- `generator/currency_generator_data.gd` - Generator unlock goals -- `generator/generator_buff_data.gd` - Buff unlock goals +- `core/level_game_state.gd` - Goal state management +- `core/generator/currency_generator_data.gd` - Generator unlock goals +- `core/generator/generator_buff_data.gd` - Buff unlock goals diff --git a/core/prestige/README.md b/core/prestige/README.md index 8380f17..b0e9ddd 100644 --- a/core/prestige/README.md +++ b/core/prestige/README.md @@ -292,6 +292,6 @@ multiplier_per_prestige = 0.05 ## See Also -- `core/game_state.gd` - State persistence -- `generator/currency_generator.gd` - Multiplier application +- `core/level_game_state.gd` - State persistence +- `core/generator/currency_generator.gd` - Multiplier application - `core/big_number.gd` - Large number math