Decouples core systems from centralized globals in favor of catalogue-based architecture and data-driven content. Key changes: - Prestige: node-based buff tech tree, graph panel, progress bar - Research: multi-worker system, per-generator research, xp generation - Ascension: meta-currency layer via multi-currency prestige resets - Buffs: refactored as generator-independent via catalogues - UI: currency panel, edge-scrolling camera + zoom, current-goal panel - Alchemy Tower: crafting building with recipe/cost system - Testing: 7 test suites (ascension, prestige, research, goals) - Content: migrated from hardcoded idles/ to gym format (tiny_sword)
71 lines
2.3 KiB
GDScript
71 lines
2.3 KiB
GDScript
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 = &""
|
|
|
|
## Worker Scaling Configuration
|
|
@export var worker_scaling_factor: float = 0.01
|
|
@export var min_workers_for_xp: int = 1
|
|
|
|
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)
|