class_name CurrencyGeneratorData extends Resource @export var id: StringName = &"" @export var name: String = "" @export var starts_unlocked: bool = true @export var starts_available: bool = true ## Base cost and exponential growth (part I): cost_next = b * r^owned @export var initial_cost: float = 10.0 @export var coefficient: float = 1.15 ## Generator timing and output. @export var initial_time: float = 1.0 @export var initial_revenue: float = 1.0 @export var initial_productivity: float = 1.0 ## Milestone boosts (part I), e.g. every 25 purchased grant x2. @export var milestone_step: int = 25 @export var milestone_multiplier: float = 2.0 ## Optional purchased-only boost from derivative-style models (part II). ## Example: 0.05 means each purchased unit adds +0.05% to output. @export var purchased_boost_percent: float = 0.0 ## Manual click reward for this generator. @export var click_mantissa: float = 1.0 @export var click_exponent: int = 0 @export var click_cooldown_seconds: float = 0.2 @export var grants_click_while_hovering: bool = false ## Returns cost of next generator func cost_next(owned: int) -> float: return cost_for_amount(owned, 1) ## Geometric-series bulk-buy cost (part I): ## total = b * r^k * ((r^n - 1) / (r - 1)) func cost_for_amount(owned: int, amount: int = 1) -> float: var safe_owned: int = maxi(owned, 0) var safe_amount: int = maxi(amount, 0) if safe_amount == 0: return 0.0 if initial_cost <= 0.0: return 0.0 if coefficient <= 0.0: return INF if is_equal_approx(coefficient, 1.0): return initial_cost * float(safe_amount) var r_to_owned: float = pow(coefficient, float(safe_owned)) var r_to_amount: float = pow(coefficient, float(safe_amount)) return initial_cost * r_to_owned * ((r_to_amount - 1.0) / (coefficient - 1.0)) ## Closed-form max-buy estimate from available currency (part I): ## max = floor(log((c(r-1)/(b*r^k))+1) / log(r)) func max_affordable(owned: int, currency: float) -> int: if currency <= 0.0: return 0 if initial_cost <= 0.0: return 0 if coefficient <= 0.0: return 0 var safe_owned: int = maxi(owned, 0) if is_equal_approx(coefficient, 1.0): return maxi(0, floori(currency / initial_cost)) var denominator: float = initial_cost * pow(coefficient, float(safe_owned)) if denominator <= 0.0: return 0 var inside: float = (currency * (coefficient - 1.0) / denominator) + 1.0 if inside <= 1.0: return 0 return maxi(0, floori(log(inside) / log(coefficient))) func milestone_count(owned: int) -> int: if milestone_step <= 0: return 0 return maxi(owned, 0) / milestone_step func milestone_multiplier_total(owned: int) -> float: if milestone_multiplier <= 1.0: return 1.0 var count: int = milestone_count(owned) if count <= 0: return 1.0 return pow(milestone_multiplier, float(count)) func purchased_multiplier(purchased: int) -> float: if purchased_boost_percent <= 0.0: return 1.0 return 1.0 + (float(maxi(purchased, 0)) * purchased_boost_percent * 0.01) func production_per_cycle(owned: int, run_multiplier: float = 1.0, purchased: int = -1) -> float: var safe_owned: int = maxi(owned, 0) if safe_owned == 0: return 0.0 var purchased_count: int = safe_owned if purchased < 0 else maxi(purchased, 0) var milestone_mult: float = milestone_multiplier_total(safe_owned) var purchased_mult: float = purchased_multiplier(purchased_count) return initial_productivity * float(safe_owned) * run_multiplier * milestone_mult * purchased_mult func production_per_second(owned: int, run_multiplier: float = 1.0, purchased: int = -1) -> float: return production_per_cycle(owned, run_multiplier, purchased) / maxf(initial_time, 0.0001) ## Returns value produced func production_total(owned: int, multipliers: float) -> float: return production_per_second(owned, multipliers) func payback_seconds(owned: int, amount: int = 1, run_multiplier: float = 1.0, purchased: int = -1) -> float: var safe_amount: int = maxi(amount, 1) var upgrade_cost: float = cost_for_amount(owned, safe_amount) if not is_finite(upgrade_cost): return INF var next_owned: int = maxi(owned, 0) + safe_amount var projected_rate: float = production_per_second(next_owned, run_multiplier, purchased) if projected_rate <= 0.0: return INF return upgrade_cost / projected_rate func income_to_cost_ratio(owned: int, amount: int = 1, run_multiplier: float = 1.0, purchased: int = -1) -> float: var safe_amount: int = maxi(amount, 1) var upgrade_cost: float = cost_for_amount(owned, safe_amount) if upgrade_cost <= 0.0 or not is_finite(upgrade_cost): return 0.0 var projected_rate: float = production_per_second(maxi(owned, 0) + safe_amount, run_multiplier, purchased) return projected_rate / upgrade_cost