# 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 is_valid() -> bool              # Has id and valid requirements
func is_met() -> bool                # All requirements satisfied
func get_progress() -> float         # 0.0 to 1.0 based on closest requirement
func get_first_requirement_summary() -> String  # "100 Gold" format
```

## 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_amount() -> BigNumber              # Required amount
func is_met() -> bool                       # Current >= required
func get_progress() -> float                # Log-scaled 0.0-1.0
func get_summary_text() -> String           # "100 Gold" format
```

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

`GameState` evaluates goals whenever currency changes:

```gdscript
func _on_currency_changed(currency_id, new_amount):
	GameState.evaluate_all_goals()
```

### Completion Flow

1. Currency updated → signal emitted
2. `GameState.evaluate_all_goals()` called
3. Each uncompleted goal checked via `is_met()`
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.

## 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 GameState
- Goals auto-discovered from `res://sandbox/goals/`
- 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:
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 management
- `generator/currency_generator_data.gd` - Generator unlock goals
- `generator/generator_buff_data.gd` - Buff unlock goals
