Decouple everything from globals
This commit is contained in:
@@ -38,12 +38,13 @@ enum UnlockBehavior {
|
||||
### 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
|
||||
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.
|
||||
@@ -62,12 +63,13 @@ extends Resource
|
||||
### Methods
|
||||
|
||||
```gdscript
|
||||
func get_currency() -> Currency # Currency to track
|
||||
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
|
||||
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:
|
||||
@@ -87,18 +89,18 @@ This means reaching 50% progress on a 1e100 goal requires ~1e50 currency.
|
||||
|
||||
### Automatic Checking
|
||||
|
||||
`GameState` evaluates goals whenever currency changes:
|
||||
`LevelGameState` evaluates goals whenever currency changes:
|
||||
|
||||
```gdscript
|
||||
func _on_currency_changed(currency_id, new_amount):
|
||||
GameState.evaluate_all_goals()
|
||||
game_state.evaluate_all_goals()
|
||||
```
|
||||
|
||||
### Completion Flow
|
||||
|
||||
1. Currency updated → signal emitted
|
||||
2. `GameState.evaluate_all_goals()` called
|
||||
3. Each uncompleted goal checked via `is_met()`
|
||||
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
|
||||
|
||||
@@ -110,6 +112,16 @@ Goals control their own unlock behavior via `unlock_behavior`:
|
||||
|
||||
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
|
||||
|
||||
@@ -13,53 +13,22 @@ enum UnlockBehavior {
|
||||
func has_id() -> bool:
|
||||
return not String(id).strip_edges().is_empty()
|
||||
|
||||
func get_valid_requirements() -> Array[GoalRequirementData]:
|
||||
var result: Array[GoalRequirementData] = []
|
||||
for requirement_resource in requirements:
|
||||
if requirement_resource == null:
|
||||
continue
|
||||
if not bool(requirement_resource.is_valid()):
|
||||
continue
|
||||
|
||||
result.append(requirement_resource)
|
||||
|
||||
return result
|
||||
func get_requirements() -> Array[GoalRequirementData]:
|
||||
return requirements.duplicate()
|
||||
|
||||
func is_valid() -> bool:
|
||||
if not has_id():
|
||||
return false
|
||||
|
||||
return not get_valid_requirements().is_empty()
|
||||
|
||||
func is_met() -> bool:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
|
||||
if requirements.is_empty():
|
||||
return false
|
||||
|
||||
for requirement_resource in valid_requirements:
|
||||
if not bool(requirement_resource.is_met()):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func get_first_requirement_summary() -> String:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
return ""
|
||||
return String(valid_requirements[0].get_summary_text())
|
||||
|
||||
func get_progress() -> float:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
return 0.0
|
||||
|
||||
var min_progress: float = 1.0
|
||||
for requirement in valid_requirements:
|
||||
if requirement == null or not requirement.is_valid():
|
||||
for req in requirements:
|
||||
if req == null:
|
||||
continue
|
||||
if req.get_currency() == null:
|
||||
continue
|
||||
if not req.has_valid_amount():
|
||||
continue
|
||||
|
||||
var requirement_progress: float = requirement.get_progress()
|
||||
if requirement_progress < min_progress:
|
||||
min_progress = requirement_progress
|
||||
|
||||
return min_progress
|
||||
return true
|
||||
|
||||
@@ -5,63 +5,11 @@ extends Resource
|
||||
@export var amount_mantissa: float = 0.0
|
||||
@export var amount_exponent: int = 0
|
||||
|
||||
func get_currency_id() -> StringName:
|
||||
if currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(currency)
|
||||
func get_currency() -> Currency:
|
||||
return currency
|
||||
|
||||
func get_amount() -> BigNumber:
|
||||
return BigNumber.new(amount_mantissa, amount_exponent)
|
||||
|
||||
func has_valid_currency() -> bool:
|
||||
var currency_id: StringName = get_currency_id()
|
||||
if currency_id == &"":
|
||||
return false
|
||||
|
||||
return GameState.is_known_currency_id(currency_id)
|
||||
|
||||
func has_valid_amount() -> bool:
|
||||
return get_amount().mantissa >= 0.0
|
||||
|
||||
func is_valid() -> bool:
|
||||
return has_valid_currency() and has_valid_amount()
|
||||
|
||||
func is_met() -> bool:
|
||||
if not is_valid():
|
||||
return false
|
||||
|
||||
var total_amount: BigNumber = GameState.get_total_currency_acquired_by_id(get_currency_id())
|
||||
return not total_amount.is_less_than(get_amount())
|
||||
|
||||
func get_summary_text() -> String:
|
||||
if not is_valid():
|
||||
return ""
|
||||
|
||||
var currency_name: String = GameState.get_currency_name(get_currency_id())
|
||||
return "%s %s" % [get_amount().to_string_suffix(2), currency_name]
|
||||
|
||||
func get_progress() -> float:
|
||||
if not is_valid():
|
||||
return 0.0
|
||||
|
||||
var current_amount: BigNumber = GameState.get_total_currency_acquired_by_id(get_currency_id())
|
||||
var required_amount: BigNumber = get_amount()
|
||||
|
||||
if required_amount.mantissa <= 0.0:
|
||||
return 1.0
|
||||
|
||||
if current_amount.is_greater_than(required_amount) or current_amount.is_equal_to(required_amount):
|
||||
return 1.0
|
||||
|
||||
if current_amount.mantissa <= 0.0:
|
||||
return 0.0
|
||||
|
||||
var current_log: float = log(maxf(current_amount.mantissa, 0.0001)) / log(10) + float(current_amount.exponent)
|
||||
var required_log: float = log(maxf(required_amount.mantissa, 0.0001)) / log(10) + float(required_amount.exponent)
|
||||
|
||||
if required_log <= 0.0:
|
||||
return 1.0
|
||||
|
||||
var progress: float = current_log / required_log
|
||||
return clampf(progress, 0.0, 1.0)
|
||||
|
||||
Reference in New Issue
Block a user