finish implementing saving and loading
This commit is contained in:
parent
bdf78a55c0
commit
022053a078
|
|
@ -2,10 +2,6 @@ extends RoomTemplate
|
||||||
|
|
||||||
signal ini_room
|
signal ini_room
|
||||||
|
|
||||||
@onready var mask_memento: CollectableUi = %MaskMemento.ui
|
|
||||||
@onready var clothes_memento: CollectableUi = %ClothesMemento.ui
|
|
||||||
@onready var comic_memento: CollectableUi = %ComicMemento.ui
|
|
||||||
@onready var ceiling_memento: CollectableUi = %CeilingMemento.ui
|
|
||||||
@onready var board_trigger: InteractiveSprite = %MindBoard
|
@onready var board_trigger: InteractiveSprite = %MindBoard
|
||||||
@onready var door_trigger: InteractiveSprite = %DoorTrigger
|
@onready var door_trigger: InteractiveSprite = %DoorTrigger
|
||||||
@onready var card_board: CardBoard = %Board
|
@onready var card_board: CardBoard = %Board
|
||||||
|
|
@ -13,25 +9,26 @@ signal ini_room
|
||||||
|
|
||||||
func start_room():
|
func start_room():
|
||||||
save_game = State.active_save_game
|
save_game = State.active_save_game
|
||||||
##TODO: make sure this is done automagically!
|
save_game.current_room = State.rooms.YOUTH
|
||||||
# Setting Memento user interface elemnts as collected based on the savegame.
|
Scenes.completed_sequences = save_game.mementos_complete
|
||||||
#mask_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_CHILDHOOD > 0
|
Scenes.started_sequences = save_game.mementos_complete
|
||||||
#clothes_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_JUI_JUTSU > 0
|
card_board.initialise_from_save(save_game)
|
||||||
#comic_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_VOICE_TRAINING > 0
|
|
||||||
#ceiling_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_DRAEVEN > 0
|
|
||||||
|
|
||||||
$logic/PlayerController.process_mode = Node.PROCESS_MODE_INHERIT
|
$logic/PlayerController.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
ini_room.emit()
|
ini_room.emit()
|
||||||
Scenes.start_sequence(Scenes.id.YOUTH_DRAEVEN)
|
if not Scenes.is_sequence_repeating(Scenes.id.YOUTH_DRAEVEN):
|
||||||
State.queue_for_stage(%PlayerController)
|
Scenes.start_sequence(Scenes.id.YOUTH_DRAEVEN)
|
||||||
|
State.queue_for_stage(%PlayerController)
|
||||||
|
else:
|
||||||
|
State.pass_stage_to(%PlayerController)
|
||||||
|
%LightAnimation.lights_on()
|
||||||
|
|
||||||
|
|
||||||
func get_ready():
|
func get_ready():
|
||||||
self.show()
|
self.show()
|
||||||
$sfx/distant_rain.play()
|
$sfx/distant_rain.play()
|
||||||
$"sfx/rain on window".play()
|
$"sfx/rain on window".play()
|
||||||
await get_tree().create_timer(0.1).timeout
|
await get_tree().create_timer(0.1).timeout
|
||||||
$logic/UI/board.hide()
|
$logic/UI/board.hide()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
Scenes.scene_finished.connect(_on_scene_finished)
|
Scenes.scene_finished.connect(_on_scene_finished)
|
||||||
|
|
@ -43,11 +40,11 @@ func _ready():
|
||||||
|
|
||||||
func pull_save_state(save: SaveGame) -> void:
|
func pull_save_state(save: SaveGame) -> void:
|
||||||
save.board_state = card_board.get_save_dict()
|
save.board_state = card_board.get_save_dict()
|
||||||
|
save.current_room = State.rooms.YOUTH
|
||||||
|
save.mementos_complete = Scenes.completed_sequences
|
||||||
|
|
||||||
func _on_scene_finished(id: int, _repeat:bool):
|
func _on_scene_finished(id: int, _repeat:bool):
|
||||||
# need to properly implement saving and loading
|
await get_tree().create_timer(3).timeout
|
||||||
return
|
|
||||||
save_game.mementos_complete &= 1 << id
|
|
||||||
save_room()
|
save_room()
|
||||||
|
|
||||||
#FIXME forgot to comment what this means, just marking it for removal
|
#FIXME forgot to comment what this means, just marking it for removal
|
||||||
|
|
|
||||||
|
|
@ -1201,10 +1201,10 @@ func _ready() -> void:
|
||||||
Scenes.scene_finished.connect(lights_on)
|
Scenes.scene_finished.connect(lights_on)
|
||||||
Scenes.scene_starting.connect(lights_off)
|
Scenes.scene_starting.connect(lights_off)
|
||||||
|
|
||||||
func lights_off(_id: int, _repeat: bool):
|
func lights_off(_id: int = -1, _repeat: bool = false):
|
||||||
queue(\"lights_out\")
|
queue(\"lights_out\")
|
||||||
|
|
||||||
func lights_on(_id: int, _repeat: bool):
|
func lights_on(_id: int = -1, _repeat: bool = false):
|
||||||
queue(\"light_up\")
|
queue(\"light_up\")
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
@ -1420,6 +1420,7 @@ script = ExtResource("1_aitp0")
|
||||||
|
|
||||||
[node name="PlayerController" parent="logic" groups=["camera_owner"] instance=ExtResource("3_foj4y")]
|
[node name="PlayerController" parent="logic" groups=["camera_owner"] instance=ExtResource("3_foj4y")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
process_mode = 4
|
||||||
transform = Transform3D(0.686123, 0, 0.727485, 0, 1, 0, -0.727485, 0, 0.686123, 0.63, 0, 0.925)
|
transform = Transform3D(0.686123, 0, 0.727485, 0, 1, 0, -0.727485, 0, 0.686123, 0.63, 0, 0.925)
|
||||||
|
|
||||||
[node name="colission" type="Node3D" parent="logic"]
|
[node name="colission" type="Node3D" parent="logic"]
|
||||||
|
|
@ -2088,7 +2089,8 @@ shadow_enabled = true
|
||||||
omni_range = 2.17653
|
omni_range = 2.17653
|
||||||
omni_attenuation = 1.41421
|
omni_attenuation = 1.41421
|
||||||
|
|
||||||
[node name="light_animation" type="AnimationPlayer" parent="visuals/lights" groups=["scene_actors"]]
|
[node name="LightAnimation" type="AnimationPlayer" parent="visuals/lights" groups=["scene_actors"]]
|
||||||
|
unique_name_in_owner = true
|
||||||
libraries = {
|
libraries = {
|
||||||
&"": SubResource("AnimationLibrary_k8op5")
|
&"": SubResource("AnimationLibrary_k8op5")
|
||||||
}
|
}
|
||||||
|
|
@ -2246,7 +2248,7 @@ light_array = Array[Vector3]([Vector3(-0.545, 0.915, 1.035), Vector3(-0.47, 0.85
|
||||||
|
|
||||||
[connection signal="ini_room" from="." to="logic/PlayerController" method="_on_ini_room"]
|
[connection signal="ini_room" from="." to="logic/PlayerController" method="_on_ini_room"]
|
||||||
[connection signal="ini_room" from="." to="logic/ScenePlayer" method="_on_ini_room"]
|
[connection signal="ini_room" from="." to="logic/ScenePlayer" method="_on_ini_room"]
|
||||||
[connection signal="ini_room" from="." to="visuals/lights/light_animation" method="_on_ini_room"]
|
[connection signal="ini_room" from="." to="visuals/lights/LightAnimation" method="_on_ini_room"]
|
||||||
[connection signal="ui_entered" from="logic/PlayerController" to="SceneUI" method="show"]
|
[connection signal="ui_entered" from="logic/PlayerController" to="SceneUI" method="show"]
|
||||||
[connection signal="ui_exited" from="logic/PlayerController" to="SceneUI" method="hide"]
|
[connection signal="ui_exited" from="logic/PlayerController" to="SceneUI" method="hide"]
|
||||||
[connection signal="body_entered" from="logic/Bed and Ladders/ladder_trigger" to="logic/PlayerController" method="_on_bed_enter"]
|
[connection signal="body_entered" from="logic/Bed and Ladders/ladder_trigger" to="logic/PlayerController" method="_on_bed_enter"]
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,4 @@ func pull_save_state(save: SaveGame) -> void:
|
||||||
|
|
||||||
func save_room():
|
func save_room():
|
||||||
pull_save_state(save_game)
|
pull_save_state(save_game)
|
||||||
save_game.save_to_file.call_deferred(get_tree().root.get_texture())
|
save_game.save_to_file(get_tree().root.get_texture())
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,111 @@
|
||||||
@tool
|
@tool
|
||||||
class_name SaveGame extends Resource
|
class_name SaveGame extends Resource
|
||||||
|
|
||||||
@export var filepath: String
|
var _is_initialised: bool = false
|
||||||
@export var unique_save_name: String = "frame_of_mind_%s_%s" % [Time.get_date_string_from_system(), Time.get_time_string_from_system()]
|
|
||||||
@export var current_room: State.rooms = State.rooms.YOUTH
|
|
||||||
@export var mementos_complete: int = 0
|
|
||||||
@export var board_state: Dictionary = {}
|
|
||||||
@export var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png")
|
|
||||||
@export var last_saved: int = int(Time.get_unix_time_from_system())
|
|
||||||
|
|
||||||
@export var is_save_file_valid: bool = false
|
@export var filepath: String:
|
||||||
|
set(value):
|
||||||
|
filepath = value
|
||||||
|
if _is_initialised:
|
||||||
|
read_save_file()
|
||||||
|
changed.emit()
|
||||||
|
@export var unique_save_name: String = "frame_of_mind_%s_%s" % [Time.get_date_string_from_system(), Time.get_time_string_from_system().replace(":", "-")]:
|
||||||
|
set(value):
|
||||||
|
unique_save_name = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
@export var current_room: State.rooms = State.rooms.NULL:
|
||||||
|
set(value):
|
||||||
|
current_room = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
@export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0:
|
||||||
|
set(value):
|
||||||
|
mementos_complete = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
@export var board_state: Dictionary = {"cards": {}, "stickies": {}}:
|
||||||
|
set(value):
|
||||||
|
board_state = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
@export var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png"):
|
||||||
|
set(value):
|
||||||
|
thumbnail = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
@export var last_saved: int = int(Time.get_unix_time_from_system()):
|
||||||
|
set(value):
|
||||||
|
last_saved = value
|
||||||
|
if _is_initialised: changed.emit()
|
||||||
|
|
||||||
|
@export var is_valid: bool = false
|
||||||
|
@export var is_empty: bool = true:
|
||||||
|
get():
|
||||||
|
return not FileAccess.file_exists("%s.json:" % filepath)
|
||||||
|
@export var save_manually: bool = false:
|
||||||
|
set(val):
|
||||||
|
if val: save_to_file(thumbnail)
|
||||||
|
|
||||||
func _validate_property(property: Dictionary):
|
func _validate_property(property: Dictionary):
|
||||||
|
if property.name == filepath:
|
||||||
|
property.usage |= PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED
|
||||||
if property.name == "thumbnail":
|
if property.name == "thumbnail":
|
||||||
property.usage = not PROPERTY_USAGE_STORAGE
|
property.usage |= PROPERTY_USAGE_READ_ONLY
|
||||||
|
if property.name == "is_valid":
|
||||||
|
property.usage |= PROPERTY_USAGE_READ_ONLY
|
||||||
|
if property.name == "is_empty":
|
||||||
|
property.usage |= PROPERTY_USAGE_READ_ONLY
|
||||||
|
|
||||||
func _init(initial_filepath = "") -> void:
|
func _init(initial_filepath = "") -> void:
|
||||||
|
|
||||||
if initial_filepath == "":
|
if initial_filepath == "":
|
||||||
filepath = "%s/%s" % [State.user_saves_path, unique_save_name]
|
filepath = "%s/%s" % [State.user_saves_path, unique_save_name]
|
||||||
else:
|
else:
|
||||||
filepath = initial_filepath
|
filepath = initial_filepath
|
||||||
|
unique_save_name = initial_filepath.get_file()
|
||||||
read_save_file()
|
read_save_file()
|
||||||
|
_is_initialised = true
|
||||||
|
|
||||||
func read_save_file():
|
func read_save_file():
|
||||||
|
print("Opening Savegame: %s.json" % filepath)
|
||||||
|
|
||||||
if FileAccess.file_exists("%s.json:" % filepath):
|
if FileAccess.file_exists("%s.json" % filepath):
|
||||||
|
var file = FileAccess.open("%s.json" % filepath, FileAccess.READ)
|
||||||
|
var raw_json = FileAccess.get_file_as_string("%s.json" % filepath)
|
||||||
var file = FileAccess.open("%s.json:" % filepath, FileAccess.READ)
|
|
||||||
var raw_json = FileAccess.get_file_as_string("%s.json:" % filepath)
|
|
||||||
file.close()
|
file.close()
|
||||||
var parsed: Dictionary = JSON.parse_string(raw_json)
|
var parsed: Dictionary = JSON.parse_string(raw_json)
|
||||||
|
|
||||||
var tmp_img: Image
|
var tmp_img: Image
|
||||||
if FileAccess.file_exists("%s/thumbnails/%s.png" % [State.user_saves_path, filepath]):
|
|
||||||
tmp_img = Image.load_from_file("%s/thumbnails/%s.png" % [State.user_saves_path, filepath])
|
|
||||||
|
|
||||||
is_save_file_valid = (
|
if FileAccess.file_exists("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]):
|
||||||
|
tmp_img = Image.load_from_file("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name])
|
||||||
|
|
||||||
|
var are_types_valid = (
|
||||||
parsed["unique_save_name"] is String and
|
parsed["unique_save_name"] is String and
|
||||||
parsed["current_room"] is int and
|
parsed["current_room"] is float and
|
||||||
parsed["mementos_complete"] is int and
|
parsed["mementos_complete"] is float and
|
||||||
parsed["coard_state"] is Dictionary and
|
parsed["board_state"] is Dictionary and
|
||||||
parsed["last_saved"] is float and last_saved != 0 and
|
parsed["last_saved"] is float and last_saved != 0
|
||||||
parsed["tmp_img"] is Image
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_save_file_valid:
|
if are_types_valid:
|
||||||
for key in parsed.keys():
|
for key in parsed.keys():
|
||||||
set(key, parsed[key])
|
set(key, parsed[key])
|
||||||
|
|
||||||
|
for dict:Dictionary in board_state.values():
|
||||||
|
for key in dict.keys():
|
||||||
|
if dict[key] is String:
|
||||||
|
if dict[key].begins_with("("):
|
||||||
|
dict[key] = parse_vec_from_string(dict[key])
|
||||||
|
|
||||||
|
is_valid = are_types_valid \
|
||||||
|
and current_room >= 0 \
|
||||||
|
and current_room < State.rooms.keys().size() \
|
||||||
|
and validate_board_state()
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
push_error("Parsing of Save failed.")
|
||||||
|
|
||||||
if tmp_img != null:
|
if tmp_img != null:
|
||||||
thumbnail = ImageTexture.create_from_image(tmp_img)
|
thumbnail = ImageTexture.create_from_image(tmp_img)
|
||||||
|
is_empty = false
|
||||||
|
else:
|
||||||
|
is_valid = true
|
||||||
|
|
||||||
func _get_save_dict() -> Dictionary:
|
func _get_save_dict() -> Dictionary:
|
||||||
return {
|
return {
|
||||||
|
|
@ -64,13 +117,54 @@ func _get_save_dict() -> Dictionary:
|
||||||
}
|
}
|
||||||
|
|
||||||
func save_to_file(current_screen: Texture):
|
func save_to_file(current_screen: Texture):
|
||||||
return
|
|
||||||
last_saved = Time.get_unix_time_from_system()
|
last_saved = Time.get_unix_time_from_system()
|
||||||
|
|
||||||
var thumbnail_image: Image = current_screen.get_image()
|
var thumbnail_image: Image = current_screen.get_image()
|
||||||
thumbnail_image.resize(384, 261, Image.INTERPOLATE_LANCZOS) # nonexistent call in ViewportTexturew
|
thumbnail_image.resize(384, 261, Image.INTERPOLATE_LANCZOS) # nonexistent call in ViewportTexturew
|
||||||
|
|
||||||
thumbnail_image.save_png("%s/thumbnails/%s.png" % [State.user_saves_path, filepath])
|
var thumbnail_path: String = "%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]
|
||||||
|
var save_dir = DirAccess.open(filepath.get_base_dir())
|
||||||
|
if not save_dir.dir_exists("thumbnails"):
|
||||||
|
save_dir.make_dir("thumbnails")
|
||||||
|
|
||||||
var file = FileAccess.open("%s.json:" % filepath, FileAccess.WRITE)
|
thumbnail_image.save_png("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name])
|
||||||
|
#thumbnail_image.save_png("%s/test.png" % State.user_saves_path)
|
||||||
|
print(filepath.get_base_dir())
|
||||||
|
var file = FileAccess.open("%s.json" % filepath, FileAccess.WRITE)
|
||||||
file.store_string(JSON.stringify(_get_save_dict()))
|
file.store_string(JSON.stringify(_get_save_dict()))
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
func calculate_completed_sequences() -> int:
|
||||||
|
var i: int = mementos_complete - ((mementos_complete >> 1) & 0x55555555);
|
||||||
|
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||||||
|
i = (i + (i >> 4)) & 0x0F0F0F0F;
|
||||||
|
i *= 0x01010101;
|
||||||
|
return i >> 24;
|
||||||
|
|
||||||
|
func calculate_total_connections() -> int:
|
||||||
|
var connections:= 0
|
||||||
|
|
||||||
|
for sticky_position in board_state.stickies.values():
|
||||||
|
connections += int(sticky_position is String)
|
||||||
|
|
||||||
|
return connections
|
||||||
|
|
||||||
|
func validate_board_state() -> bool:
|
||||||
|
if board_state.keys().has("cards") and board_state.keys().has("stickies"):
|
||||||
|
for card in board_state.cards.values():
|
||||||
|
if not card is Vector2:
|
||||||
|
push_error("Save %s could not be parsed: Corrupted Cards." % unique_save_name)
|
||||||
|
return false
|
||||||
|
for sticky in board_state.stickies.values():
|
||||||
|
if not (sticky == -1 or sticky is Vector2 or board_state.cards.keys.has(sticky)):
|
||||||
|
push_error("Save %s could not be parsed: Corrupted Sticky Notes.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
func parse_vec_from_string(string: String) -> Vector2:
|
||||||
|
var string_array = string.replace("(", "").replace(")", "").split(", ")
|
||||||
|
return Vector2(float(string_array[0]), float(string_array[1]))
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ func _ready():
|
||||||
|
|
||||||
get_viewport().gui_focus_changed.connect(reclaim_lost_focus)
|
get_viewport().gui_focus_changed.connect(reclaim_lost_focus)
|
||||||
|
|
||||||
|
print(get_save_dict())
|
||||||
|
|
||||||
|
|
||||||
func reclaim_lost_focus():
|
func reclaim_lost_focus():
|
||||||
if has_stage:
|
if has_stage:
|
||||||
|
|
@ -396,19 +398,25 @@ func get_save_dict() -> Dictionary:
|
||||||
|
|
||||||
for child in dropzone.get_children():
|
for child in dropzone.get_children():
|
||||||
if child is Card:
|
if child is Card:
|
||||||
if child.has_sticky_note_attached():
|
# Save position of Card.
|
||||||
stickies[child.get_attached_sticky_note().name] = child.name
|
|
||||||
cards[child.name] = child.transform.origin
|
cards[child.name] = child.transform.origin
|
||||||
|
|
||||||
|
if child.has_sticky_note_attached():
|
||||||
|
# Saves Card Name as position of it's children.
|
||||||
|
stickies[child.get_attached_sticky_note().name] = child.name
|
||||||
|
|
||||||
elif child is StickyNote:
|
elif child is StickyNote:
|
||||||
|
# Save position of StickyNote.
|
||||||
cards[child.name] = child.transform.origin
|
cards[child.name] = child.transform.origin
|
||||||
|
|
||||||
for child in sticky_note_container.get_children():
|
for child in sticky_note_container.get_children():
|
||||||
if child is StickyNotePanel:
|
if child is StickyNotePanel:
|
||||||
|
# Saves all collected Stickies that are not on board.
|
||||||
stickies[child.attached_sticky_note.name] = -1
|
stickies[child.attached_sticky_note.name] = -1
|
||||||
return {
|
return {
|
||||||
"cards": cards,
|
"cards": cards,
|
||||||
"stickies": stickies
|
"stickies": stickies
|
||||||
} if cards != {} and stickies != {} else {}
|
}
|
||||||
|
|
||||||
func initialise_from_save(savegame: SaveGame):
|
func initialise_from_save(savegame: SaveGame):
|
||||||
if savegame.board_state == {}: return
|
if savegame.board_state == {}: return
|
||||||
|
|
@ -419,12 +427,13 @@ func initialise_from_save(savegame: SaveGame):
|
||||||
|
|
||||||
for card:Card in card_pile["cards"]:
|
for card:Card in card_pile["cards"]:
|
||||||
add_card(card)
|
add_card(card)
|
||||||
card.transform.origin = cards[card.name]
|
card.transform.origin = cards[card.name] # Replacing position reference with card reference! Needed in next loop.
|
||||||
cards[card.name] = card
|
cards[card.name] = card
|
||||||
|
|
||||||
for sticky:StickyNote in card_pile["sticky_notes"]:
|
for sticky:StickyNote in card_pile["sticky_notes"]:
|
||||||
if stickies[sticky.name] == -1:
|
if stickies[sticky.name] == -1.0:
|
||||||
add_sticky_note(sticky)
|
add_sticky_note(sticky)
|
||||||
if stickies[sticky.name] is String:
|
elif stickies[sticky.name] is String:
|
||||||
cards[stickies[sticky.name]].attach_sticky_note(sticky)
|
cards[stickies[sticky.name]].attach_sticky_note(sticky)
|
||||||
else:
|
else:
|
||||||
insert_area(dropzone, sticky)
|
insert_area(dropzone, sticky)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ var has_stage: bool = false:
|
||||||
if is_node_ready():
|
if is_node_ready():
|
||||||
if has_stage: new_game_button.grab_focus()
|
if has_stage: new_game_button.grab_focus()
|
||||||
new_game_button.disabled = not has_stage
|
new_game_button.disabled = not has_stage
|
||||||
continue_button.disabled = not has_stage
|
continue_button.disabled = not has_stage or save_game_handle.get_most_recent_save().current_room == 0
|
||||||
load_game_button.disabled = not has_stage
|
load_game_button.disabled = not has_stage or not save_game_handle.has_existing_saves()
|
||||||
settings_button.disabled = not has_stage
|
settings_button.disabled = not has_stage
|
||||||
credits_button.disabled = not has_stage
|
credits_button.disabled = not has_stage
|
||||||
quit_button.disabled = not has_stage
|
quit_button.disabled = not has_stage
|
||||||
|
|
@ -31,14 +31,14 @@ signal roll_credits
|
||||||
|
|
||||||
var await_new_game: bool = false
|
var await_new_game: bool = false
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
save_game_handle.picked.connect(_on_save_picked)
|
save_game_handle.picked.connect(_on_save_picked)
|
||||||
continue_button.visible = save_game_handle.get_most_recent_save().current_room != 0
|
continue_button.disabled = save_game_handle.get_most_recent_save().current_room == 0
|
||||||
continue_button.pressed.connect(func(): start_game.emit(save_game_handle.get_most_recent_save()))
|
continue_button.pressed.connect(func(): start_game.emit(save_game_handle.get_most_recent_save()))
|
||||||
new_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(true))
|
new_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(true))
|
||||||
load_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(false))
|
load_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(false))
|
||||||
|
load_game_button.disabled = not save_game_handle.has_existing_saves()
|
||||||
settings_button.get_popup().index_pressed.connect(settings_popup.show_settings)
|
settings_button.get_popup().index_pressed.connect(settings_popup.show_settings)
|
||||||
quit_button.pressed.connect(get_tree().quit)
|
quit_button.pressed.connect(get_tree().quit)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,119 @@
|
||||||
|
@tool
|
||||||
class_name SaveGameDisplay extends Button
|
class_name SaveGameDisplay extends Button
|
||||||
|
|
||||||
func _init(save: SaveGame, id: int) -> void:
|
var _is_built: bool = false
|
||||||
var base_container:= HBoxContainer.new()
|
|
||||||
base_container.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
||||||
add_child(base_container)
|
|
||||||
|
|
||||||
var texture:= TextureRect.new()
|
@export var save: SaveGame:
|
||||||
texture.texture = save.thumbnail
|
set(new_save):
|
||||||
texture.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
save = new_save
|
||||||
|
if _is_built: rebuild()
|
||||||
|
@export var id: int:
|
||||||
|
set(new_id):
|
||||||
|
id = new_id
|
||||||
|
if _is_built: rebuild()
|
||||||
|
|
||||||
base_container.add_child(texture)
|
func _init(new_save: SaveGame = SaveGame.new(), new_id: int = 0) -> void:
|
||||||
var heading_split:= HSplitContainer.new()
|
self.save = new_save
|
||||||
var heading:= Label.new()
|
self.id = new_id
|
||||||
|
|
||||||
heading.text = "Slot %d" % id
|
func _ready() -> void:
|
||||||
heading.theme_type_variation = "HeaderLarge"
|
save.changed.connect(rebuild)
|
||||||
|
rebuild()
|
||||||
|
_is_built = true
|
||||||
|
|
||||||
var localised_date_time: String
|
func rebuild():
|
||||||
var localised_weekday: PackedStringArray
|
for child in get_children(true):
|
||||||
var date_time: Dictionary = Time.get_datetime_dict_from_unix_time(save.last_saved)
|
remove_child(child)
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
match TranslationServer.get_locale():
|
if not save.is_valid:
|
||||||
"de":
|
disabled = true
|
||||||
localised_weekday = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
|
text = "Slot %d corrupted." % id
|
||||||
localised_date_time = "%s, %d.%d.%d um %d:%02d" % [localised_weekday[date_time["weekday"]],
|
else:
|
||||||
date_time["day"],
|
disabled = false
|
||||||
date_time["month"],
|
text = ""
|
||||||
date_time["year"],
|
|
||||||
date_time["hour"],
|
var base_container := HBoxContainer.new()
|
||||||
date_time["minute"]
|
base_container.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
]
|
add_child(base_container)
|
||||||
_:
|
|
||||||
localised_weekday = ["Monday", "Tuseday", "Wensday", "Thursday", "Friday", "Saturday", "Sunday"]
|
var texture := TextureRect.new()
|
||||||
localised_date_time = "%s, %d/%d/%d - %d:%02d (%s)" % [localised_weekday[date_time["weekday"]],
|
texture.texture = save.thumbnail
|
||||||
|
texture.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
|
base_container.add_child(texture)
|
||||||
|
var heading_split := HSplitContainer.new()
|
||||||
|
var heading := Label.new()
|
||||||
|
|
||||||
|
heading.text = "Slot %d" % id
|
||||||
|
heading.theme_type_variation = "HeaderLarge"
|
||||||
|
|
||||||
|
var localised_date_time: String
|
||||||
|
var localised_weekday: PackedStringArray
|
||||||
|
var date_time: Dictionary = Time.get_datetime_dict_from_unix_time(save.last_saved)
|
||||||
|
|
||||||
|
match TranslationServer.get_locale():
|
||||||
|
"de":
|
||||||
|
localised_weekday = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
|
||||||
|
localised_date_time = "%s, %d.%d.%d um %d:%02d" % [localised_weekday[date_time["weekday"]],
|
||||||
date_time["day"],
|
date_time["day"],
|
||||||
date_time["month"],
|
date_time["month"],
|
||||||
date_time["year"],
|
date_time["year"],
|
||||||
date_time["hour"] % 12 if date_time["hour"] % 12 > 1 else 12 if date_time["hour"] == 12 or date_time["minute"] == 0 else 0,
|
date_time["hour"],
|
||||||
date_time["minute"],
|
date_time["minute"]
|
||||||
"AM" if date_time["hour"] < 12 else "PM"]
|
]
|
||||||
|
_:
|
||||||
|
localised_weekday = ["Monday", "Tuseday", "Wensday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||||
|
localised_date_time = "%s, %d/%d/%d - %d:%02d (%s)" % [localised_weekday[date_time["weekday"]],
|
||||||
|
date_time["day"],
|
||||||
|
date_time["month"],
|
||||||
|
date_time["year"],
|
||||||
|
date_time["hour"] % 12 if date_time["hour"] % 12 > 1 else 12 if date_time["hour"] == 12 or date_time["minute"] == 0 else 0,
|
||||||
|
date_time["minute"],
|
||||||
|
"AM" if date_time["hour"] < 12 else "PM"]
|
||||||
|
|
||||||
var time:= Label.new()
|
var time_label := Label.new()
|
||||||
time.text = localised_date_time if not save.current_room == 0 else "Start new game."
|
time_label.text = localised_date_time if not save.current_room == State.rooms.NULL else "Start new game"
|
||||||
|
|
||||||
var info:= VBoxContainer.new()
|
var info:= VBoxContainer.new()
|
||||||
base_container.add_child(info)
|
base_container.add_child(info)
|
||||||
|
|
||||||
info.add_child(heading_split)
|
info.add_child(heading_split)
|
||||||
heading_split.add_child(heading)
|
heading_split.add_child(heading)
|
||||||
heading_split.add_child(time)
|
heading_split.add_child(time_label)
|
||||||
|
|
||||||
var room:= Label.new()
|
var room:= Label.new()
|
||||||
room.theme_type_variation = "HeaderMedium"
|
room.theme_type_variation = "HeaderMedium"
|
||||||
match save.current_room:
|
match save.current_room:
|
||||||
State.rooms.MENU:
|
State.rooms.NULL:
|
||||||
room.text = "Empty Slot"
|
room.text = "Empty Slot"
|
||||||
State.rooms.DRAVEN:
|
State.rooms.YOUTH:
|
||||||
room.text = "Intro Sequence"
|
if save.mementos_complete == 0:
|
||||||
State.rooms.YOUTH:
|
room.text = "Youth Room"
|
||||||
room.text = "Inside youth room."
|
else:
|
||||||
State.rooms.TRANSITION:
|
room.text = "Intro Sequence"
|
||||||
room.text = "Transitioning to Adulthood."
|
State.rooms.TRANSITION:
|
||||||
State.rooms.ADULTHOOD:
|
room.text = "Transitioning to Adulthood"
|
||||||
room.text = "Exploring Adulthood."
|
State.rooms.ADULTHOOD:
|
||||||
State.rooms.ENDING:
|
room.text = "Exploring Adulthood"
|
||||||
room.text = "Ending"
|
State.rooms.ENDING:
|
||||||
|
room.text = "Ending"
|
||||||
|
|
||||||
var state: = Label.new()
|
var state: = Label.new()
|
||||||
state.text = ("""
|
state.text = TranslationServer.translate(("""
|
||||||
Mementos collected: 1/4
|
Mementos collected: %d/4
|
||||||
Connections found: 1/8
|
Connections found: %d/8
|
||||||
Secrets found: 1/4
|
""").strip_edges()) % [save.calculate_completed_sequences(), save.calculate_total_connections()]
|
||||||
""").strip_edges()
|
#Secrets found: 1/4
|
||||||
|
|
||||||
info.add_child(room)
|
info.add_child(room)
|
||||||
info.add_child(state)
|
info.add_child(state)
|
||||||
info.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
info.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
custom_minimum_size = base_container.get_combined_minimum_size() + Vector2(64, 32)
|
theme_type_variation = "SaveButton"
|
||||||
|
|
||||||
theme_type_variation = "SaveButton"
|
call_deferred("resize")
|
||||||
|
|
||||||
|
func resize():
|
||||||
|
custom_minimum_size = get_child(0, true).get_combined_minimum_size() + Vector2(64, 32)
|
||||||
|
get_child(0, true).position = Vector2(32, 16)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,12 @@ var scroll_container: ScrollContainer
|
||||||
|
|
||||||
var override_save_slot: bool = false
|
var override_save_slot: bool = false
|
||||||
|
|
||||||
|
func _validate_property(property: Dictionary) -> void:
|
||||||
|
if property.name == "saves":
|
||||||
|
property.usage = PROPERTY_USAGE_READ_ONLY + PROPERTY_USAGE_SCRIPT_VARIABLE + PROPERTY_USAGE_EDITOR
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
#FIXME: stop this from creating countless save games!
|
|
||||||
return
|
|
||||||
var dir = DirAccess.open(State.user_saves_path)
|
var dir = DirAccess.open(State.user_saves_path)
|
||||||
print(DirAccess.get_open_error())
|
print(DirAccess.get_open_error())
|
||||||
# Invalid Error being raised when Directory does not exist.
|
# Invalid Error being raised when Directory does not exist.
|
||||||
|
|
@ -28,31 +31,39 @@ func _ready() -> void:
|
||||||
dir = DirAccess.open("user://")
|
dir = DirAccess.open("user://")
|
||||||
dir.make_dir_recursive(State.user_saves_path)
|
dir.make_dir_recursive(State.user_saves_path)
|
||||||
load_games()
|
load_games()
|
||||||
|
for i in range(save_buttons.size()):
|
||||||
|
save_buttons[i].pressed.connect(func(): picked.emit(saves[i]))
|
||||||
|
print("connect ", i)
|
||||||
|
|
||||||
func load_games():
|
func load_games():
|
||||||
|
saves = []
|
||||||
var save_game_dir := DirAccess.open(State.user_saves_path)
|
var save_game_dir := DirAccess.open(State.user_saves_path)
|
||||||
var filepaths: PackedStringArray = save_game_dir.get_files()
|
var filepaths: PackedStringArray = save_game_dir.get_files()
|
||||||
|
|
||||||
for path in filepaths:
|
for path in filepaths:
|
||||||
if path.ends_with(".json"):
|
if path.ends_with(".json"):
|
||||||
saves.append(SaveGame.new(path))
|
saves.append(SaveGame.new("%s/%s" % [State.user_saves_path, path.get_basename()]))
|
||||||
|
|
||||||
saves.append(SaveGame.new())
|
saves.append(SaveGame.new())
|
||||||
|
|
||||||
#purging the current state
|
#purging the current state
|
||||||
save_buttons = []
|
save_buttons = []
|
||||||
if scroll_container != null:
|
if scroll_container != null:
|
||||||
scroll_container.free()
|
scroll_container.queue_free()
|
||||||
|
|
||||||
scroll_container = ScrollContainer.new()
|
scroll_container = ScrollContainer.new()
|
||||||
|
|
||||||
scroll_container.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
scroll_container.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||||
|
scroll_container.custom_minimum_size = Vector2(0, ProjectSettings.get_setting("display/window/size/viewport_height") - 256)
|
||||||
add_child(scroll_container)
|
add_child(scroll_container)
|
||||||
|
|
||||||
|
var save_box := VBoxContainer.new()
|
||||||
|
save_box.add_theme_constant_override("separation", 16)
|
||||||
|
scroll_container.add_child(save_box)
|
||||||
|
|
||||||
for i in range(saves.size()):
|
for i in range(saves.size()):
|
||||||
var new_button := SaveGameDisplay.new(saves[i], i+1)
|
var new_button := SaveGameDisplay.new(saves[i], i+1)
|
||||||
scroll_container.add_child(new_button)
|
save_box.add_child(new_button)
|
||||||
save_buttons.append(new_button)
|
save_buttons.append(new_button)
|
||||||
new_button.pressed.connect(func(): _on_game_picked(i))
|
new_button.pressed.connect(func(): _on_game_picked(i))
|
||||||
|
|
||||||
|
|
@ -68,8 +79,11 @@ func _on_game_picked(id: int):
|
||||||
|
|
||||||
# This function is called when the user us supposed to choose a slot to load or create a new game.
|
# This function is called when the user us supposed to choose a slot to load or create a new game.
|
||||||
func pick_save_slot(create_new_game: bool):
|
func pick_save_slot(create_new_game: bool):
|
||||||
State.take_stage(self)
|
if saves.size() == 1:
|
||||||
self.override_save_slot = create_new_game
|
picked.emit(saves[0])
|
||||||
|
else:
|
||||||
|
State.take_stage(self)
|
||||||
|
self.override_save_slot = create_new_game
|
||||||
|
|
||||||
func get_most_recent_save() -> SaveGame:
|
func get_most_recent_save() -> SaveGame:
|
||||||
var most_recent_time := 0.0
|
var most_recent_time := 0.0
|
||||||
|
|
@ -80,3 +94,10 @@ func get_most_recent_save() -> SaveGame:
|
||||||
most_recent_time = saves[i].last_saved
|
most_recent_time = saves[i].last_saved
|
||||||
|
|
||||||
return saves[most_recent_index] if most_recent_time > 0 else SaveGame.new()
|
return saves[most_recent_index] if most_recent_time > 0 else SaveGame.new()
|
||||||
|
|
||||||
|
func has_existing_saves() -> bool:
|
||||||
|
return saves.size() > 1
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
State.leave_stage(self)
|
||||||
|
|
|
||||||
17
src/main.gd
17
src/main.gd
|
|
@ -38,8 +38,8 @@ var currently_loading_room: String = "":
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
currently_loading_room = youth_room_path
|
currently_loading_room = get_room_path_from_id(main_menu.save_game_handle.get_most_recent_save().current_room)
|
||||||
|
main_menu.start_game.connect(load_save)
|
||||||
get_tree().tree_process_mode_changed.connect(pause_mode_changed)
|
get_tree().tree_process_mode_changed.connect(pause_mode_changed)
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
|
|
@ -52,10 +52,6 @@ func _process(_delta: float) -> void:
|
||||||
currently_loading_room = ""
|
currently_loading_room = ""
|
||||||
room_loaded.emit()
|
room_loaded.emit()
|
||||||
|
|
||||||
if Input.is_action_just_pressed("reset_demo") and (OS.has_feature("demo") or true):
|
|
||||||
State.stage_list = [self]
|
|
||||||
_return_to_menu()
|
|
||||||
$"Messe-Menue".show()
|
|
||||||
if Input.is_action_just_pressed("ui_menu") and in_game:
|
if Input.is_action_just_pressed("ui_menu") and in_game:
|
||||||
toggle_pause_menu()
|
toggle_pause_menu()
|
||||||
|
|
||||||
|
|
@ -94,10 +90,10 @@ func _return_to_menu():
|
||||||
|
|
||||||
func load_save(save: SaveGame):
|
func load_save(save: SaveGame):
|
||||||
|
|
||||||
#if currently_loading_room != "":
|
if currently_loading_room != "":
|
||||||
# await(room_loaded)
|
await(room_loaded)
|
||||||
|
|
||||||
if save.current_room != current_room_id:
|
if get_room_path_from_id(save.current_room) != get_room_path_from_id(current_room_id):
|
||||||
# TODO Prevent race condition from appearing when save is loaded while room is still loading.
|
# TODO Prevent race condition from appearing when save is loaded while room is still loading.
|
||||||
currently_loading_room = get_room_path_from_id(save.current_room)
|
currently_loading_room = get_room_path_from_id(save.current_room)
|
||||||
await(room_loaded)
|
await(room_loaded)
|
||||||
|
|
@ -106,6 +102,7 @@ func load_save(save: SaveGame):
|
||||||
|
|
||||||
State.active_save_game = save
|
State.active_save_game = save
|
||||||
in_game = true
|
in_game = true
|
||||||
|
current_room.start_room()
|
||||||
|
|
||||||
func _on_ready_to_unload():
|
func _on_ready_to_unload():
|
||||||
if get_child(0) is Node3D:
|
if get_child(0) is Node3D:
|
||||||
|
|
@ -113,7 +110,7 @@ func _on_ready_to_unload():
|
||||||
|
|
||||||
func get_room_path_from_id(id: State.rooms) -> String:
|
func get_room_path_from_id(id: State.rooms) -> String:
|
||||||
match id:
|
match id:
|
||||||
State.rooms.YOUTH, State.rooms.MENU, State.rooms.DRAVEN:
|
State.rooms.YOUTH, State.rooms.NULL:
|
||||||
return youth_room_path
|
return youth_room_path
|
||||||
State.rooms.TRANSITION:
|
State.rooms.TRANSITION:
|
||||||
return transition_room_path
|
return transition_room_path
|
||||||
|
|
|
||||||
|
|
@ -294,8 +294,7 @@ func queue_for_stage(target: Object, index: int = 1):
|
||||||
#region play state
|
#region play state
|
||||||
|
|
||||||
enum rooms {
|
enum rooms {
|
||||||
MENU,
|
NULL,
|
||||||
DRAVEN,
|
|
||||||
YOUTH,
|
YOUTH,
|
||||||
TRANSITION,
|
TRANSITION,
|
||||||
ADULTHOOD,
|
ADULTHOOD,
|
||||||
|
|
@ -317,4 +316,4 @@ enum sequences {
|
||||||
BURNOUT
|
BURNOUT
|
||||||
}
|
}
|
||||||
|
|
||||||
var current_room = rooms.MENU
|
var current_room = rooms.NULL
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue