boot/: opening_screen (attribution -> title/flavor text placeholder, explicitly marked TODO for a later real cinematic, skippable by keypress/click) -> main_menu (Neues Spiel/Fortsetzen/Optionen/Credits/ Beenden, ConfirmationDialog for overwrite-existing-save) -> options_menu (TabContainer with 4 empty placeholder categories: Grafik/Sound/ Steuerung/Spieloptionen) and credits_screen, both just navigable stubs. project.godot's run/main_scene now points at boot/opening_screen.tscn instead of directly at the gameplay scene. autoload/save_manager.gd: new SaveManager singleton. Deliberately minimal — persists only a timestamp to user://savegame.json — but a real, working has_save()/save_game()/load_game()/start_new_game() round trip, enough to back the menu's Start/Continue/overwrite-confirm logic without inventing game state that doesn't exist yet. player/equipment/: Equipment (Node) + EquipmentItem (Resource) stub classes per the user's explicit ask for a "class diagram skeleton" to build on later — exported fields and empty TODO methods, no logic. Wired as a child of world/island.tscn's real Player (not player.tscn, which is only a debug prototype scene, not the actual game's player). player.gd's new `equipment` onready var uses get_node_or_null() since that child only exists on the real player, not every scene reusing this script. Verified headless: all new boot scenes load cleanly, a full boot smoke test via run/main_scene succeeds, and — since button-click navigation can't be simulated headlessly — SaveManager's actual save/load/ overwrite/cleanup cycle was exercised directly and behaves correctly (has_save flips true/false correctly, loaded data matches what was saved). Manual in-editor check of the menu navigation itself is still needed and not yet done.
38 lines
1.1 KiB
GDScript
38 lines
1.1 KiB
GDScript
extends Node
|
|
|
|
const SAVE_PATH := "user://savegame.json"
|
|
|
|
func has_save() -> bool:
|
|
return FileAccess.file_exists(SAVE_PATH)
|
|
|
|
func start_new_game() -> void:
|
|
# TODO: sobald echter Spielzustand existiert (Position, Fortschritt, ...),
|
|
# hier den frischen Zustand aufbauen statt nur zu speichern.
|
|
save_game()
|
|
|
|
func save_game() -> void:
|
|
var data := {
|
|
"saved_at_unix": Time.get_unix_time_from_system(),
|
|
}
|
|
var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
|
if file == null:
|
|
push_error("Speichern fehlgeschlagen: %s" % FileAccess.get_open_error())
|
|
return
|
|
file.store_string(JSON.stringify(data))
|
|
file.close()
|
|
|
|
func load_game() -> Dictionary:
|
|
if not has_save():
|
|
push_warning("Kein Spielstand vorhanden.")
|
|
return {}
|
|
var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
|
|
var content := file.get_as_text()
|
|
file.close()
|
|
var parsed = JSON.parse_string(content)
|
|
if typeof(parsed) != TYPE_DICTIONARY:
|
|
push_error("Spielstand-Datei ist beschädigt.")
|
|
return {}
|
|
# TODO: geladene Werte tatsächlich auf Spieler/Welt anwenden, sobald es
|
|
# etwas Sinnvolles zu laden gibt.
|
|
return parsed
|