Randoloot/scripts/ui/save_browser.gd
2026-10-27 22:20:01 +01:00

161 lines
6.3 KiB
GDScript

extends "res://scripts/ui/menu_modal.gd"
signal load_requested(slot_id: String)
signal saved
const SHIPS := preload("res://scripts/game/ship_catalog.gd")
var save_mode := false
var _entries: Array[Dictionary] = []
var _selected_id := ""
var _name: LineEdit
var _list: VBoxContainer
var _summary: Label
var _status: Label
var _action: Button
var _group := ButtonGroup.new()
func _ready() -> void:
heading = "ZAPISZ WYPRAWĘ" if save_mode else "WCZYTAJ WYPRAWĘ"
subtitle = "Nadaj nazwę nowemu zapisowi lub wybierz zapis do nadpisania." if save_mode else "Wybierz zapis i wróć do swojej wyprawy."
marker = "ARCHIWUM / DZIENNIK POKŁADOWY"
preferred_size = Vector2(900,660)
super._ready()
if save_mode:
var row := HBoxContainer.new()
row.add_theme_constant_override("separation",12)
body.add_child(row)
_name = LineEdit.new()
_name.placeholder_text = tr("Nazwa zapisu")
_name.max_length = 48
_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_name.custom_minimum_size.y = 44
input_style(_name)
row.add_child(_name)
button(row,tr("Nowy zapis"),_new_save)
_name.text_changed.connect(func(_text: String) -> void: _update_action())
_name.text_submitted.connect(func(_text: String) -> void: _activate())
var content := HBoxContainer.new()
content.add_theme_constant_override("separation",18)
body.add_child(content)
var left := VBoxContainer.new()
left.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content.add_child(left)
label(left,tr("ZAPISANE WYPRAWY"),11,CYAN)
var scroll := ScrollContainer.new()
scroll.custom_minimum_size = Vector2(440,270 if save_mode else 340)
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
left.add_child(scroll)
_list = VBoxContainer.new()
_list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_list.add_theme_constant_override("separation",10)
scroll.add_child(_list)
var details := PanelContainer.new()
details.custom_minimum_size.x = 220
details.add_theme_stylebox_override("panel",box(Color("0e202d"),Color("294653"),16))
content.add_child(details)
var info := VBoxContainer.new()
info.add_theme_constant_override("separation",16)
details.add_child(info)
label(info,tr("DANE WYPRAWY"),11,GOLD)
_summary = label(info,"",14)
_summary.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
var rule_note := label(info,tr("Wczytanie rozpoczyna poziom od początku. Postęp i wyposażenie zostają zachowane."),12,MUTED)
rule_note.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_status = label(body,"",12,GOLD)
_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_status.hide()
button(footer,tr("Anuluj"),_close)
_action = button(footer,tr("Zapisz grę") if save_mode else tr("Wczytaj"),_activate,true)
_refresh_list()
if save_mode: _new_save()
elif not _entries.is_empty(): _select(_entries[0])
_update_action()
func _refresh_list() -> void:
for child in _list.get_children():
_list.remove_child(child)
child.queue_free()
_entries = GameState.SAVES.list_saves()
for entry in _entries:
if save_mode and entry.id == "auto": continue
_add_entry(entry)
if _list.get_child_count() == 0:
var empty := label(_list,tr("Nie ma jeszcze zapisanych wypraw."),14,MUTED)
empty.custom_minimum_size = Vector2(400,96)
empty.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
func _add_entry(entry: Dictionary) -> void:
var card := Button.new()
card.toggle_mode = true
card.button_group = _group
card.custom_minimum_size.y = 88
card.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
style_button(card)
card.name = entry.id
_list.add_child(card)
var row := HBoxContainer.new()
row.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
row.offset_left = 14
row.offset_top = 12
row.offset_right = -14
row.offset_bottom = -12
row.add_theme_constant_override("separation",14)
card.add_child(row)
var icon := TextureRect.new()
icon.texture = load(SHIPS.texture_path(SHIPS.for_path(entry.ship_path)))
icon.custom_minimum_size = Vector2(54,54)
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.add_child(icon)
var column := VBoxContainer.new()
column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
column.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.add_child(column)
var name_label := label(column,tr(entry.name) if entry.id == "auto" else entry.name,16)
name_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
name_label.auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED if entry.id != "auto" else Node.AUTO_TRANSLATE_MODE_INHERIT
var metadata := label(column,tr("Układ %d · Kapitan %d") % [entry.level,entry.captain_level],12,CYAN)
metadata.mouse_filter = Control.MOUSE_FILTER_IGNORE
var date := label(column,str(entry.saved_at).replace("T"," "),11,MUTED)
date.mouse_filter = Control.MOUSE_FILTER_IGNORE
card.pressed.connect(_select.bind(entry))
func _select(entry: Dictionary) -> void:
_selected_id = entry.id
if save_mode: _name.text = entry.name
_summary.text = tr("Układ %d\nKapitan · poziom %d\nKredyty: %d") % [entry.level,entry.captain_level,entry.credits]
if entry.recovered: _summary.text += "\n\n"+tr("Odzyskano z kopii zapasowej")
for card in _list.get_children():
if card is Button: card.set_pressed_no_signal(card.name == _selected_id)
_update_action()
func _new_save() -> void:
_selected_id = ""
_name.text = tr("Wyprawa %d") % GameState.system_level
for card in _list.get_children():
if card is Button: card.set_pressed_no_signal(false)
_summary.text = tr("Nowy zapis\nUkład %d\nKapitan · poziom %d") % [GameState.system_level,GameState.captain.level]
_name.grab_focus()
_name.select_all()
_update_action()
func _update_action() -> void:
if _action == null: return
_action.disabled = _name.text.strip_edges().is_empty() if save_mode else _selected_id.is_empty()
_action.text = tr("Nadpisz zapis") if save_mode and not _selected_id.is_empty() else tr("Zapisz grę" if save_mode else "Wczytaj")
func _activate() -> void:
if _action.disabled: return
if not save_mode:
load_requested.emit(_selected_id)
return
var result := GameState.save_named_game(_name.text,_selected_id)
if result != OK:
_status.text = tr("Nie udało się zapisać gry.")+" "+error_string(result)
_status.show()
return
saved.emit()
_close()