Files
SectSimulator/src/UI/Panels/SavePanel.gd
T

169 lines
5.9 KiB
GDScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
## 存档面板(挂载于 SavePanel.tscn)。
## 两级浏览:左侧存档组列表 → 右侧该组槽位列表。
## 存档模式(游戏内):点"新建存档"每次创建新槽位;读档模式(主菜单):点槽位读档。
extends PanelContainer
## 面板模式。
enum Mode { SAVE, LOAD }
## 请求关闭面板(返回上级界面)。
signal back_pressed
## 槽位条目场景。
const SAVE_SLOT_SCENE := preload("res://src/UI/Panels/SaveSlot.tscn")
@onready var title_label: Label = %TitleLabel
@onready var group_container: VBoxContainer = %GroupContainer
@onready var slot_list: VBoxContainer = %SlotList
@onready var new_slot_button: Button = %Button_NewSlot
## 当前模式。
var mode: Mode = Mode.LOAD
## 当前浏览的存档组 ID。
var _current_profile: int = 0
## 打开面板前的暂停状态(存档模式关闭时恢复)。
var _was_paused := false
## 读档模式打开(主菜单,不暂停时间,自动选中第一个存档组)。
func open_load() -> void:
mode = Mode.LOAD
new_slot_button.visible = false
_current_profile = 0
var profiles := SaveSystem.get_profiles()
if profiles.size() > 0:
_current_profile = int(profiles[0]["id"])
_show_profiles()
visible = true
## 存档模式打开(游戏内,暂停时间,当前组固定高亮)。
## 点槽位 = 回到该进度点;点"新建存档" = 保存当前进度为新槽。
func open_save() -> void:
mode = Mode.SAVE
new_slot_button.visible = true
_current_profile = GameState.profile_id
_was_paused = TimeSystem.paused
TimeSystem.set_paused(true)
_show_profiles()
visible = true
## 关闭面板(恢复打开前的暂停状态)。
func close_panel() -> void:
visible = false
TimeSystem.set_paused(_was_paused)
## 点击"返回"。
func _on_button_esc_button_up() -> void:
close_panel()
if mode == Mode.LOAD:
back_pressed.emit()
## 点击"新建存档":在所属组下创建新槽位并刷新列表。
func _on_button_new_slot_button_up() -> void:
if SaveSystem.save_game(_current_profile) != "":
_show_slots()
## 左列:存档组列表(当前组高亮;存档模式下当前组固定)。
func _show_profiles() -> void:
title_label.text = "选择存档(存档模式)" if mode == Mode.SAVE else "选择存档"
_clear(group_container)
var profiles := SaveSystem.get_profiles()
if profiles.is_empty():
var label := Label.new()
label.text = "暂无存档组"
group_container.add_child(label)
_show_slots()
return
for p in profiles:
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 6)
var btn := Button.new()
btn.text = "%s %s" % [p["name"], p["last_date"]]
btn.toggle_mode = true
var is_current: bool = int(p["id"]) == _current_profile
btn.set_pressed_no_signal(is_current)
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
if mode == Mode.SAVE and is_current:
btn.disabled = true
else:
btn.button_up.connect(_on_group_pressed.bind(int(p["id"])))
row.add_child(btn)
# 删除按钮:存档模式下当前组禁用(正在使用)
var del_btn := Button.new()
del_btn.text = "删"
del_btn.disabled = mode == Mode.SAVE and is_current
del_btn.button_up.connect(_on_profile_delete_requested.bind(int(p["id"])))
row.add_child(del_btn)
group_container.add_child(row)
_show_slots()
## 请求删除存档组:直接删除并刷新(当前浏览组删除后自动切到第一组)。
## @param profile_id: 存档组 ID
func _on_profile_delete_requested(profile_id: int) -> void:
if not SaveSystem.delete_profile(profile_id):
return
if _current_profile == profile_id:
_current_profile = 0
var profiles := SaveSystem.get_profiles()
if profiles.size() > 0:
_current_profile = int(profiles[0]["id"])
_show_profiles()
## 点击存档组:切换浏览。
## @param profile_id: 存档组 ID
func _on_group_pressed(profile_id: int) -> void:
_current_profile = profile_id
_show_profiles()
## 右列:当前组槽位列表。
func _show_slots() -> void:
_clear(slot_list)
if _current_profile == 0:
return
var slots := SaveSystem.get_slots(_current_profile)
if slots.is_empty():
var label := Label.new()
label.text = "(暂无存档,点上方\"新建存档\"" if mode == Mode.SAVE else "(该组暂无存档)"
slot_list.add_child(label)
return
for i in slots.size():
_add_slot_entry(i + 1, slots[i])
## 添加一条槽位条目。
## @param index: 序号(1 起)
## @param slot: 槽位元数据 {name, date_text, disciple_count, spirit_stones}
func _add_slot_entry(index: int, slot: Dictionary) -> void:
var entry: PanelContainer = SAVE_SLOT_SCENE.instantiate()
slot_list.add_child(entry)
var slot_name := str(slot["name"])
var index_text := "自动" if slot_name == "auto" else str(index)
var name_text := "自动存档" if slot_name == "auto" else "存档 %d" % index
entry.setup(slot_name, index_text, name_text,
"%s 弟子%d人" % [slot["date_text"], slot["disciple_count"]],
"灵石 %d" % slot["spirit_stones"])
entry.slot_pressed.connect(_on_slot_pressed)
entry.delete_requested.connect(_on_slot_delete_requested)
## 点击槽位:读档模式进入游戏;存档模式回到该进度点(当前未保存进度丢失)。
## @param slot_name: 槽文件名(不含 .json
func _on_slot_pressed(slot_name: String) -> void:
if mode == Mode.LOAD:
GameState.request_load_game(_current_profile, slot_name)
get_tree().change_scene_to_file("res://src/Core/MainGame.tscn")
return
# 存档模式:直接加载所选槽位(回到该进度点)
if SaveSystem.load_game(_current_profile, slot_name):
close_panel()
## 请求删除槽位:直接删除并刷新(确认弹窗后续接入)。
## @param slot_name: 槽文件名(不含 .json
func _on_slot_delete_requested(slot_name: String) -> void:
if SaveSystem.delete_slot(_current_profile, slot_name):
_show_slots()
## 清空容器。
## @param container: 目标容器
func _clear(container: VBoxContainer) -> void:
for child in container.get_children():
child.queue_free()