feat: 定时招募弹窗,开局5选3+定期3候选,配置驱动(GameConfig/RecruitPanel)

This commit is contained in:
2026-08-06 00:13:31 +08:00
parent a00c95af51
commit a3cbd738ad
10 changed files with 324 additions and 28 deletions
@@ -0,0 +1,96 @@
[gd_scene format=3 uid="uid://d4y7q3m6k2x5n7w2"]
[ext_resource type="Script" path="res://src/UI/Panels/RecruitPanel/recruit_panel.gd" id="1_script"]
[ext_resource type="FontFile" uid="uid://drt448qncx27p" path="res://assets/fonts/dingliezhuhaifont-20240831GengXinBan)-2.ttf" id="2_font"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dialog"]
bg_color = Color(0.11, 0.08, 0.13, 0.97)
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
[node name="RecruitPanel" type="Control" unique_id=770000001]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_script")
[node name="Backdrop" type="ColorRect" parent="." unique_id=770000002]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0, 0, 0, 0.6)
[node name="CenterContainer" type="CenterContainer" parent="." unique_id=770000003]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Panel" type="PanelContainer" parent="CenterContainer" unique_id=770000004]
theme_override_styles/panel = SubResource("StyleBoxFlat_dialog")
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/Panel" unique_id=770000005]
theme_override_constants/margin_left = 28
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 28
theme_override_constants/margin_bottom = 20
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/Panel/MarginContainer" unique_id=770000006]
theme_override_constants/separation = 12
[node name="TitleLabel" type="Label" parent="CenterContainer/Panel/MarginContainer/VBoxContainer" unique_id=770000007]
unique_name_in_owner = true
theme_override_fonts/font = ExtResource("2_font")
theme_override_font_sizes/font_size = 30
text = "弟子入宗"
[node name="HintLabel" type="Label" parent="CenterContainer/Panel/MarginContainer/VBoxContainer" unique_id=770000008]
unique_name_in_owner = true
theme_override_fonts/font = ExtResource("2_font")
theme_override_font_sizes/font_size = 20
theme_override_colors/font_color = Color(0.78, 0.75, 0.82, 1)
text = ""
[node name="ScrollContainer" type="ScrollContainer" parent="CenterContainer/Panel/MarginContainer/VBoxContainer" unique_id=770000009]
custom_minimum_size = Vector2(640, 300)
size_flags_vertical = 3
[node name="ListContainer" type="VBoxContainer" parent="CenterContainer/Panel/MarginContainer/VBoxContainer/ScrollContainer" unique_id=770000010]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
[node name="ButtonRow" type="HBoxContainer" parent="CenterContainer/Panel/MarginContainer/VBoxContainer" unique_id=770000011]
theme_override_constants/separation = 8
[node name="Button_AcceptAll" type="Button" parent="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow" unique_id=770000012]
unique_name_in_owner = true
theme_override_fonts/font = ExtResource("2_font")
theme_override_font_sizes/font_size = 22
text = "全部接受"
[node name="Button_RejectAll" type="Button" parent="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow" unique_id=770000013]
unique_name_in_owner = true
theme_override_fonts/font = ExtResource("2_font")
theme_override_font_sizes/font_size = 22
text = "全部拒绝"
[node name="Spacer" type="Control" parent="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow" unique_id=770000014]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button_Confirm" type="Button" parent="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow" unique_id=770000015]
unique_name_in_owner = true
theme_override_fonts/font = ExtResource("2_font")
theme_override_font_sizes/font_size = 22
text = "确定"
[connection signal="button_up" from="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow/Button_AcceptAll" to="." method="_on_button_accept_all_button_up"]
[connection signal="button_up" from="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow/Button_RejectAll" to="." method="_on_button_reject_all_button_up"]
[connection signal="button_up" from="CenterContainer/Panel/MarginContainer/VBoxContainer/ButtonRow/Button_Confirm" to="." method="_on_button_confirm_button_up"]
+108
View File
@@ -0,0 +1,108 @@
## 招募弹窗(挂载于 RecruitPanel.tscn)。
## 监听候选生成信号自动弹出,玩家勾选后点"确定"结算入宗。
extends Control
## 招募模式:开局必须选满 / 定期自由选择。
enum Mode { OPENING, PERIODIC }
@onready var title_label: Label = %TitleLabel
@onready var hint_label: Label = %HintLabel
@onready var list_container: VBoxContainer = %ListContainer
@onready var confirm_button: Button = %Button_Confirm
## 当前招募模式。
var _mode: Mode = Mode.PERIODIC
## 勾选框列表(与 _entry_disciples 按下标一一对应)。
var _check_buttons: Array[CheckButton] = []
## 对应勾选框的候选弟子。
var _entry_disciples: Array[Disciple] = []
func _ready() -> void:
# 订阅候选生成信号:开局与定期招募都会触发
DiscipleManager.applicants_generated.connect(_on_applicants_generated)
visible = false
## 候选生成时弹出:按当前候选池重建列表。
## @param is_opening: 是否开局招募
func _on_applicants_generated(is_opening: bool) -> void:
_mode = Mode.OPENING if is_opening else Mode.PERIODIC
_clear_entries()
for d in DiscipleManager.applicants:
_add_entry(d)
title_label.text = "弟子入宗(%s" % ("开局招募" if is_opening else "定期招募")
_update_ui()
visible = true
## 勾选任一候选后刷新提示与确定按钮可用性。
func _on_check_toggled(_pressed: bool, _d: Disciple) -> void:
_update_ui()
## 全部接受:勾选所有候选。
func _on_button_accept_all_button_up() -> void:
for c in _check_buttons:
c.set_pressed_no_signal(true)
_update_ui()
## 全部拒绝:取消所有勾选。
func _on_button_reject_all_button_up() -> void:
for c in _check_buttons:
c.set_pressed_no_signal(false)
_update_ui()
## 确定:勾选的入宗、未勾选的拒绝,关闭弹窗并恢复时间。
func _on_button_confirm_button_up() -> void:
var selected: Array[Disciple] = []
for i in _entry_disciples.size():
if _check_buttons[i].button_pressed:
selected.append(_entry_disciples[i])
DiscipleManager.finish_recruitment(selected)
_close()
## 刷新提示文本与确定按钮状态。
func _update_ui() -> void:
if _mode == Mode.OPENING:
var picked := 0
for c in _check_buttons:
if c.button_pressed:
picked += 1
hint_label.text = "开局招募:请选择 %d 名弟子入宗(已选 %d/%d" % [
GameConfig.opening_pick_count, picked, _check_buttons.size(),
]
confirm_button.disabled = picked < GameConfig.opening_pick_count
else:
hint_label.text = "定期招募:勾选入宗弟子,未勾选的将被拒绝(可全部拒绝)"
confirm_button.disabled = false
## 关闭弹窗:清空条目并恢复时间推进。
func _close() -> void:
_clear_entries()
visible = false
TimeSystem.set_paused(false)
## 清空候选条目。
func _clear_entries() -> void:
for child in list_container.get_children():
child.queue_free()
_check_buttons.clear()
_entry_disciples.clear()
## 添加一名候选的行条目:信息文本 + 入宗勾选框。
## @param d: 候选弟子
func _add_entry(d: Disciple) -> void:
var row := HBoxContainer.new()
var info := Label.new()
info.text = "%s %d岁 | %s资质%s | %s灵根 | %s" % [
d.name, d.age, d.get_aptitude_name(),
"·天灵根" if d.is_heavenly else "",
d.get_roots_text(), d.get_realm_text(),
]
info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var check := CheckButton.new()
check.text = "入宗"
check.toggled.connect(_on_check_toggled.bind(d))
row.add_child(info)
row.add_child(check)
list_container.add_child(row)
_check_buttons.append(check)
_entry_disciples.append(d)
@@ -0,0 +1 @@
uid://byjqc1ssqulc5