292 lines
12 KiB
GDScript
292 lines
12 KiB
GDScript
extends UIPage
|
||
|
||
# --- UI 节点引用 ---
|
||
@onready var title_label: Label = $BG/Title/Title
|
||
@onready var npc_name_label: Label = $BG/Option/NPC_Info_1/Name
|
||
@onready var npc_staff_type_label: Label = $BG/Option/NPC_Info_1/Staff # 通常显示 "员工"
|
||
@onready var npc_job_label: Label = $BG/Option/NPC_Info_2/Info_List_0/Job/Title
|
||
@onready var npc_level_label: Label = $BG/Option/NPC_Info_2/Info_List_0/Job/Level
|
||
@onready var npc_icon_rect: TextureRect = $BG/Option/NPC_Info_2/Info_List_0/Icon
|
||
|
||
@onready var stat_design_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_1/info
|
||
@onready var stat_code_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_2/info
|
||
@onready var stat_art_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_3/info
|
||
@onready var stat_audio_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_4/info
|
||
|
||
@onready var cost_label: Label = $BG/Option/NPC_Info_2/Info_List_3/info_4/info
|
||
|
||
@onready var power_bar_segments_container: HBoxContainer = $BG/Option/NPC_Info_2/Info_List_2
|
||
var _power_bar_segments: Array[ColorRect] = [] # 用于存储体力条的各个片段
|
||
|
||
@onready var prev_button: Button = $BG/Title/previous/Button
|
||
@onready var next_button: Button = $BG/Title/next/Button
|
||
@onready var confirm_button: Button = $BG/Confirm
|
||
|
||
@onready var notice_path: Control = $notice
|
||
|
||
@export var Suitable_position:Array = []
|
||
|
||
# --- 内部状态 ---
|
||
var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据
|
||
var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字)
|
||
var current_npc_index: int = -1 # 当前在 enabled_npc_keys 数组中选中的NPC的索引
|
||
var temp_next_ui_node_path = ''
|
||
|
||
# --- 常量 ---
|
||
const NPC_ICON_BASE_PATH = "res://Entity/NPC/art/" # NPC 图标的基础路径 (如果后续有 Icon 字段)
|
||
const DEFAULT_NPC_ICON_PATH = "res://Entity/NPC/art/秘书.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:
|
||
super._ready()
|
||
var node_name = str(self.name)
|
||
add_to_group(node_name) # 方便父节点或其他系统查找
|
||
|
||
temp_next_ui_node_path = next_ui_node_path
|
||
|
||
# 收集体力条的片段
|
||
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.duplicate(true)
|
||
|
||
# Suitable_position 是一个 @export var Array,你需要确保它在编辑器中或通过代码被正确赋值。
|
||
# 例如: Suitable_position = ["项目经理", "技术总监", "艺术总监"]
|
||
|
||
for npc_key in _all_npcs_data:
|
||
var npc_info = _all_npcs_data[npc_key]
|
||
|
||
if typeof(npc_info) == TYPE_DICTIONARY:
|
||
var npc_type: String = npc_info.get("type", "") # 获取NPC类型,默认为空字符串
|
||
var npc_title: String = npc_info.get("title", "") # 获取NPC职位,默认为空字符串
|
||
var npc_outsourcing: float = float(npc_info.get("outsourcing", 0.0)) # 获取外包费用,默认为0.0
|
||
|
||
# 检查条件1: type是员工,同时title在Suitable_position中有
|
||
var condition1_met = false
|
||
if npc_type == "员工" and Suitable_position.has(npc_title):
|
||
condition1_met = true
|
||
|
||
# 检查条件2: outsourcing>0,同时title在Suitable_position中有
|
||
var condition2_met = false
|
||
if npc_outsourcing > 0.0 and Suitable_position.has(npc_title): # 浮点数比较建议与 0.0 比较
|
||
condition2_met = true
|
||
|
||
# 如果任一条件满足,则将该NPC加入到可用列表中
|
||
if condition1_met or condition2_met:
|
||
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]
|
||
|
||
# 从 cost_label 获取费用文本并转换为整数
|
||
var cost_string = cost_label.text
|
||
var current_npc_cost: int
|
||
|
||
# 进行转换,并处理可能的转换失败 (尽管在此逻辑下,cost_label.text 应该总是数字)
|
||
if cost_string.is_valid_int():
|
||
current_npc_cost = cost_string.to_int()
|
||
else:
|
||
printerr(str(self.name) + ": Error converting cost_label.text ('" + cost_string + "') to integer.")
|
||
# 可以选择在这里弹出一个错误提示给用户,或者阻止后续操作
|
||
# 例如,可以简单地返回,或者显示一个通知
|
||
go_to_child_page(notice_path) # 假设 notice_path 可以显示一个通用错误
|
||
return
|
||
|
||
# 导航到下一个页面或结束工作流
|
||
next_ui_node_path = temp_next_ui_node_path
|
||
|
||
# 将 GameState 中的 money 与当前NPC的 cost 进行比较
|
||
if GameState.get_value("money") < current_npc_cost:
|
||
# 如果钱不够,跳转到提示页面 (例如,显示“资金不足”)
|
||
# 您可能需要一个特定的提示页面或消息来指明是费用不足
|
||
# GameState.set_value("notice_msg","资金不足以支付该负责人费用:" + str(current_npc_cost)) # 示例:设置特定提示信息
|
||
go_to_child_page(notice_path)
|
||
else:
|
||
# 如果钱足够,则扣除费用
|
||
var new_money = GameState.get_value("money") - current_npc_cost
|
||
GameState.set_value("money", new_money)
|
||
|
||
# 设置选中的NPC为关键环节负责人
|
||
set_main_data("关键环节负责人", selected_npc_key)
|
||
GameState.set_value("dialogue_npc", selected_npc_key)
|
||
|
||
#设置任务状态开启
|
||
GameState.set_value("is_on_task",true)
|
||
go_next() # 进入下一个UI流程
|