From 18a4c04ee1531c609d615ba403345441a35c226d Mon Sep 17 00:00:00 2001 From: Michele Rossi Date: Sun, 3 May 2026 19:00:16 +0200 Subject: [PATCH] Cleanup --- BUFF_MIGRATION.md | 122 ------- PLANNING.md | 325 ------------------ core/{ => goals}/goal_catalogue.gd | 0 core/{ => goals}/goal_catalogue.gd.uid | 0 core/prestige/prestige_panel.gd | 6 +- .../tiny_sword/buildings/castle/castle.gd | 4 +- .../tiny_sword/buildings/castle/castle.tscn | 1 + .../tiny_sword/goals/ts_goal_catalogue.tres | 2 +- docs/gyms/tiny_sword/tiny_sword.tscn | 1 + 9 files changed, 11 insertions(+), 450 deletions(-) delete mode 100644 BUFF_MIGRATION.md delete mode 100644 PLANNING.md rename core/{ => goals}/goal_catalogue.gd (100%) rename core/{ => goals}/goal_catalogue.gd.uid (100%) diff --git a/BUFF_MIGRATION.md b/BUFF_MIGRATION.md deleted file mode 100644 index 04a006d..0000000 --- a/BUFF_MIGRATION.md +++ /dev/null @@ -1,122 +0,0 @@ -# Buff System Migration Guide - -## Overview -This guide walks you through migrating from per-generator buffs to the new global buff system. - -## Prerequisites -- Backup your existing save file: `user://idle_save.json` -- Note: This is a **breaking change** - old saves (v1) will be rejected - -## Migration Steps - -### Step 1: Update Buff Resources - -Open each buff in `res://sandbox/buffs/` and set the `target_ids` field: - -**For buffs that should apply to all generators:** -- Set `target_ids = ["*"]` - -**For buffs that target specific generators:** -- Set `target_ids = ["generator_id_1", "generator_id_2"]` -- Use the same IDs as defined in your generator data files - -**Example:** -```gdscript -# farm_flux.tres -target_ids = ["farm", "forestry"] # Multi-target buff - -# global_boost.tres -target_ids = ["*"] # Wildcard - all current and future generators -``` - -### Step 2: Update Generator Resources - -Open each generator in `res://sandbox/generators/` and: - -1. **Remove** the `buffs` array field (or clear it) -2. **(Optional)** Add `expected_buff_ids` for documentation purposes - -This is safe because generators now query `GameState.get_buffs_for_generator()` at runtime. - -### Step 3: Delete Old Save Files - -Delete `user://idle_save.json` to start fresh with the new v2 format. - -**Note:** There is no automatic migration from v1 to v2. Players will need to start new games. - -### Step 4: Verify Auto-Discovery - -The `BuffDatabase` autoload will automatically load all `.tres` files from `res://sandbox/buffs/` at runtime. - -Verify in the output log: -``` -BuffDatabase initialized with N buffs -``` - -### Step 5: Test Key Scenarios - -Run through these test cases: - -1. **Single-target buff**: Buy a buff that targets only one generator - - Verify only that generator's production increases - -2. **Multi-target buff**: Buy a buff targeting multiple generators - - Verify all targeted generators' production increases - -3. **Wildcard buff**: Buy a buff with `target_ids = ["*"]` - - Verify ALL generators (current and future) get the bonus - -4. **Goal unlock**: Meet a buff unlock goal - - Verify the buff automatically unlocks and activates - -5. **Save/Load**: Save the game, close, and reopen - - Verify buff levels and unlock states persist - -6. **Prestige**: Perform a prestige - - Verify all buff levels reset to 0 - - Verify buff unlock states reset to false - -## Rollback (If Needed) - -If issues arise: - -1. Revert all code changes using git -2. Restore old save file from backup -3. Restore buff/generator `.tres` files to original state -4. Remove `BuffDatabase` from `project.godot` autoloads - -## Checking Your Work - -After migration, verify: - -- [ ] All buffs load automatically at startup -- [ ] Buff UI displays correctly for each generator -- [ ] Buying a buff level increases the GLOBAL level (not per-generator) -- [ ] Multi-target buffs affect all specified generators -- [ ] Wildcard buffs affect all generators -- [ ] Save files include buff state (version 2) -- [ ] Prestige resets all buff levels - -## Common Issues - -### Issue: Buff not appearing in UI -**Solution**: Check that the buff's `target_ids` includes the generator's ID or uses `["*"]` - -### Issue: Wildcard buffs not applying to new generators -**Solution**: Ensure new generators call `GameState.register_buff()` for each buff they should inherit - -### Issue: Old save won't load -**Solution**: This is expected - v1 saves are incompatible. Delete `user://idle_save.json` and start fresh. - -### Issue: Buff multipliers not stacking -**Solution**: Verify `get_effective_multiplier()` is being called and that buff levels > 0 - -## Success Criteria - -Migration is complete when: -- ✅ All generators produce correct amounts with active buffs -- ✅ Buff levels are shared globally across all targets -- ✅ Wildcard buffs automatically apply to new generators -- ✅ Save/load preserves buff state correctly -- ✅ Prestige resets all buff levels to 0 -- ✅ New buffs can be added by dropping `.tres` files in `res://sandbox/buffs/` diff --git a/PLANNING.md b/PLANNING.md deleted file mode 100644 index 1fd8491..0000000 --- a/PLANNING.md +++ /dev/null @@ -1,325 +0,0 @@ -# Per-Level GameState Architecture Refactoring Plan - -## Overview - -Convert the current autoload-based global GameState system to a per-level instance-based architecture where each level scene has its own `LevelGameState` node with references to catalogues (resources) and its own save file. - -## Current Architecture (To Be Replaced) - -``` -project.godot autoloads: -├─ BuffDatabase (autoload) -├─ CurrencyDatabase (autoload) -├─ GameState (autoload) -└─ PrestigeManager (autoload) - -tiny_sword.tscn: -└─ Uses GameState autoload directly from any node -``` - -**Problems:** -- Level scenes implicitly depend on global autoloads -- Cannot have multiple levels with independent state -- Catalogues auto-discover from filesystem (tightly coupled) -- Save file path is hardcoded globally - -## Target Architecture - -``` -tiny_sword.tscn (root node) -├─ LevelGameState (Node) -│ ├─ @export var currency_catalogue: CurrencyCatalogue (Resource) -│ ├─ @export var buff_catalogue: BuffCatalogue (Resource) -│ ├─ @export var goal_catalogue: GoalCatalogue (Resource) -│ ├─ @export var save_file_path: String = "user://tiny_sword_save.json" -│ └─ PrestigeManager (Node child) -│ └─ @export var game_state: LevelGameState -├─ World (Node2D) -│ ├─ GoldMine (CurrencyGenerator) -│ │ └─ @onready var game_state = find_parent("LevelGameState") -│ └─ ...other generators -└─ UI (Control) - ├─ CurrencyTile (each: @export var game_state: LevelGameState) - └─ ... -``` - -## Catalogue Resources - -All catalogues are `Resource` subclasses with explicit arrays populated in the editor: - -### CurrencyCatalogue -```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] -``` - -**Location:** `res://docs/gyms/tiny_sword/currencies/tiny_sword_catalogue.tres` - -### BuffCatalogue -```gdscript -class_name BuffCatalogue -extends Resource - -@export var buffs: Array[GeneratorBuffData] = [] - -func get_buff_by_id(id: StringName) -> GeneratorBuffData -func get_all_ids() -> Array[StringName] -func get_buffs_for_generator(gen_id: StringName) -> Array[GeneratorBuffData] -``` - -**Location:** `res://docs/gyms/tiny_sword/buffs/tiny_sword_buffs.tres` - -### GoalCatalogue -```gdscript -class_name GoalCatalogue -extends Resource - -@export var goals: Array[GoalData] = [] - -func get_goal_by_id(id: StringName) -> GoalData -func get_all_ids() -> Array[StringName] -``` - -**Location:** `res://docs/gyms/tiny_sword/goals/tiny_sword_goals.tres` - ---- - -## Implementation Steps - -### Step 1: Create Catalogue Classes - -**Files to create:** - -1. `core/currency_catalogue.gd` -2. `core/buff_catalogue.gd` -3. `core/goal_catalogue.gd` - -**Purpose:** Resource classes that hold arrays of game data and provide lookup methods. - ---- - -### Step 2: Create LevelGameState - -**File to create:** `core/level_game_state.gd` - -**Key changes from current `game_state.gd`:** - -| Current | New | -|---------|-----| -| `extends Node` (autoload) | `extends Node` (instance) | -| `CurrencyDatabase.get_known_currency_ids()` | `currency_catalogue.get_all_ids()` | -| `BuffDatabase` calls | `buff_catalogue` calls | -| Static `file_name` | `@export var save_file_path: String` | -| Filesystem goal discovery | `goal_catalogue.goals` array | -| Buff auto-registration from BuffDatabase | Buff registration from `buff_catalogue` | - -**New properties:** -```gdscript -@export var currency_catalogue: CurrencyCatalogue -@export var buff_catalogue: BuffCatalogue -@export var goal_catalogue: GoalCatalogue -@export var save_file_path: String = "user://level_save.json" -``` - -**Methods to port:** -- All currency methods (`add_currency`, `spend_currency`, `get_currency_amount_by_id`, etc.) -- All generator methods (`register_generator`, `get_generator_state`, etc.) -- All buff methods (`register_buff`, `get_buff_level`, `get_effective_multiplier`, etc.) -- All goal methods (`register_goal`, `is_goal_completed`, `evaluate_all_goals`, etc.) -- Save/load (`save_game()`, `load_game()`) with configurable path -- Prestige methods (`reset_for_prestige`, `emit_currency_changed_for_all`) - ---- - -### Step 3: Convert PrestigeManager - -**File to modify:** `core/prestige/prestige_manager.gd` - -**Changes:** -- Remove autoload registration from `project.godot` -- Add `@export var game_state: LevelGameState` -- Change `/root/PrestigeManager` lookup to use direct reference -- Make it a child node of `LevelGameState` in scenes - -**Key fix in `_get_prestige_multiplier()`:** -```gdscript -# Old: get_node_or_null("/root/PrestigeManager") -# New: Direct access through injected reference -``` - ---- - -### Step 4: Update CurrencyGenerator - -**File to modify:** `core/generator/currency_generator.gd` - -**Changes:** -- Replace all `GameState.` calls with `game_state.` calls -- Add `@onready var game_state: LevelGameState = find_parent("LevelGameState")` -- Update signal connections: `game_state.currency_changed.connect(...)` -- Update `_get_prestige_multiplier()` to use injected reference - ---- - -### Step 5: Update CurrencyTile - -**File to modify:** `currency_label.gd` - -**Changes:** -```gdscript -@export var game_state: LevelGameState # ← NEW - -func _ready() -> void: - if game_state == null: - push_error("CurrencyTile '%s' missing game_state reference" % name) - return - - _currency_id = game_state.get_currency_id(currency) - # ... rest of initialization -``` - ---- - -### Step 6: Update project.godot - -**Remove autoloads:** -```ini -# REMOVE these lines: -# BuffDatabase="*res://core/buff_database.gd" -# CurrencyDatabase="*res://core/currency_database.gd" -# GameState="*uid://d2j7tvlgxr2jp" -# PrestigeManager="*res://core/prestige/prestige_manager.gd" -``` - ---- - -### Step 7: Update tiny_sword.tscn - -**Add LevelGameState node:** -```ini -[node name="LevelGameState" type="Node" parent="."] -currency_catalogue = ExtResource("currency_catalogue_tres") -buff_catalogue = ExtResource("buff_catalogue_tres") -goal_catalogue = ExtResource("goal_catalogue_tres") -save_file_path = "user://tiny_sword_save.json" -``` - -**Add PrestigeManager as child:** -```ini -[node name="PrestigeManager" type="Node" parent="LevelGameState"] -game_state = NodePath("..") # Reference to LevelGameState -``` - -**Wire up children:** -- Each `CurrencyTile`: `game_state = LevelGameState` -- Each `CurrencyGenerator`: auto-discovers via `find_parent()` - ---- - -### Step 8: Create Catalogue Resources - -**Create `.tres` files via Godot editor:** - -1. `res://docs/gyms/tiny_sword/currencies/tiny_sword_catalogue.tres` - - `currencies = [gold, worker, food, wood]` - -2. `res://docs/gyms/tiny_sword/buffs/tiny_sword_buffs.tres` - - `buffs = [all relevant buffs for this level]` - -3. `res://docs/gyms/tiny_sword/goals/tiny_sword_goals.tres` - - `goals = [all relevant goals for this level]` - ---- - -### Step 9: Clean Up - -**Files to delete:** -- `core/currency_database.gd` (replaced by `CurrencyCatalogue`) -- `core/buff_database.gd` (replaced by `BuffCatalogue`) -- `core/game_state.gd` (replaced by `level_game_state.gd`) - ---- - -## File Summary - -### Files to Create (4) -| File | Purpose | -|------|---------| -| `core/currency_catalogue.gd` | Resource with `Array[Currency]` + lookup methods | -| `core/buff_catalogue.gd` | Resource with `Array[GeneratorBuffData]` + lookup methods | -| `core/goal_catalogue.gd` | Resource with `Array[GoalData]` + lookup methods | -| `core/level_game_state.gd` | Complete GameState implementation without autoload dependencies | - -### Files to Modify (4) -| File | Changes | -|------|---------| -| `core/prestige/prestige_manager.gd` | Remove autoload, add `@export var game_state` | -| `core/generator/currency_generator.gd` | Add `find_parent()` lookup, replace `GameState.` | -| `currency_label.gd` | Add `@export var game_state: LevelGameState` | -| `project.godot` | Remove 4 autoloads | - -### Files to Delete (3) -| File | Reason | -|------|--------| -| `core/currency_database.gd` | Replaced by `CurrencyCatalogue` | -| `core/buff_database.gd` | Replaced by `BuffCatalogue` | -| `core/game_state.gd` | Replaced by `level_game_state.gd` | - -### Scene Updates -| File | Changes | -|------|---------| -| `tiny_sword.tscn` | Add `LevelGameState` node, add `PrestigeManager` child, wire catalogues | -| Create `.tres` resources | `tiny_sword_catalogue.tres`, `tiny_sword_buffs.tres`, `tiny_sword_goals.tres` | - ---- - -## Benefits - -1. **Decoupled levels**: Each level can exist independently without global dependencies -2. **Multiple levels**: Can support multiple levels with independent state (future feature) -3. **Explicit dependencies**: All dependencies are visible in the inspector -4. **Resource-based catalogues**: Content is defined as editor-authorable resources -5. **Per-level saves**: Each level has its own save file path -6. **Better testing**: Easier to test individual levels in isolation - ---- - -## Risks and Considerations - -1. **Signal connections**: UI components must be manually wired to `LevelGameState` instance -2. **PrestigeManager access**: Must ensure proper reference injection -3. **Catalogue population**: Catalogue resources must be created and populated in editor -4. **Migration**: Existing save files may need migration logic - ---- - -## Implementation Order - -1. Create catalogue classes (3 files) -2. Create level_game_state.gd (the core refactor) -3. Update prestige_manager.gd (remove autoload dependency) -4. Update currency_generator.gd (add game_state injection) -5. Update currency_label.gd (add game_state export) -6. Update project.godot (remove autoloads) -7. Create catalogue resources (.tres files via editor) -8. Update tiny_sword.tscn (wire everything together) -9. Delete old files (cleanup) - ---- - -## Status - -- [ ] Step 1: Create catalogue classes -- [ ] Step 2: Create level_game_state.gd -- [ ] Step 3: Update prestige_manager.gd -- [ ] Step 4: Update currency_generator.gd -- [ ] Step 5: Update currency_label.gd -- [ ] Step 6: Update project.godot -- [ ] Step 7: Create catalogue resources (manual editor work) -- [ ] Step 8: Update tiny_sword.tscn (manual editor work) -- [ ] Step 9: Delete old files diff --git a/core/goal_catalogue.gd b/core/goals/goal_catalogue.gd similarity index 100% rename from core/goal_catalogue.gd rename to core/goals/goal_catalogue.gd diff --git a/core/goal_catalogue.gd.uid b/core/goals/goal_catalogue.gd.uid similarity index 100% rename from core/goal_catalogue.gd.uid rename to core/goals/goal_catalogue.gd.uid diff --git a/core/prestige/prestige_panel.gd b/core/prestige/prestige_panel.gd index b098ea6..5530a60 100644 --- a/core/prestige/prestige_panel.gd +++ b/core/prestige/prestige_panel.gd @@ -14,12 +14,16 @@ extends PanelContainer var _is_waiting_for_confirm: bool = false func _ready() -> void: - var manager: Node = _get_prestige_manager() + game_state.ready.connect(_on_game_state_ready) + +func _on_game_state_ready() -> void: + var manager: PrestigeManager = _get_prestige_manager() manager.prestige_state_changed.connect(_on_prestige_state_changed) manager.prestige_performed.connect(_on_prestige_performed) game_state.currency_changed.connect(_on_currency_changed) _refresh_ui() + func _on_reset_button_pressed() -> void: var manager: PrestigeManager = _get_prestige_manager() diff --git a/docs/gyms/tiny_sword/buildings/castle/castle.gd b/docs/gyms/tiny_sword/buildings/castle/castle.gd index 8bdceba..f68c4cc 100644 --- a/docs/gyms/tiny_sword/buildings/castle/castle.gd +++ b/docs/gyms/tiny_sword/buildings/castle/castle.gd @@ -12,7 +12,9 @@ func _process(delta: float) -> void: pass func _on_area_2d_mouse_entered() -> void: - _prestige_panel.visible = true + ## TODO: remove this comment to enable prestige panel + #_prestige_panel.visible = true + pass func _on_area_2d_mouse_exited() -> void: _prestige_panel.visible = false diff --git a/docs/gyms/tiny_sword/buildings/castle/castle.tscn b/docs/gyms/tiny_sword/buildings/castle/castle.tscn index be9a85c..882c612 100644 --- a/docs/gyms/tiny_sword/buildings/castle/castle.tscn +++ b/docs/gyms/tiny_sword/buildings/castle/castle.tscn @@ -23,6 +23,7 @@ position = Vector2(1, 22) shape = SubResource("RectangleShape2D_tgvch") [node name="PrestigePanel" parent="." unique_id=245519778 instance=ExtResource("3_l7gct")] +visible = false offset_left = 155.0 offset_top = -80.0 offset_right = 575.0 diff --git a/docs/gyms/tiny_sword/goals/ts_goal_catalogue.tres b/docs/gyms/tiny_sword/goals/ts_goal_catalogue.tres index 844d992..d5067d8 100644 --- a/docs/gyms/tiny_sword/goals/ts_goal_catalogue.tres +++ b/docs/gyms/tiny_sword/goals/ts_goal_catalogue.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="GoalCatalogue" format=3 uid="uid://cgt1mjir1v4br"] [ext_resource type="Script" uid="uid://dx4kmh33rrkpy" path="res://core/goals/goal_data.gd" id="1_6p6ue"] -[ext_resource type="Script" uid="uid://bfbp4mo8ys5p8" path="res://core/goal_catalogue.gd" id="2_84pbn"] +[ext_resource type="Script" uid="uid://bfbp4mo8ys5p8" path="res://core/goals/goal_catalogue.gd" id="2_84pbn"] [ext_resource type="Resource" uid="uid://ik7t0r3su633" path="res://docs/gyms/tiny_sword/goals/gold_total_30_goal.tres" id="2_xvtf2"] [ext_resource type="Resource" uid="uid://cts0407h130d6" path="res://docs/gyms/tiny_sword/goals/gold_total_1300_goal.tres" id="3_wb626"] [ext_resource type="Resource" uid="uid://bo463s6jt0ep7" path="res://docs/gyms/tiny_sword/goals/gold_total_13k_goal.tres" id="4_3oaoj"] diff --git a/docs/gyms/tiny_sword/tiny_sword.tscn b/docs/gyms/tiny_sword/tiny_sword.tscn index ce36306..0f0595a 100644 --- a/docs/gyms/tiny_sword/tiny_sword.tscn +++ b/docs/gyms/tiny_sword/tiny_sword.tscn @@ -43,6 +43,7 @@ anchors_preset = 0 layout_mode = 1 [node name="GoalsDebugUI" parent="LevelGameState/CanvasLayer/UI" unique_id=1494700185 instance=ExtResource("10_qifrv")] +visible = false layout_mode = 1 offset_left = 1433.0 offset_top = 5.0