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]