extends UIPage # --- 节点引用 --- @onready var options_container: VBoxContainer = $BG/Option/Options/List_1 @onready var explanation_label: Label = $BG/Option/Explaination # --- 内部状态 --- var option_buttons: Array[Button] = [] # 存储选项按钮节点的数组 var highlighted_button: Button = null # 当前逻辑上选中的按钮 (用于区分首次点击和确认点击) var current_strategy_data: Dictionary = {} # 存储从 GameState 获取的原始策略数据 var initial_selection_key: String = "" # 由父节点传入的初始/当前选择的策略 Key (中文名) # --- 初始化 --- func _ready() -> void: super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑) add_to_group(str(name)) # 便于父节点或其他系统查找 # --- 获取按钮引用 --- option_buttons.clear() for child in options_container.get_children(): if child is Button: option_buttons.append(child) # 断开旧连接以防万一 (虽然理论上 _ready 只执行一次) if child.is_connected("pressed", _on_option_button_pressed): child.disconnect("pressed", _on_option_button_pressed) # --- 连接 GameState 通用值变化信号 --- # 用于响应策略数据可能的动态变化 (如解锁新策略) if GameState and not GameState.state_value_changed.is_connected(_on_game_state_value_changed): GameState.state_value_changed.connect(_on_game_state_value_changed) # --- 连接 visibility_changed 信号 --- # 确保每次界面可见时都刷新列表内容 if not is_connected("visibility_changed", _on_visibility_changed): visibility_changed.connect(_on_visibility_changed) # _update_strategy_list() 不再在 _ready 中调用,移至 _on_visibility_changed # --- 父节点调用接口 --- # 由父节点 (task_development.gd) 在显示此弹窗前调用,传入当前的临时选择 func set_initial_selection(strategy_key: String) -> void: initial_selection_key = strategy_key print("Strategy: Initial selection key set by parent: '", initial_selection_key, "'") # 注意:这里只存储值,实际的高亮逻辑仍在 _update_strategy_list 中处理 # --- 信号处理 --- # 处理可见性变化的函数 func _on_visibility_changed() -> void: print("Strategy: _on_visibility_changed called, visible = ", is_visible_in_tree()) # 当节点变为可见时,更新列表并设置初始焦点 if is_visible_in_tree(): print("Strategy popup became visible. Updating list and setting focus...") # 确保在更新列表前,initial_selection_key 已被父节点设置 _update_strategy_list() # else: # 可选:如果需要在隐藏时做清理,可以在这里添加逻辑 # print("Strategy popup became hidden.") # 当 GameState 的任何值发生变化时调用 func _on_game_state_value_changed(key: String, new_value) -> void: # 检查是否是 task_development 数据发生了变化,这可能影响可用策略 # 注意:这是一个比较宽泛的检查。如果 task_development 下其他不相关数据变化也会触发刷新。 if key == "task_development": # 并且确保当前界面是可见的,避免在后台刷新不可见的UI if is_visible_in_tree(): print("Strategy: Detected change in 'task_development', refreshing list...") # 重新执行列表更新,它会使用最新的 GameState 数据 # 并尝试根据 initial_selection_key (由父节点设定,理论上不变) 恢复高亮 _update_strategy_list() # --- 核心 UI 更新逻辑 --- # 更新策略列表UI的函数 func _update_strategy_list() -> void: # 0. 重置界面逻辑状态 (清除上次的高亮和说明) _reset_highlight_state() # 0b. 【修改】从 MainController 的共享数据中获取初始应选中的策略 Key # 使用键名 "开发策略"。如果未找到该键,默认为空字符串。 # 这将覆盖之前可能通过 set_initial_selection 设置的值。 initial_selection_key = get_main_data("开发策略", "") # <--- 从共享数据获取初始高亮项 if not initial_selection_key.is_empty(): print("Strategy (_update_strategy_list): 从 get_main_data(\"开发策略\") 获取到初始选择 Key: '%s'" % initial_selection_key) else: print("Strategy (_update_strategy_list): 未从 get_main_data(\"开发策略\") 获取到初始选择 Key,或 Key 为空。") # 1. 从 GameState 获取最新的 task_development 数据 if not GameState: printerr("Strategy: GameState not available during _update_strategy_list.") for button in option_buttons: button.visible = false explanation_label.text = "错误:无法访问游戏状态。" return var task_dev_data: Dictionary = GameState.get_value("task_development", {}) if task_dev_data.is_empty(): printerr("Strategy: Failed to get 'task_development' data from GameState.") for button in option_buttons: button.visible = false explanation_label.text = "错误:无法获取开发数据。" return # 提取策略子字典 current_strategy_data = task_dev_data.get("strategies", {}) if current_strategy_data.is_empty(): printerr("Strategy: 'strategies' data not found or empty in task_development.") for button in option_buttons: button.visible = false explanation_label.text = "没有可用的开发策略。" return # 2. 筛选出已启用的策略 var enabled_strategies = [] for strategy_name in current_strategy_data: # 遍历字典的键 (策略中文名) var details: Dictionary = current_strategy_data[strategy_name] # 确保 details 是字典并且 'enabled' 键存在且为 true if typeof(details) == TYPE_DICTIONARY and details.get("enabled", false) == true: enabled_strategies.append({"name": strategy_name, "details": details}) # 如果需要固定顺序,可以排序 # enabled_strategies.sort_custom(func(a, b): return a["name"] < b["name"]) # 3. 填充按钮 var strategy_index: int = 0 var first_enabled_button: Button = null # 用于没有初始选择时的默认高亮 # --- 确保每次更新时正确设置按钮状态和信号连接 --- for button in option_buttons: button.visible = false button.disabled = true if button.is_connected("pressed", _on_option_button_pressed): button.disconnect("pressed", _on_option_button_pressed) if button.has_meta("strategy_name"): button.remove_meta("strategy_name") while strategy_index < enabled_strategies.size() and strategy_index < option_buttons.size(): var button: Button = option_buttons[strategy_index] var strategy_data: Dictionary = enabled_strategies[strategy_index] var strategy_name: String = strategy_data["name"] var strategy_details: Dictionary = strategy_data["details"] var title_label: Label = button.find_child("Title", true, false) as Label var cost_label: Label = button.find_child("Cost", true, false) as Label if title_label and cost_label: title_label.text = strategy_name var cost_value = strategy_details.get("Cost", null) if typeof(cost_value) == TYPE_FLOAT or typeof(cost_value) == TYPE_INT: var percentage: int = int(cost_value * 100) cost_label.text = "+%d%%" % percentage else: cost_label.text = "N/A" button.set_meta("strategy_name", strategy_name) button.visible = true button.disabled = false button.pressed.connect(_on_option_button_pressed.bind(button)) if first_enabled_button == null: first_enabled_button = button else: printerr("Strategy: 在按钮 '%s' 下未找到 Title 或 Cost 标签。" % button.name) strategy_index += 1 # 4. 设置初始逻辑选中状态和焦点 # (此部分逻辑不变,但现在 initial_selection_key 是从 get_main_data 获取的) # print("--- Updating Strategy List (Post GameState Load) ---") # Debugging # print("Initial selection key (potentially from get_main_data): '", initial_selection_key, "'") # Debugging var initial_highlight_button: Button = null if not initial_selection_key.is_empty(): # print("Searching for matching button for key: '", initial_selection_key, "'") # Debugging for button in option_buttons: if button.visible and not button.disabled: var meta_name = button.get_meta("strategy_name", "") # print(" Checking button: '", button.name, "' with meta: '", meta_name, "'") # Debugging if meta_name == initial_selection_key: # print(" Match found!: ", button.name) # Debugging initial_highlight_button = button break if initial_highlight_button == null: # print("No match found for initial key or key was empty. Trying first enabled button.") # Debugging initial_highlight_button = first_enabled_button if initial_highlight_button: # print("Button to initially highlight: ", initial_highlight_button.name) # Debugging _set_initial_highlight(initial_highlight_button) else: # print("No button available to highlight.") # Debugging explanation_label.text = "没有可用的开发策略。" # print("--- Finished Updating Strategy List (Post GameState Load) ---") # Debugging # --- 交互处理 --- # 处理选项按钮点击事件的函数 func _on_option_button_pressed(button_node: Button) -> void: # 从按钮元数据获取对应的策略名称 var strategy_name: String = button_node.get_meta("strategy_name", "") if strategy_name.is_empty(): printerr("Strategy: 无法从按钮 %s 获取 strategy_name 元数据。" % button_node.name) return # 检查点击的按钮是否就是当前已逻辑高亮的按钮 if button_node == highlighted_button: # --- 第二次点击 (确认选择) --- print("Strategy: Confirmed selection - ", strategy_name) set_main_data("开发策略", strategy_name) go_next() else: # --- 第一次点击 或 点击了不同的按钮 (更新逻辑选择和说明) --- print("Strategy: Logically selected - ", strategy_name) # 更新当前逻辑高亮的按钮引用 highlighted_button = button_node # 更新底部的说明文本 # 确保 current_strategy_data 是最新的 (理论上 _update_strategy_list 刚更新过) if current_strategy_data.has(strategy_name): var details: Dictionary = current_strategy_data[strategy_name] explanation_label.text = details.get("Explaination", "暂无说明。") # 使用 .get 提供默认值 else: # 如果因为某些原因数据不同步,显示错误 explanation_label.text = "错误:找不到策略详情。" printerr("Strategy: Could not find details for strategy '", strategy_name, "' in current_strategy_data.") # 注意:此时按钮的视觉焦点可能还未改变,依赖于 Button 主题的 focus 样式 # _set_initial_highlight 内部会处理 grab_focus # --- 辅助函数 --- # (辅助函数) 重置界面逻辑高亮状态 func _reset_highlight_state() -> void: highlighted_button = null # 清除逻辑高亮引用 explanation_label.text = "" # 清空说明文本 # (辅助函数) 设置初始逻辑选中按钮并赋予焦点 func _set_initial_highlight(button_to_highlight: Button) -> void: print("--- Setting Initial Highlight ---") if not is_instance_valid(button_to_highlight): printerr("Strategy: Invalid button passed to _set_initial_highlight.") return print("Button received: ", button_to_highlight.name) # 设置逻辑高亮引用 highlighted_button = button_to_highlight print("highlighted_button variable set to: ", highlighted_button.name) # 更新说明文本 var strategy_name = highlighted_button.get_meta("strategy_name", "") if not strategy_name.is_empty() and current_strategy_data.has(strategy_name): var details: Dictionary = current_strategy_data[strategy_name] explanation_label.text = details.get("Explaination", "暂无说明。") elif not strategy_name.is_empty(): explanation_label.text = "错误:找不到策略详情。" printerr("Strategy: Could not find details for highlighted strategy '", strategy_name, "'") else: explanation_label.text = "错误:无法获取策略名称。" # 如果连元数据都没有 # 尝试让按钮获得实际输入焦点 (使用 call_deferred 确保在安全的时机执行) # 这会让按钮应用其主题中的 "focus" 样式 if highlighted_button.is_inside_tree() and highlighted_button.visible and not highlighted_button.disabled: print("Attempting call_deferred('grab_focus') for: ", highlighted_button.name) highlighted_button.call_deferred("grab_focus") else: print("Button '%s' not valid, not in tree, hidden, or disabled. Cannot grab focus." % highlighted_button.name) print("--- Finished Setting Initial Highlight ---")