whittler/scripts/unlock_data_lightweight.gd
2026-01-28 20:18:44 +00:00

124 lines
3.7 KiB
GDScript

class_name UnlockDataLightweight
## Lightweight unlock data structure for simulations
## Contains the same calculation logic as UnlockDataResource but without Resource overhead
var unlock_id: int = 0
var unlock_name: String = ""
var base_cost: int = 0
var is_unlocked: bool = false
# Scaling settings
var is_scaling: bool = false
var current_rank: int = 0
var max_rank: int = -1
# Cost scaling
var cost_scaling_type: int = 1 # 0=Linear, 1=Exponential
var cost_scaling_multiplier: float = 1.5
var cost_linear_increase: int = 100
var cost_ladder: Array[int] = []
# Effect ladder
var effect_ladder: Array[float] = []
# Base modifiers
var base_modifiers: Dictionary = {}
## Static factory method to create from UnlockDataResource (one-time conversion)
static func from_resource(resource: UnlockDataResource) -> UnlockDataLightweight:
var data = UnlockDataLightweight.new()
data.unlock_id = resource.unlock_id
data.unlock_name = resource.unlock_name
data.base_cost = resource.base_cost
data.is_scaling = resource.is_scaling
data.max_rank = resource.max_rank
data.cost_scaling_type = resource.cost_scaling_type
data.cost_scaling_multiplier = resource.cost_scaling_multiplier
data.cost_linear_increase = resource.cost_linear_increase
data.cost_ladder = resource.cost_ladder.duplicate()
data.effect_ladder = resource.effect_ladder.duplicate()
data.base_modifiers = resource.base_modifiers.duplicate(true)
# Start fresh
data.is_unlocked = false
data.current_rank = 0
return data
## Clone for thread safety (fast - no Resource creation)
func clone() -> UnlockDataLightweight:
var copy = UnlockDataLightweight.new()
copy.unlock_id = unlock_id
copy.unlock_name = unlock_name
copy.base_cost = base_cost
copy.is_scaling = is_scaling
copy.max_rank = max_rank
copy.cost_scaling_type = cost_scaling_type
copy.cost_scaling_multiplier = cost_scaling_multiplier
copy.cost_linear_increase = cost_linear_increase
copy.cost_ladder = cost_ladder # Shared - read-only
copy.effect_ladder = effect_ladder # Shared - read-only
copy.base_modifiers = base_modifiers # Shared - read-only
# Mutable state
copy.is_unlocked = false
copy.current_rank = 0
return copy
## Same logic as UnlockDataResource.get_next_cost()
func get_next_cost() -> int:
if not is_scaling:
return base_cost
if cost_ladder.size() > 0 and current_rank < cost_ladder.size():
return cost_ladder[current_rank]
if cost_scaling_type == 0: # Linear
return base_cost + (cost_linear_increase * current_rank)
else: # Exponential
return int(base_cost * pow(cost_scaling_multiplier, current_rank))
## Same logic as UnlockDataResource.get_current_modifiers()
func get_current_modifiers() -> Dictionary:
if not is_unlocked or current_rank == 0:
return {}
return get_modifiers_at_rank(current_rank)
## Same logic as UnlockDataResource.get_modifiers_at_rank()
func get_modifiers_at_rank(rank: int) -> Dictionary:
if rank == 0:
return {}
# For one-shot unlocks or empty ladder, return base_modifiers
if effect_ladder.size() == 0:
return base_modifiers.duplicate()
var ladder_index = rank - 1
if ladder_index >= effect_ladder.size():
ladder_index = effect_ladder.size() - 1 # Use last value if rank exceeds ladder
var result = {}
for key in base_modifiers.keys():
result[key] = effect_ladder[ladder_index]
return result
## Same logic as UnlockDataResource.can_rank_up()
func can_rank_up() -> bool:
if not is_scaling:
return not is_unlocked
if max_rank > 0 and current_rank >= max_rank:
return false
return true
## Same logic as UnlockDataResource.unlock()
func unlock() -> bool:
if not can_rank_up():
return false
if not is_scaling:
is_unlocked = true
current_rank = 1
else:
current_rank += 1
is_unlocked = true
return true