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