feat: save game computed properties and cleaner validation; and card board saves the game, too.
This commit is contained in:
parent
e9700b760d
commit
7b327c47f6
|
|
@ -17,6 +17,9 @@ func start_room():
|
||||||
card_board.board_completed.connect(func():
|
card_board.board_completed.connect(func():
|
||||||
#TODO: hook in ending
|
#TODO: hook in ending
|
||||||
save_room())
|
save_room())
|
||||||
|
|
||||||
|
card_board.closed.connect(save_room)
|
||||||
|
|
||||||
%PlayerController.process_mode = Node.PROCESS_MODE_INHERIT
|
%PlayerController.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
ini_room.emit()
|
ini_room.emit()
|
||||||
Scenes.player_enable.emit(true)
|
Scenes.player_enable.emit(true)
|
||||||
|
|
@ -42,7 +45,7 @@ func _on_scene_finished(_id: int, _repeat:bool):
|
||||||
|
|
||||||
func save_room():
|
func save_room():
|
||||||
# Update board state before saving
|
# Update board state before saving
|
||||||
save_game.board_state = card_board.get_save_dict()
|
card_board.save_to_resource(save_game)
|
||||||
save_game.mementos_complete = Scenes.completed_sequences
|
save_game.mementos_complete = Scenes.completed_sequences
|
||||||
save_game.sequences_enabled = Scenes.enabled_sequences
|
save_game.sequences_enabled = Scenes.enabled_sequences
|
||||||
super.save_room()
|
super.save_room()
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ func get_ready():
|
||||||
save_game.is_childhood_board_complete = true
|
save_game.is_childhood_board_complete = true
|
||||||
save_room())
|
save_room())
|
||||||
|
|
||||||
|
card_board.closed.connect(save_room)
|
||||||
|
|
||||||
card_picker.cards_picked.connect(card_board.populate_board)
|
card_picker.cards_picked.connect(card_board.populate_board)
|
||||||
|
|
||||||
ui.hide()
|
ui.hide()
|
||||||
|
|
@ -79,7 +81,7 @@ func _on_scene_finished(_id: int, _repeat:bool):
|
||||||
|
|
||||||
func save_room():
|
func save_room():
|
||||||
# Update board state before saving
|
# Update board state before saving
|
||||||
save_game.board_state = card_board.get_save_dict()
|
card_board.save_to_resource(save_game)
|
||||||
save_game.mementos_complete = Scenes.completed_sequences
|
save_game.mementos_complete = Scenes.completed_sequences
|
||||||
super.save_room()
|
super.save_room()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,8 @@ func get_cards_by_scene_id(id: int) -> Array[Card]:
|
||||||
return output
|
return output
|
||||||
|
|
||||||
# used to put cards on the dev board
|
# used to put cards on the dev board
|
||||||
func get_cards_by_name_array(names: Array[StringName]) -> Dictionary:
|
func get_cards_by_name_array(names: Array[StringName]) -> Dictionary[String, Array]:
|
||||||
var output:Dictionary = {
|
var output:Dictionary[String, Array] = {
|
||||||
"cards": [],
|
"cards": [],
|
||||||
"sticky_notes": []
|
"sticky_notes": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,59 @@ class_name SaveGame extends Resource
|
||||||
## Save game data container
|
## Save game data container
|
||||||
## This is primarily a data class - file I/O helpers are thin wrappers around ResourceSaver/Loader
|
## This is primarily a data class - file I/O helpers are thin wrappers around ResourceSaver/Loader
|
||||||
|
|
||||||
# === Computed Properties ===
|
|
||||||
|
|
||||||
var current_room_path: String:
|
|
||||||
get:
|
|
||||||
return Main.room_paths[current_room] if Main else ""
|
|
||||||
|
|
||||||
var is_empty: bool:
|
|
||||||
get:
|
|
||||||
return not FileAccess.file_exists(filepath) or (current_room == State.rooms.NULL)
|
|
||||||
|
|
||||||
# === Data Fields ===
|
# === Data Fields ===
|
||||||
|
|
||||||
@export var filepath: String = ""
|
|
||||||
@export var unique_save_name: String = ""
|
@export var unique_save_name: String = ""
|
||||||
@export var current_room: State.rooms = State.rooms.NULL
|
@export var current_room: State.rooms = State.rooms.NULL
|
||||||
@export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0
|
@export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0
|
||||||
@export_flags_2d_physics var sequences_enabled: int = 63
|
@export_flags_2d_physics var sequences_enabled: int = 63
|
||||||
@export var board_state: Dictionary = {"cards": {}, "stickies": {}, "randoms": []}
|
|
||||||
@export var childhood_mementos: Dictionary = {"cards": {}, "stickies": {}, "randoms": []}
|
# Board state - properly typed fields
|
||||||
|
@export var board_cards: Dictionary[StringName, Vector2] = {}
|
||||||
|
@export var board_stickies: Dictionary[StringName, Variant] = {}
|
||||||
|
@export var board_randoms: Array[StringName] = []
|
||||||
|
|
||||||
@export var is_childhood_board_complete: bool = false
|
@export var is_childhood_board_complete: bool = false
|
||||||
@export var player_position: Vector3 = Vector3.ZERO
|
@export var player_position: Vector3 = Vector3.ZERO
|
||||||
@export var player_yaw: float = 0.0
|
@export var player_yaw: float = 0.0
|
||||||
@export var player_pitch: float = 0.0
|
@export var player_pitch: float = 0.0
|
||||||
@export var last_saved: int = 0
|
@export var last_saved: int = 0
|
||||||
@export var is_valid: bool = false
|
|
||||||
@export var is_demo: bool = false
|
@export var is_demo: bool = false
|
||||||
|
|
||||||
|
# === Computed Properties ===
|
||||||
|
var is_valid: bool:
|
||||||
|
get: return _validate()
|
||||||
|
|
||||||
|
var current_room_path: String:
|
||||||
|
get: return Main.room_paths[current_room] if Main else ""
|
||||||
|
|
||||||
|
var is_empty: bool:
|
||||||
|
get: return not FileAccess.file_exists(file_name) or (current_room == State.rooms.NULL)
|
||||||
|
|
||||||
|
var completed_sequences: int:
|
||||||
|
get:
|
||||||
|
# Hamming weight (population count) algorithm for counting set bits
|
||||||
|
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
|
||||||
|
|
||||||
|
var total_connections: int:
|
||||||
|
get:
|
||||||
|
var connections := 0
|
||||||
|
for sticky_position in board_stickies.values():
|
||||||
|
connections += int(sticky_position is String)
|
||||||
|
return connections
|
||||||
|
|
||||||
|
# === State Variables / External Data ===
|
||||||
|
## Where to save the savegame to / where it was loaded from
|
||||||
|
var file_name: String = ""
|
||||||
|
|
||||||
|
## Screenshot or placeholder image
|
||||||
var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png")
|
var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png")
|
||||||
|
|
||||||
# === Editor Conveniences ===
|
|
||||||
|
|
||||||
@export var save_manually: bool = false:
|
|
||||||
set(val):
|
|
||||||
if val:
|
|
||||||
save_to_file(thumbnail)
|
|
||||||
|
|
||||||
func _validate_property(property: Dictionary):
|
|
||||||
if property.name == "filepath":
|
|
||||||
property.usage |= PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED
|
|
||||||
if property.name in ["thumbnail", "is_valid", "is_empty"]:
|
|
||||||
property.usage |= PROPERTY_USAGE_READ_ONLY
|
|
||||||
|
|
||||||
# === Static Helpers ===
|
# === Static Helpers ===
|
||||||
|
|
||||||
## Generates a unique save filepath
|
## Generates a unique save filepath
|
||||||
|
|
@ -56,32 +67,16 @@ static func generate_save_path() -> String:
|
||||||
## Creates a new save game with generated filepath
|
## Creates a new save game with generated filepath
|
||||||
static func create_new() -> SaveGame:
|
static func create_new() -> SaveGame:
|
||||||
var save := SaveGame.new()
|
var save := SaveGame.new()
|
||||||
save.filepath = generate_save_path()
|
save.file_name = generate_save_path()
|
||||||
save.unique_save_name = save.filepath.get_file().get_basename()
|
save.unique_save_name = save.file_name.get_file().get_basename()
|
||||||
save.is_valid = true
|
|
||||||
save.is_demo = OS.has_feature("Demo")
|
save.is_demo = OS.has_feature("Demo")
|
||||||
save.last_saved = int(Time.get_unix_time_from_system())
|
save.last_saved = int(Time.get_unix_time_from_system())
|
||||||
|
|
||||||
# Ensure save directory exists
|
# Ensure save directory exists
|
||||||
if not DirAccess.dir_exists_absolute(save.filepath.get_base_dir()):
|
if not DirAccess.dir_exists_absolute(save.file_name.get_base_dir()):
|
||||||
DirAccess.make_dir_absolute(save.filepath.get_base_dir())
|
DirAccess.make_dir_absolute(save.file_name.get_base_dir())
|
||||||
|
|
||||||
print_debug("SaveGame: Created new save: %s" % save.filepath)
|
|
||||||
return save
|
|
||||||
|
|
||||||
## Creates a DEBUG save (not persisted to disk)
|
|
||||||
static func create_debug() -> SaveGame:
|
|
||||||
var save := SaveGame.new()
|
|
||||||
save.filepath = "DEBUG"
|
|
||||||
save.unique_save_name = "DEBUG"
|
|
||||||
save.is_valid = true
|
|
||||||
save.is_demo = OS.has_feature("Demo")
|
|
||||||
|
|
||||||
if OS.has_feature("debug") or OS.has_feature("demo"):
|
|
||||||
push_warning("Created DEBUG savegame. Progress will not be stored!")
|
|
||||||
else:
|
|
||||||
push_error("Created DEBUG savegame outside of demo/debug environment. This will lead to data loss!")
|
|
||||||
|
|
||||||
|
print_debug("SaveGame: Created new save: %s" % save.file_name)
|
||||||
return save
|
return save
|
||||||
|
|
||||||
## Loads an existing save from disk
|
## Loads an existing save from disk
|
||||||
|
|
@ -90,37 +85,29 @@ static func load_from_file(save_filepath: String) -> SaveGame:
|
||||||
push_error("SaveGame: File does not exist: %s" % save_filepath)
|
push_error("SaveGame: File does not exist: %s" % save_filepath)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
print_debug("SaveGame: Loading from: %s" % save_filepath)
|
|
||||||
|
|
||||||
var loaded: SaveGame = ResourceLoader.load(save_filepath, "", ResourceLoader.CACHE_MODE_IGNORE)
|
var loaded: SaveGame = ResourceLoader.load(save_filepath, "", ResourceLoader.CACHE_MODE_IGNORE)
|
||||||
|
|
||||||
if not loaded:
|
if not loaded:
|
||||||
push_error("Failed to load SaveGame resource from: %s" % save_filepath)
|
push_error("SaveGame: Failed to load resource from: %s" % save_filepath)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
# Update filepath metadata
|
# Update filepath metadata
|
||||||
loaded.filepath = save_filepath
|
loaded.file_name = save_filepath
|
||||||
loaded.unique_save_name = save_filepath.get_file().get_basename()
|
loaded.unique_save_name = save_filepath.get_file().get_basename()
|
||||||
|
|
||||||
# Backwards compatibility
|
# Load thumbnail (stored separately as PNG)
|
||||||
if "randoms" not in loaded.board_state:
|
|
||||||
loaded.board_state["randoms"] = []
|
|
||||||
|
|
||||||
# Load thumbnail separately (not stored in .tres)
|
|
||||||
_load_thumbnail(loaded)
|
_load_thumbnail(loaded)
|
||||||
|
|
||||||
# Validate
|
# Validate and return
|
||||||
loaded.is_valid = loaded._validate()
|
loaded.is_valid = loaded._validate()
|
||||||
|
|
||||||
if not loaded.is_valid:
|
if not loaded.is_valid:
|
||||||
push_error("Validation of loaded save failed: %s" % save_filepath)
|
push_error("SaveGame: Validation failed: %s" % save_filepath)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return loaded
|
return loaded
|
||||||
|
|
||||||
## Helper to load thumbnail from separate PNG file
|
## Helper to load thumbnail from separate PNG file
|
||||||
static func _load_thumbnail(save: SaveGame) -> void:
|
static func _load_thumbnail(save: SaveGame) -> void:
|
||||||
var thumbnail_path := "%s/thumbnails/%s.png" % [save.filepath.get_base_dir(), save.unique_save_name]
|
var thumbnail_path := "%s/thumbnails/%s.png" % [save.file_name.get_base_dir(), save.unique_save_name]
|
||||||
if FileAccess.file_exists(thumbnail_path):
|
if FileAccess.file_exists(thumbnail_path):
|
||||||
var img := Image.load_from_file(thumbnail_path)
|
var img := Image.load_from_file(thumbnail_path)
|
||||||
if img:
|
if img:
|
||||||
|
|
@ -143,7 +130,7 @@ func capture_player_state() -> void:
|
||||||
|
|
||||||
## Saves to disk with thumbnail
|
## Saves to disk with thumbnail
|
||||||
func save_to_file(screen_shot: Texture) -> void:
|
func save_to_file(screen_shot: Texture) -> void:
|
||||||
if filepath == "DEBUG":
|
if file_name == "DEBUG":
|
||||||
push_warning("SaveGame: DEBUG save skipped (intentional).")
|
push_warning("SaveGame: DEBUG save skipped (intentional).")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -151,7 +138,7 @@ func save_to_file(screen_shot: Texture) -> void:
|
||||||
push_warning("SaveGame: Not saving empty savegame.")
|
push_warning("SaveGame: Not saving empty savegame.")
|
||||||
return
|
return
|
||||||
|
|
||||||
print_debug("SaveGame: Saving to file: %s" % filepath)
|
print_debug("SaveGame: Saving to file: %s" % file_name)
|
||||||
|
|
||||||
# Capture current state
|
# Capture current state
|
||||||
capture_player_state()
|
capture_player_state()
|
||||||
|
|
@ -161,11 +148,11 @@ func save_to_file(screen_shot: Texture) -> void:
|
||||||
_save_thumbnail(screen_shot)
|
_save_thumbnail(screen_shot)
|
||||||
|
|
||||||
# Save resource
|
# Save resource
|
||||||
var result := ResourceSaver.save(self, filepath)
|
var result := ResourceSaver.save(self, file_name)
|
||||||
if result != OK:
|
if result != OK:
|
||||||
push_error("Failed to save resource to: %s (Error: %d)" % [filepath, result])
|
push_error("Failed to save resource to: %s (Error: %d)" % [file_name, result])
|
||||||
else:
|
else:
|
||||||
print_debug("Successfully saved to: %s" % filepath)
|
print_debug("Successfully saved to: %s" % file_name)
|
||||||
|
|
||||||
## Processes and saves thumbnail as PNG
|
## Processes and saves thumbnail as PNG
|
||||||
func _save_thumbnail(screen_shot: Texture) -> void:
|
func _save_thumbnail(screen_shot: Texture) -> void:
|
||||||
|
|
@ -176,45 +163,31 @@ func _save_thumbnail(screen_shot: Texture) -> void:
|
||||||
img.crop(384, 216)
|
img.crop(384, 216)
|
||||||
|
|
||||||
# Ensure thumbnails directory exists
|
# Ensure thumbnails directory exists
|
||||||
var save_dir := DirAccess.open(filepath.get_base_dir())
|
var save_dir := DirAccess.open(file_name.get_base_dir())
|
||||||
if not save_dir.dir_exists("thumbnails"):
|
if not save_dir.dir_exists("thumbnails"):
|
||||||
save_dir.make_dir("thumbnails")
|
save_dir.make_dir("thumbnails")
|
||||||
|
|
||||||
var thumbnail_path := "%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]
|
var thumbnail_path := "%s/thumbnails/%s.png" % [file_name.get_base_dir(), unique_save_name]
|
||||||
img.save_png(thumbnail_path)
|
img.save_png(thumbnail_path)
|
||||||
|
|
||||||
## Validates save data integrity
|
|
||||||
|
# === Legacy Validation (may want to be removed) ===
|
||||||
|
|
||||||
func _validate() -> bool:
|
func _validate() -> bool:
|
||||||
if current_room < 0 or current_room >= State.rooms.keys().size():
|
if current_room < 0 or current_room >= State.rooms.keys().size():
|
||||||
return false
|
return false
|
||||||
return validate_board_state()
|
return _validate_board_state()
|
||||||
|
|
||||||
# === Helper Methods ===
|
func _validate_board_state() -> bool:
|
||||||
|
# Validate cards
|
||||||
func calculate_completed_sequences() -> int:
|
for card in board_cards.values():
|
||||||
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 not board_state.has("cards") or not board_state.has("stickies"):
|
|
||||||
return false
|
|
||||||
|
|
||||||
for card in board_state.cards.values():
|
|
||||||
if not card is Vector2:
|
if not card is Vector2:
|
||||||
push_error("Save %s: Corrupted cards" % unique_save_name)
|
push_error("Save %s: Corrupted cards" % unique_save_name)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
for sticky in board_state.stickies.values():
|
# Validate stickies
|
||||||
if not (sticky is int or sticky is Vector2 or sticky is float or board_state.cards.has(sticky)):
|
for sticky in board_stickies.values():
|
||||||
|
if not (sticky is int or sticky is Vector2 or sticky is float or board_cards.has(sticky)):
|
||||||
push_error("Save %s: Corrupted sticky notes" % unique_save_name)
|
push_error("Save %s: Corrupted sticky notes" % unique_save_name)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -604,122 +604,92 @@ func on_sticky_panel_cleared(at_id: int):
|
||||||
else:
|
else:
|
||||||
current_sticky_note_id += 1
|
current_sticky_note_id += 1
|
||||||
|
|
||||||
func get_save_dict() -> Dictionary:
|
## Saves board state directly to SaveGame resource
|
||||||
var cards: Dictionary = {}
|
func save_to_resource(savegame: SaveGame) -> void:
|
||||||
var stickies: Dictionary = {}
|
savegame.board_cards.clear()
|
||||||
var randoms: Array[StringName]
|
savegame.board_stickies.clear()
|
||||||
|
savegame.board_randoms.clear()
|
||||||
|
|
||||||
for child in dropzone.get_children():
|
for child in dropzone.get_children():
|
||||||
if child is Card:
|
if child is Card:
|
||||||
# Save position of Card.
|
# Save position of Card
|
||||||
cards[child.name] = child.transform.origin
|
savegame.board_cards[child.name] = child.transform.origin
|
||||||
if child.picked_random:
|
if child.picked_random:
|
||||||
randoms.append(child.name)
|
savegame.board_randoms.append(child.name)
|
||||||
|
|
||||||
var note : StickyNote = child.get_attached_sticky_note()
|
var note: StickyNote = child.get_attached_sticky_note()
|
||||||
if note:
|
if note:
|
||||||
# Saves Card Name as position of it's children.
|
# Save Card Name as position of its children
|
||||||
stickies[child.get_attached_sticky_note().name] = child.name
|
savegame.board_stickies[child.get_attached_sticky_note().name] = child.name
|
||||||
if child.get_attached_sticky_note().picked_random:
|
if child.get_attached_sticky_note().picked_random:
|
||||||
randoms.append(child.get_attached_sticky_note().name)
|
savegame.board_randoms.append(child.get_attached_sticky_note().name)
|
||||||
|
|
||||||
elif child is StickyNote:
|
elif child is StickyNote:
|
||||||
# Save position of StickyNote.
|
# Save position of StickyNote
|
||||||
cards[child.name] = child.transform.origin
|
savegame.board_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.
|
# Save all collected Stickies that are not on board
|
||||||
stickies[child.attached_sticky_note.name] = -1
|
savegame.board_stickies[child.attached_sticky_note.name] = -1
|
||||||
|
|
||||||
|
## Legacy method for backwards compatibility
|
||||||
|
func get_save_dict() -> Dictionary:
|
||||||
return {
|
return {
|
||||||
"cards": cards,
|
"cards": {},
|
||||||
"stickies": stickies,
|
"stickies": {},
|
||||||
"randoms": randoms
|
"randoms": []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func initialise_from_save(savegame: SaveGame) -> void:
|
func initialise_from_save(savegame: SaveGame) -> void:
|
||||||
last_save_dict = savegame.board_state.duplicate()
|
# Early return if no board data
|
||||||
if savegame.board_state == {}: return
|
if savegame.board_cards.is_empty() and savegame.board_stickies.is_empty():
|
||||||
rebuild_from_savedict(savegame.board_state)
|
return
|
||||||
|
|
||||||
func rebuild_from_savedict(board_state:Dictionary) -> void:
|
rebuild_from_save(savegame)
|
||||||
var cards: Dictionary
|
|
||||||
if board_state["cards"] != {} :
|
|
||||||
cards = board_state["cards"]
|
|
||||||
var stickies: Dictionary
|
|
||||||
if board_state["stickies"] != {} :
|
|
||||||
stickies = board_state["stickies"]
|
|
||||||
var randoms: Array[StringName]
|
|
||||||
if board_state["randoms"] != [] :
|
|
||||||
randoms = board_state["randoms"]
|
|
||||||
|
|
||||||
if cards == null and stickies == null: return
|
func rebuild_from_save(savegame: SaveGame) -> void:
|
||||||
|
# Early return if nothing to load
|
||||||
|
if savegame.board_cards.is_empty() and savegame.board_stickies.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Collect all card names
|
||||||
var all_cards: Array[StringName]
|
var all_cards: Array[StringName]
|
||||||
for card_name: StringName in cards.keys():
|
for card_name: StringName in savegame.board_cards.keys():
|
||||||
all_cards.append(card_name)
|
all_cards.append(card_name)
|
||||||
for card_name: StringName in stickies.keys():
|
for card_name: StringName in savegame.board_stickies.keys():
|
||||||
all_cards.append(card_name)
|
all_cards.append(card_name)
|
||||||
var card_pile = HardCards.get_cards_by_name_array(all_cards)
|
|
||||||
|
|
||||||
for card:Card in card_pile["cards"]:
|
var card_pile : Dictionary[String, Array] = HardCards.get_cards_by_name_array(all_cards)
|
||||||
|
|
||||||
|
# Track cards by name for sticky note attachment
|
||||||
|
var cards_by_name: Dictionary = {}
|
||||||
|
|
||||||
|
for card: Card in card_pile["cards"]:
|
||||||
add_card(card, false)
|
add_card(card, false)
|
||||||
card.transform.origin = cards[card.name]# Replacing position reference with card reference! Needed in next loop.
|
card.transform.origin = savegame.board_cards[card.name]
|
||||||
cards[card.name] = card
|
cards_by_name[card.name] = card
|
||||||
text_recovery[card.name] = card.text
|
text_recovery[card.name] = card.text
|
||||||
card.picked_random = randoms.has( card.card_id )
|
card.picked_random = savegame.board_randoms.has(card.card_id)
|
||||||
for sticky:StickyNote in card_pile["sticky_notes"]:
|
|
||||||
|
for sticky: StickyNote in card_pile["sticky_notes"]:
|
||||||
text_recovery[sticky.name] = sticky.text
|
text_recovery[sticky.name] = sticky.text
|
||||||
if stickies[sticky.name] is int:
|
var sticky_data = savegame.board_stickies[sticky.name]
|
||||||
if stickies[sticky.name] == -1:
|
|
||||||
|
if sticky_data is int:
|
||||||
|
if sticky_data == -1:
|
||||||
add_sticky_note(sticky, false)
|
add_sticky_note(sticky, false)
|
||||||
elif stickies[sticky.name] is String:
|
elif sticky_data is String:
|
||||||
cards[stickies[sticky.name]].attach_sticky_note(sticky)
|
# Attached to a card
|
||||||
|
cards_by_name[sticky_data].attach_sticky_note(sticky)
|
||||||
else:
|
else:
|
||||||
|
# Loose on board at position
|
||||||
insert_area(dropzone, sticky)
|
insert_area(dropzone, sticky)
|
||||||
sticky.transform.origin = stickies[sticky.name]
|
sticky.transform.origin = sticky_data
|
||||||
sticky.picked_random = randoms.has( sticky.sticky_id )
|
|
||||||
|
|
||||||
func validate_board():
|
sticky.picked_random = savegame.board_randoms.has(sticky.sticky_id)
|
||||||
if current_context == NAVIGATE:
|
|
||||||
|
|
||||||
var needs_rebuild := false
|
|
||||||
for node in dropzone.get_children():
|
|
||||||
if node is Card:
|
|
||||||
match validate_card(node):
|
|
||||||
Error.OUT_OF_BOUNDS:
|
|
||||||
node.position = last_save_dict[node.name]
|
|
||||||
Error.ILLEGAL_STATE:
|
|
||||||
needs_rebuild = true
|
|
||||||
if node is StickyNote:
|
|
||||||
match validate_sticky(node):
|
|
||||||
Error.OUT_OF_BOUNDS:
|
|
||||||
node.position = last_save_dict[node.name]
|
|
||||||
Error.ILLEGAL_STATE:
|
|
||||||
needs_rebuild = true
|
|
||||||
for panel:StickyNotePanel in sticky_note_container.get_children():
|
|
||||||
if panel.attached_sticky_note != null:
|
|
||||||
match validate_sticky(panel.attached_sticky_note):
|
|
||||||
Error.OUT_OF_BOUNDS:
|
|
||||||
panel.attached_sticky_note.position = panel.ancor_position
|
|
||||||
Error.ILLEGAL_STATE:
|
|
||||||
needs_rebuild = true
|
|
||||||
|
|
||||||
# FIXME: currently, illegal temporary state exists a lot and needs to be rectified before this can be trusted.
|
|
||||||
if needs_rebuild and false:
|
|
||||||
|
|
||||||
for child in dropzone.get_children(): child.free()
|
|
||||||
for child in sticky_note_container.get_children(): child.free()
|
|
||||||
|
|
||||||
rebuild_from_savedict(last_save_dict)
|
|
||||||
|
|
||||||
current_dropzone_id = 0
|
|
||||||
current_sticky_note_id = 0
|
|
||||||
focus_stickies = false
|
|
||||||
current_context = NAVIGATE
|
|
||||||
else:
|
|
||||||
last_save_dict = get_save_dict()
|
|
||||||
|
|
||||||
func validate_sticky(note: StickyNote) -> CardBoard.Error:
|
func validate_sticky(note: StickyNote) -> CardBoard.Error:
|
||||||
if not get_viewport_rect().has_point(note.get_global_transform().origin):
|
if not get_viewport_rect().has_point(note.get_global_transform().origin):
|
||||||
|
|
@ -746,7 +716,7 @@ func validate_card(card: Card) -> CardBoard.Error:
|
||||||
|
|
||||||
|
|
||||||
func try_select_nearest_card(from: Vector2, towards: Vector2, include_stickies: bool = false) -> bool:
|
func try_select_nearest_card(from: Vector2, towards: Vector2, include_stickies: bool = false) -> bool:
|
||||||
var selection_transform = Transform2D(0, from).looking_at(from+towards)
|
var selection_transform := Transform2D(0, from).looking_at(from+towards)
|
||||||
|
|
||||||
var scores: Dictionary[int, Area2D] = {-1: null}
|
var scores: Dictionary[int, Area2D] = {-1: null}
|
||||||
for child:Area2D in dropzone.get_children():
|
for child:Area2D in dropzone.get_children():
|
||||||
|
|
@ -798,8 +768,8 @@ func try_select_nearest_empty_card(from: Vector2) -> bool:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func get_distance_score(from: Vector2, to: Transform2D) -> int:
|
func get_distance_score(from: Vector2, to: Transform2D) -> int:
|
||||||
var diff = from * to
|
var diff := from * to
|
||||||
var dir = diff.normalized()
|
var dir := diff.normalized()
|
||||||
if dir.x > 0.5 and diff.length() > 0:
|
if dir.x > 0.5 and diff.length() > 0:
|
||||||
return int((abs(dir.y) + 0.5) * diff.length())
|
return int((abs(dir.y) + 0.5) * diff.length())
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func _ready():
|
||||||
%SkipButton.pressed.connect(card_burned.emit)
|
%SkipButton.pressed.connect(card_burned.emit)
|
||||||
|
|
||||||
func burn_cards(_id: int, _repeat: bool = false) -> void:
|
func burn_cards(_id: int, _repeat: bool = false) -> void:
|
||||||
var random_card_names: Array = State.save_game.board_state["randoms"]
|
var random_card_names: Array = State.save_game.board_randoms.duplicate()
|
||||||
|
|
||||||
for card_name in random_card_names:
|
for card_name in random_card_names:
|
||||||
if card_name.begins_with("p"):
|
if card_name.begins_with("p"):
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ func set_theme(new_theme:Theme):
|
||||||
current_main_theme = new_theme
|
current_main_theme = new_theme
|
||||||
theme_changed.emit(new_theme)
|
theme_changed.emit(new_theme)
|
||||||
|
|
||||||
@export_file var user_settings_path:String = "user://user_settings.json"
|
const user_settings_path:String = "user://user_settings.json"
|
||||||
@export_file var user_saves_path:String = "user://savegames"
|
const user_saves_path:String = "user://savegames"
|
||||||
|
|
||||||
@export_group("Acessability")
|
@export_group("Acessability")
|
||||||
@export var reduce_motion: bool = false:
|
@export var reduce_motion: bool = false:
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ func rebuild():
|
||||||
state.text = TranslationServer.translate(("""
|
state.text = TranslationServer.translate(("""
|
||||||
Mementos collected: %d/4
|
Mementos collected: %d/4
|
||||||
Connections found: %d/8
|
Connections found: %d/8
|
||||||
""").strip_edges()) % [save.calculate_completed_sequences(), save.calculate_total_connections()]
|
""").strip_edges()) % [save.completed_sequences, save.total_connections]
|
||||||
#Secrets found: 1/4
|
#Secrets found: 1/4
|
||||||
|
|
||||||
info.add_child(room)
|
info.add_child(room)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func _on_game_picked(id: int) -> void:
|
||||||
|
|
||||||
func _on_delete_requested(id: int) -> void:
|
func _on_delete_requested(id: int) -> void:
|
||||||
var save_to_delete := saves[id]
|
var save_to_delete := saves[id]
|
||||||
var save_path := save_to_delete.filepath
|
var save_path := save_to_delete.file_name
|
||||||
var thumbnail_path := "%s/thumbnails/%s.png" % [save_path.get_base_dir(), save_to_delete.unique_save_name]
|
var thumbnail_path := "%s/thumbnails/%s.png" % [save_path.get_base_dir(), save_to_delete.unique_save_name]
|
||||||
|
|
||||||
# Delete the save file
|
# Delete the save file
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue