class_name ResearchData extends Resource @export var id: StringName = &"" @export var generator_id: StringName = &"" @export var name: String = "" @export_multiline var description: String = "" @export var icon: Texture2D ## XP Configuration @export var xp_per_currency_produced: float = 0.01 @export var base_xp_required: float = 100.0 @export var xp_growth_multiplier: float = 1.5 ## Multiplier Configuration @export var base_multiplier: float = 1.0 @export var multiplier_per_level: float = 0.1 ## Associated Buff (single buff per research track) @export var associated_buff_id: StringName = &"" func get_xp_required_for_level(level: int) -> float: return base_xp_required * pow(xp_growth_multiplier, float(maxi(level - 1, 0))) func get_xp_required_for_level_big(level: int) -> BigNumber: var float_val: float = base_xp_required * pow(xp_growth_multiplier, float(maxi(level - 1, 0))) return BigNumber.from_float(float_val) func get_total_xp_for_level(level: int) -> BigNumber: if level <= 0: return BigNumber.new(0.0, 0) var total: BigNumber = BigNumber.new(0.0, 0) for l in range(1, level + 1): total = total.add(get_xp_required_for_level_big(l)) return total func get_level_for_xp(xp: BigNumber) -> int: if xp.mantissa == 0.0: return 0 var level: int = 0 while true: var next_xp: BigNumber = get_total_xp_for_level(level + 1) if xp.compare_to(next_xp) < 0: break level += 1 return level func get_multiplier_for_level(level: int) -> float: return base_multiplier + (multiplier_per_level * float(maxi(level, 0))) func get_xp_progress(xp: BigNumber) -> float: if xp.mantissa == 0.0: return 0.0 var current_level: int = get_level_for_xp(xp) if current_level < 0: return 0.0 var xp_at_current_level: BigNumber = get_total_xp_for_level(current_level) var xp_needed_for_next: BigNumber = get_xp_required_for_level_big(current_level + 1) var xp_in_current_level: BigNumber = xp.subtract(xp_at_current_level) if xp_needed_for_next.mantissa == 0.0: return 1.0 var ratio: float = (xp_in_current_level.mantissa / xp_needed_for_next.mantissa) * pow(10.0, float(xp_in_current_level.exponent - xp_needed_for_next.exponent)) return clampf(ratio, 0.0, 1.0)