# Goals Module Documentation ## Overview The `goals/` subfolder contains the achievement system. Goals track player progress and can unlock generators or buffs when conditions are met. ## Files | File | Purpose | |------|---------| | `goal_data.gd` | Goal definition resource | | `goal_requirement_data.gd` | Individual requirement criteria | ## GoalData Resource class defining an achievement. ### Properties ```gdscript class_name GoalData extends Resource @export var id: StringName = &"" # Unique identifier @export var requirements: Array[GoalRequirementData] # Conditions to complete @export var unlock_behavior: UnlockBehavior = MANUAL # AUTOMATIC or MANUAL ``` ### Enum ```gdscript enum UnlockBehavior { AUTOMATIC, # Goal completes immediately when met MANUAL, # Goal requires player to click unlock button } ``` ### Methods ```gdscript func has_id() -> bool # Has non-empty id func is_valid() -> bool # Has valid id and requirements func get_requirements() -> Array[GoalRequirementData] # Access requirements ``` **Note:** State-dependent methods (`is_goal_met()`, `get_goal_progress()`, `get_goal_requirement_summary()`) are implemented in `LevelGameState` for proper decoupling. ## GoalRequirementData Single condition within a goal. ### Properties ```gdscript class_name GoalRequirementData extends Resource @export var currency: Currency # Currency to track @export var amount_mantissa: float = 0.0 # Required amount (scientific notation) @export var amount_exponent: int = 0 ``` ### Methods ```gdscript func get_currency() -> Currency # Currency to track 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()`) are implemented in `LevelGameState` for proper decoupling. ### Progress Calculation Uses **logarithmic scaling** for better visual feedback on huge numbers: ```gdscript # Convert to log space current_log = log(current_mantissa) / log(10) + current_exponent required_log = log(required_mantissa) / log(10) + required_exponent # Progress ratio progress = clampf(current_log / required_log, 0.0, 1.0) ``` This means reaching 50% progress on a 1e100 goal requires ~1e50 currency. ## Goal Evaluation ### Automatic Checking `LevelGameState` evaluates goals whenever currency changes: ```gdscript func _on_currency_changed(currency_id, new_amount): evaluate_all_goals() ``` ### Completion Flow 1. Currency updated → signal emitted 2. `LevelGameState.evaluate_all_goals()` called 3. Each uncompleted goal checked via `is_goal_met(goal)` 4. If met → `goal_completed` signal emitted 5. Buffs with unlock goals checked → unlocked if goal complete ### Manual Unlock vs Automatic Goals control their own unlock behavior via `unlock_behavior`: - **AUTOMATIC**: Goal completes immediately when requirements are met - **MANUAL**: Goal stays incomplete until player clicks unlock button Generators with `unlock_goal` automatically unlock when the goal completes. ### Goal Methods in LevelGameState ```gdscript func is_goal_requirement_met(requirement: GoalRequirementData) -> bool func get_goal_requirement_progress(requirement: GoalRequirementData) -> float func get_goal_requirement_summary(requirement: GoalRequirementData) -> String func is_goal_met(goal: GoalData) -> bool func get_goal_progress(goal: GoalData) -> float ``` ## Usage Example ### Defining a Goal Create `res://sandbox/goals/first_million.tres`: ``` [gd_resource type="Resource" script_class="GoalData"] [resource] id = &"first_million" requirements = [ preload("res://sandbox/goals/first_million_req.tres") ] ``` ### Defining a Requirement Create `res://sandbox/goals/first_million_req.tres`: ``` [gd_resource type="Resource" script_class="GoalRequirementData"] [resource] currency = preload("res://sandbox/currencies/gold.tres") amount_mantissa = 1.0 amount_exponent = 6 # 1,000,000 ``` ### Connecting to Generator In `CurrencyGeneratorData`: ```gdscript @export var unlock_goal: GoalData # Assign goal resource ``` The goal's `unlock_behavior` determines if the generator unlocks automatically or requires manual button click. ## Signals ```gdscript signal goal_completed(goal_id: StringName) signal goal_progress_changed(goal_id: StringName, progress: float) ``` ## Integration Points ### With LevelGameState - Goals registered from `GoalCatalogue` assigned to `LevelGameState` - Completion state saved to JSON - Buff unlock goals checked automatically ### With Buffs ```gdscript # In GeneratorBuffData @export var unlock_goal: GoalData # When goal completes, buff auto-unlocks: level_game_state._try_unlock_buff_from_goal(buff) ``` ### With Prestige - Goal completion state persists through prestige - Reset via `LevelGameState.reset_for_prestige()` ## See Also - `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