5.0 KiB
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
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
enum UnlockBehavior {
AUTOMATIC, # Goal completes immediately when met
MANUAL, # Goal requires player to click unlock button
}
Methods
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_met(), get_progress(), get_summary_text()) have been moved to LevelGameState for proper decoupling.
GoalRequirementData
Single condition within a goal.
Properties
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
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()) have been moved to LevelGameState for proper decoupling.
Progress Calculation
Uses logarithmic scaling for better visual feedback on huge numbers:
# 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:
func _on_currency_changed(currency_id, new_amount):
game_state.evaluate_all_goals()
Completion Flow
- Currency updated → signal emitted
LevelGameState.evaluate_all_goals()called- Each uncompleted goal checked via
is_goal_met(goal) - If met →
goal_completedsignal emitted - 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
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:
@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
signal goal_completed(goal_id: StringName)
signal goal_progress_changed(goal_id: StringName, progress: float)
Integration Points
With GameState
- Goals auto-discovered from
res://sandbox/goals/ - Completion state saved to JSON
- Buff unlock goals checked automatically
With Buffs
# In GeneratorBuffData
@export var unlock_goal: GoalData
# When goal completes, buff auto-unlocks:
GameState._try_unlock_buff_from_goal(buff)
With Prestige
- Goal completion state persists through prestige
- Reset via
GameState.reset_for_prestige()
See Also
core/game_state.gd- Goal state managementgenerator/currency_generator_data.gd- Generator unlock goalsgenerator/generator_buff_data.gd- Buff unlock goals