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)
156 lines
5.3 KiB
GDScript
156 lines
5.3 KiB
GDScript
class_name ResearchPanel
|
|
extends PanelContainer
|
|
|
|
const RESEARCH_ROW_SCENE: PackedScene = preload("res://core/research/research_row.tscn")
|
|
|
|
@onready var _title_label: Label = $ScrollContainer/VBoxContainer/TitleLabel
|
|
@onready var _research_rows_container: VBoxContainer = $ScrollContainer/VBoxContainer/ResearchRows
|
|
@onready var _buy_worker_button: Button = $ScrollContainer/VBoxContainer/HBoxContainer/BuyWorkerButton
|
|
|
|
var _game_state: LevelGameState
|
|
var _research_rows: Dictionary = {}
|
|
var _active_research_id: StringName = &""
|
|
|
|
func _ready() -> void:
|
|
_game_state = find_parent("LevelGameState")
|
|
if _game_state == null:
|
|
push_error("ResearchPanel: Could not find LevelGameState parent")
|
|
return
|
|
|
|
_game_state.research_xp_changed.connect(_on_research_xp_changed)
|
|
_game_state.research_level_up.connect(_on_research_level_up)
|
|
_game_state.currency_changed.connect(_on_currency_changed)
|
|
_game_state.research_workers_changed.connect(_on_research_workers_changed)
|
|
|
|
_build_research_rows()
|
|
_refresh_all()
|
|
_refresh_worker_button()
|
|
|
|
func _build_research_rows() -> void:
|
|
for child in _research_rows_container.get_children():
|
|
child.queue_free()
|
|
_research_rows.clear()
|
|
_active_research_id = &""
|
|
|
|
if _game_state.research_catalogue:
|
|
for research in _game_state.research_catalogue.get_all_research():
|
|
var row: ResearchRow = RESEARCH_ROW_SCENE.instantiate()
|
|
_research_rows_container.add_child(row)
|
|
row.setup(research)
|
|
row.active_changed.connect(_on_research_active_changed.bind(research.id))
|
|
_research_rows[research.id] = row
|
|
|
|
_load_active_research_state()
|
|
|
|
func _refresh_all() -> void:
|
|
for row in _research_rows.values():
|
|
_refresh_row(row)
|
|
|
|
func _refresh_row(row: ResearchRow) -> void:
|
|
var research_id: StringName = row.get_research_id()
|
|
var xp: BigNumber = _game_state.get_research_xp(research_id)
|
|
var level: int = _game_state.get_research_level(research_id)
|
|
var research: ResearchData = _game_state.research_catalogue.get_research_by_id(research_id)
|
|
|
|
if research != null:
|
|
var progress: float = research.get_xp_progress(xp)
|
|
var multiplier: float = research.get_multiplier_for_level(level)
|
|
var xp_current: BigNumber = xp.subtract(research.get_total_xp_for_level(level))
|
|
var xp_needed: BigNumber = research.get_xp_required_for_level_big(level + 1)
|
|
|
|
row.update_display(level, progress, multiplier, xp_current, xp_needed)
|
|
|
|
func _on_research_xp_changed(research_id: StringName, _new_xp: BigNumber) -> void:
|
|
if _research_rows.has(research_id):
|
|
_refresh_row(_research_rows[research_id])
|
|
|
|
func _on_research_level_up(research_id: StringName, _old_level: int, _new_level: int) -> void:
|
|
if _research_rows.has(research_id):
|
|
_refresh_row(_research_rows[research_id])
|
|
|
|
func _on_research_active_changed(is_active: bool, research_id: StringName) -> void:
|
|
if is_active:
|
|
if _active_research_id != &"" and _active_research_id != research_id:
|
|
var existing_row: ResearchRow = _research_rows.get(_active_research_id)
|
|
if existing_row != null:
|
|
existing_row.set_active(false, false)
|
|
_active_research_id = research_id
|
|
_save_active_research_state()
|
|
else:
|
|
if _active_research_id == research_id:
|
|
_active_research_id = &""
|
|
_save_active_research_state()
|
|
|
|
func _load_active_research_state() -> void:
|
|
if _game_state == null:
|
|
return
|
|
|
|
var save_data: Dictionary = _game_state.get_external_save_data("research_active")
|
|
if save_data.has("active_research_id"):
|
|
var loaded_id: String = String(save_data.get("active_research_id", ""))
|
|
if not loaded_id.is_empty():
|
|
_active_research_id = StringName(loaded_id)
|
|
var row: ResearchRow = _research_rows.get(_active_research_id)
|
|
if row != null:
|
|
row.set_active(true, false)
|
|
|
|
func _save_active_research_state() -> void:
|
|
if _game_state == null:
|
|
return
|
|
|
|
var save_data: Dictionary = {}
|
|
if _active_research_id != &"":
|
|
save_data["active_research_id"] = String(_active_research_id)
|
|
_game_state.set_external_save_data("research_active", save_data)
|
|
|
|
func get_active_research_id() -> StringName:
|
|
return _active_research_id
|
|
|
|
func is_research_active(research_id: StringName) -> bool:
|
|
return _active_research_id == research_id
|
|
|
|
func activate_research(research_id: StringName) -> void:
|
|
if _research_rows.has(research_id):
|
|
var row: ResearchRow = _research_rows[research_id]
|
|
row.set_active(true)
|
|
|
|
func _on_currency_changed(currency_id: StringName, _new_amount: BigNumber) -> void:
|
|
if currency_id == &"worker":
|
|
_refresh_worker_button()
|
|
|
|
func _on_research_workers_changed(_new_count: int) -> void:
|
|
_refresh_worker_button()
|
|
|
|
func _can_buy_worker() -> bool:
|
|
if _game_state == null:
|
|
return false
|
|
|
|
var worker_currency: BigNumber = _game_state.get_currency_amount_by_id(&"worker")
|
|
|
|
return worker_currency.mantissa >= 1.0
|
|
|
|
func _buy_worker() -> void:
|
|
if _game_state == null:
|
|
return
|
|
|
|
_game_state.assign_worker_to_research()
|
|
|
|
func _on_buy_worker_pressed() -> void:
|
|
_buy_worker()
|
|
_refresh_worker_button()
|
|
|
|
func _refresh_worker_button() -> void:
|
|
if _buy_worker_button == null:
|
|
return
|
|
|
|
if _game_state == null:
|
|
_buy_worker_button.disabled = true
|
|
return
|
|
|
|
var can_buy: bool = _can_buy_worker()
|
|
_buy_worker_button.disabled = not can_buy
|
|
|
|
var worker_currency: BigNumber = _game_state.get_currency_amount_by_id(&"worker")
|
|
var research_workers: int = _game_state.get_research_workers()
|
|
_buy_worker_button.text = "Assign Worker to Research (%d available, %d assigned)" % [int(worker_currency.mantissa), research_workers]
|