# proposal.gd extends Control # --- UI 节点引用 --- @onready var title_label: Label = $proposal/Title/Title @onready var npc_name_label: Label = $proposal/Option/NPC_Info_1/Name @onready var npc_staff_type_label: Label = $proposal/Option/NPC_Info_1/Staff # 通常显示 "员工" @onready var npc_job_label: Label = $proposal/Option/NPC_Info_2/Info_List_0/Job/Title @onready var npc_level_label: Label = $proposal/Option/NPC_Info_2/Info_List_0/Job/Level @onready var npc_icon_rect: TextureRect = $proposal/Option/NPC_Info_2/Info_List_0/Icon @onready var stat_design_label: Label = $proposal/Option/NPC_Info_2/Info_List_1/Info_1/info @onready var stat_code_label: Label = $proposal/Option/NPC_Info_2/Info_List_1/Info_2/info @onready var stat_art_label: Label = $proposal/Option/NPC_Info_2/Info_List_1/Info_3/info @onready var stat_audio_label: Label = $proposal/Option/NPC_Info_2/Info_List_1/Info_4/info @onready var cost_label: Label = $proposal/Option/NPC_Info_2/Info_List_3/info_4/info @onready var power_bar_segments_container: HBoxContainer = $proposal/Option/NPC_Info_2/Info_List_2 var _power_bar_segments: Array[ColorRect] = [] # 用于存储体力条的各个片段 @onready var prev_button: Button = $proposal/Title/previous/Button @onready var next_button: Button = $proposal/Title/next/Button @onready var confirm_button: Button = $proposal/Confirm # --- 内部状态 --- var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据 var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字) var current_npc_index: int = -1 # 当前在 enabled_npc_keys 数组中选中的NPC的索引 # --- 常量 --- const NPC_ICON_BASE_PATH = "res://Entity/NPC/" # NPC 图标的基础路径 (如果后续有 Icon 字段) const DEFAULT_NPC_ICON_PATH = "res://Entity/NPC/NPC_1_UI.png" # 默认/占位NPC图标 const POWER_CURRENT_COLOR = Color.GREEN_YELLOW # 当前体力颜色 const POWER_MAX_POTENTIAL_COLOR = Color(0.2, 0.4, 0.2, 0.8) # 最大潜力槽颜色 (稍暗的绿色) const POWER_DISABLED_COLOR = Color(0.1, 0.1, 0.1, 0.3) # 体力条禁用/未达到部分的颜色 func _ready() -> void: var node_name = str(self.name) add_to_group(node_name) # 方便父节点或其他系统查找 # 收集体力条的片段 for child in power_bar_segments_container.get_children(): if child is ColorRect: _power_bar_segments.append(child) if _power_bar_segments.size() != 20: printerr(node_name + ": Expected 20 power bar segments, found " + str(_power_bar_segments.size())) # 连接信号 if prev_button and not prev_button.pressed.is_connected(_on_previous_pressed): prev_button.pressed.connect(_on_previous_pressed) if next_button and not next_button.pressed.is_connected(_on_next_pressed): next_button.pressed.connect(_on_next_pressed) if confirm_button and not confirm_button.pressed.is_connected(_on_confirm_pressed): confirm_button.pressed.connect(_on_confirm_pressed) if not is_connected("visibility_changed",Callable(self,"_on_visibility_changed")): visibility_changed.connect(Callable(self,"_on_visibility_changed")) # 如果节点在 _ready 时就可见,则立即刷新显示 if is_visible_in_tree(): reset_display() func _on_visibility_changed() -> void: if is_visible_in_tree(): reset_display() # 重置显示状态,在窗口可见时调用 func reset_display() -> void: print(str(self.name) + ": Resetting display state.") _load_and_filter_npcs() if enabled_npc_keys.is_empty(): current_npc_index = -1 print(str(self.name) + ": No enabled NPCs found.") else: current_npc_index = 0 # 默认显示第一个可用的NPC print(str(self.name) + ": Found %d enabled NPCs. Defaulting to index 0." % enabled_npc_keys.size()) _display_current_npc() # 从 GameState 加载NPC数据并筛选出可用的负责人 func _load_and_filter_npcs() -> void: _all_npcs_data.clear() enabled_npc_keys.clear() if not GameState: printerr(str(self.name) + ": GameState not available in _load_and_filter_npcs.") return var raw_npcs_data = GameState.get_value("npcs", {}) if raw_npcs_data.is_empty(): print(str(self.name) + ": 'npcs' data in GameState is empty or not found.") return _all_npcs_data = raw_npcs_data for npc_key in _all_npcs_data: var npc_info = _all_npcs_data[npc_key] if typeof(npc_info) == TYPE_DICTIONARY and npc_info.get("type") == "员工": enabled_npc_keys.append(npc_key) # 可选:对 enabled_npc_keys进行排序,以确保显示顺序一致 # enabled_npc_keys.sort() print(str(self.name) + ": Loaded and filtered NPCs. Enabled count: " + str(enabled_npc_keys.size())) # 根据 current_npc_index 更新UI显示 func _display_current_npc() -> void: if current_npc_index < 0 or current_npc_index >= enabled_npc_keys.size(): # --- 处理没有可用NPC或索引无效的情况 --- title_label.text = "策划案负责人" npc_name_label.text = "无可用负责人" npc_staff_type_label.text = "-" # 通常显示 "员工" npc_job_label.text = "-" npc_level_label.text = "-" npc_icon_rect.texture = null # 或者一个“无”的占位图 stat_design_label.text = "-" stat_code_label.text = "-" stat_art_label.text = "-" stat_audio_label.text = "-" cost_label.text = "-" # 隐藏所有体力条片段 for segment in _power_bar_segments: segment.visible = false if prev_button: prev_button.disabled = true if next_button: next_button.disabled = true if confirm_button: confirm_button.disabled = true return # --- 如果有有效NPC --- if prev_button: prev_button.disabled = enabled_npc_keys.size() <= 1 if next_button: next_button.disabled = enabled_npc_keys.size() <= 1 if confirm_button: confirm_button.disabled = false var display_index = current_npc_index + 1 var total_count = enabled_npc_keys.size() title_label.text = "策划案负责人 %d/%d" % [display_index, total_count] var npc_key = enabled_npc_keys[current_npc_index] if not _all_npcs_data.has(npc_key): printerr(str(self.name) + ": Current NPC key '%s' not found in cached _all_npcs_data!" % npc_key) # 显示错误状态,可以做得更友好 npc_name_label.text = "错误:数据丢失" # 隐藏所有体力条片段 for segment in _power_bar_segments: segment.visible = false return var npc_info = _all_npcs_data[npc_key] # 更新基本信息 npc_name_label.text = npc_key npc_staff_type_label.text = npc_info.get("type", "员工") # 根据筛选,这里应该是"员工" npc_job_label.text = npc_info.get("title", "-") npc_level_label.text = "Lv" + str(int(npc_info.get("level", 1))) # 更新图标 (后续会从npc_info.Icon获取) var icon_name_from_data = npc_info.get("Icon", "") # 假设后续会有这个字段 if not icon_name_from_data.is_empty(): var dynamic_icon_path = NPC_ICON_BASE_PATH + icon_name_from_data + ".png" # 假设文件名规则 if ResourceLoader.exists(dynamic_icon_path): npc_icon_rect.texture = ResourceLoader.load(dynamic_icon_path) else: printerr(str(self.name) + ": Failed to load NPC icon: " + dynamic_icon_path + ". Falling back to default.") npc_icon_rect.texture = ResourceLoader.load(DEFAULT_NPC_ICON_PATH) else: # print(str(self.name) + ": NPC icon name is empty for key '%s'. Using default." % npc_key) npc_icon_rect.texture = ResourceLoader.load(DEFAULT_NPC_ICON_PATH) # 更新能力值 (确保转换为整数显示) stat_design_label.text = str(int(npc_info.get("design", 0.0))) stat_code_label.text = str(int(npc_info.get("code", 0.0))) stat_art_label.text = str(int(npc_info.get("art", 0.0))) stat_audio_label.text = str(int(npc_info.get("audio", 0.0))) # 更新费用 cost_label.text = str(int(npc_info.get("outsourcing", 0.0))) # --- 更新体力条 (包含 visible 控制) --- var power = float(npc_info.get("power", 0.0)) var power_max = float(npc_info.get("power_max", 0.0)) if power_max <= 0: # 防止除零错误或无效数据 for segment in _power_bar_segments: segment.visible = false # 如果最大体力为0或无效,所有格段都不可见 else: var total_visible_segments = floori(power_max / 10.0) # 根据 power_max 计算总共应显示的格数 var current_power_segments = floori(power / 10.0) # 当前体力对应的格数 # 确保 current_power_segments 不会超过 total_visible_segments (逻辑上 power 不应大于 power_max) current_power_segments = mini(current_power_segments, total_visible_segments) for i in range(_power_bar_segments.size()): # 遍历所有20个可能的格段 var segment = _power_bar_segments[i] if i < total_visible_segments: segment.visible = true # 此格段在NPC的最大体力范围内,设为可见 if i < current_power_segments: segment.color = POWER_CURRENT_COLOR # 当前体力部分 else: segment.color = POWER_MAX_POTENTIAL_COLOR # 最大潜力中未充满的部分 else: segment.visible = false # 此格段超出NPC的最大体力范围,设为不可见 func _on_previous_pressed() -> void: if enabled_npc_keys.size() > 1: current_npc_index -= 1 if current_npc_index < 0: current_npc_index = enabled_npc_keys.size() - 1 _display_current_npc() func _on_next_pressed() -> void: if enabled_npc_keys.size() > 1: current_npc_index += 1 if current_npc_index >= enabled_npc_keys.size(): current_npc_index = 0 _display_current_npc() func _on_confirm_pressed() -> void: if current_npc_index != -1 and current_npc_index < enabled_npc_keys.size(): var selected_npc_key = enabled_npc_keys[current_npc_index] var parent_node = get_parent() if parent_node and parent_node.has_method("update_task_options"): parent_node.update_task_options({"关键环节负责人": selected_npc_key}) print(str(self.name) + ": Confirmed NPC '%s'. Sent to parent." % selected_npc_key) else: printerr(str(self.name) + ": Parent node not found or missing 'update_task_options' method.") # 无论父节点是否成功更新,都尝试继续后续流程 if parent_node and parent_node.has_method("start_task"): parent_node.start_task() else: printerr(str(self.name) + ": Parent node not found or missing 'start_task' method.") if parent_node and parent_node.has_method("close_all_popups"): parent_node.close_all_popups() else: printerr(str(self.name) + ": Parent node not found or missing 'close_all_popups' method.") self.hide() # Fallback hide else: print(str(self.name) + ": No valid NPC selected to confirm.") # 即使没有有效选择,也尝试关闭(或提示用户) var parent_node = get_parent() if parent_node and parent_node.has_method("close_all_popups"): parent_node.close_all_popups() # 或者只关闭自己并返回主界面 else: self.hide()