Cleanup and planning

This commit is contained in:
2026-03-29 15:24:13 +02:00
parent ebc9325b53
commit 85bbe51956
25 changed files with 635 additions and 725 deletions

View File

@@ -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

View File

@@ -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")

View File

@@ -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