269 lines
12 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 ---")