frame-of-mind/src/logic-scenes/board/card-board.gd

636 lines
22 KiB
GDScript3
Raw Normal View History

2024-10-06 09:31:47 +00:00
class_name CardBoard extends PanelContainer
enum {NAVIGATE, ASSIGN, DRAG}
2025-03-31 19:31:09 +00:00
enum Error {
OK,
OUT_OF_BOUNDS,
ILLEGAL_STATE,
MISSING
}
2023-11-01 22:19:47 +00:00
var focus_stickies:bool = true:
2024-09-15 09:30:31 +00:00
set(stickies):
if not is_node_ready(): return
2024-09-15 09:30:31 +00:00
if stickies and sticky_note_container.get_child_count() == 0: return
2025-01-31 02:22:07 +00:00
# this messes things up if called unneeded.
if focus_stickies != stickies:
focus_stickies = stickies
if not current_context == ASSIGN:
if stickies:
current_sticky_note_id = current_sticky_note_id
else:
current_dropzone_id = current_dropzone_id
2023-07-02 13:10:33 +00:00
var has_stage = false:
2024-09-15 09:30:31 +00:00
set(focus):
if focus:
has_stage = true
get_tree().call_group("interactables", "collapse")
current_dropzone_id = 0
current_sticky_note_id = 0
focus_stickies = true
2024-09-15 09:30:31 +00:00
else:
has_stage = false
if is_node_ready():
if focus:
process_mode = Node.PROCESS_MODE_INHERIT
else:
process_mode = Node.PROCESS_MODE_DISABLED
2025-01-31 02:22:07 +00:00
for sticky in dropzone.get_children():
if sticky is StickyNote:
sticky.is_dragged = false
2024-09-15 09:30:31 +00:00
visible = has_stage
2023-07-11 13:04:46 +00:00
@onready var dropzone = $HBoxContainer/dropzone
2023-08-01 08:59:24 +00:00
var dropzone_size: Vector2
@export var dropzone_padding:int = 100
2023-10-12 16:25:21 +00:00
@onready var sticky_note_container = $HBoxContainer/ScrollContainer/VBoxContainer
@onready var current_context:int = NAVIGATE:
2024-09-15 09:30:31 +00:00
set(context):
if current_context == ASSIGN and !context == ASSIGN:
sticky_note_container.get_child(current_sticky_note_id).clear_if_empty()
#match context:
# NAVIGATE:
# _return_sticky_notes_to_panels()
# DRAG:
# pass
# ASSIGN:
# pass
current_context = context
2023-07-17 22:15:04 +00:00
@onready var instructions = $instructions_panel/HBoxContainer/cards_remaining
2025-03-31 19:31:09 +00:00
@onready var timer: Timer = $Timer
2023-07-17 22:15:04 +00:00
var mementos_collected: int = 0:
2024-09-15 09:30:31 +00:00
set(mementos):
mementos_collected = mementos
match mementos:
1:
instructions.text = "There are three Mementos left to find."
2:
instructions.text = "You have collected half of the mementos."
3:
instructions.text = "Find the last Memento to complete the Board."
4:
instructions.text = "Combine cards to order your thoughts."
2023-10-12 16:25:21 +00:00
@onready var currently_active_node: Area2D = null:
2024-09-15 09:30:31 +00:00
set(new_node):
2025-01-31 02:22:07 +00:00
# this makes sure no accidental context switches can happen while a card is being dragged.
2025-02-24 15:14:08 +00:00
if not (current_context == DRAG):
2025-01-31 02:22:07 +00:00
if not currently_active_node == null:
currently_active_node.highlighted = false
currently_active_node = new_node
if not currently_active_node == null:
currently_active_node.highlighted = true
2023-09-23 14:19:58 +00:00
@onready var current_dropzone_id: int = 0:
2024-09-15 09:30:31 +00:00
set(new_id):
if is_node_ready():
if new_id > dropzone.get_child_count() - 1: current_dropzone_id = 0
elif new_id < 0: current_dropzone_id = dropzone.get_child_count() - 1
else: current_dropzone_id = new_id
if current_context == ASSIGN and not focus_stickies:
while not dropzone.get_child(current_dropzone_id) is Card:
current_dropzone_id = (current_dropzone_id + (1 if not new_id == -1 else -1)) % dropzone.get_child_count()
dropzone.get_child(current_dropzone_id).preview_sticky_note(currently_active_node)
elif not focus_stickies:
currently_active_node = dropzone.get_child(current_dropzone_id)
2024-09-15 09:30:31 +00:00
2023-10-12 16:25:21 +00:00
@onready var current_sticky_note_id: int = 0:
2024-09-15 09:30:31 +00:00
set(new_id):
if is_node_ready():
if sticky_note_container.get_child_count() <= 1: return
elif new_id > sticky_note_container.get_child_count() - 1: current_sticky_note_id = 0
elif new_id < 0: current_sticky_note_id = sticky_note_container.get_child_count() - 1
else: current_sticky_note_id = new_id
if current_context == ASSIGN:
_return_sticky_notes_to_panels()
currently_active_node.preview_sticky_note(sticky_note_container.get_child(current_sticky_note_id).attached_sticky_note)
2025-02-24 15:14:08 +00:00
else:
if sticky_note_container.get_child(current_sticky_note_id).get_child_count() == 1:
currently_active_node = sticky_note_container.get_child(current_sticky_note_id).get_child(0)
else:
for i in range(sticky_note_container.get_child_count() - 1):
if sticky_note_container.get_child(i).get_child_count() == 1:
currently_active_node = sticky_note_container.get_child(i).get_child(0)
2023-07-02 13:10:33 +00:00
2025-03-31 19:31:09 +00:00
var last_save_dict: Dictionary
var text_recovery: Dictionary
signal board_completed
# Called when the node enters the scene tree for the first time.
func _ready():
2025-02-24 15:14:08 +00:00
var size_reference = StickyNotePanel.new()
2024-09-15 09:30:31 +00:00
2025-02-24 15:14:08 +00:00
dropzone_size = get_viewport_rect().size - Vector2(dropzone_padding + size_reference.minimum_size.x, dropzone_padding)
2024-09-15 09:30:31 +00:00
if get_parent() == get_tree().root:
populate_board(["c_void", 'c_gifted', "p_wet", "p_joy"])
populate_board(["c_jui_jutsu", 'c_hit', "p_girly", "p_vent"])
populate_board(["c_comic_heroes", 'c_teasing', "p_agent_q", "p_good_intended"])
populate_board(["c_out_of_world", 'c_confusion', "p_outer_conflict", "p_unique"])
2023-09-23 14:19:58 +00:00
2024-09-15 09:30:31 +00:00
has_stage = has_stage
2025-02-24 15:14:08 +00:00
get_viewport().gui_focus_changed.connect(reclaim_lost_focus)
2025-03-25 21:34:13 +00:00
#FIXME properly implement board recovery
#timer.timeout.connect(validate_board)
#timer.start()
2025-03-31 19:31:09 +00:00
#await get_tree().process_frame
#last_save_dict = get_save_dict()
2025-02-24 15:14:08 +00:00
2025-06-03 21:18:34 +00:00
func reclaim_lost_focus(_thief):
2025-02-24 15:14:08 +00:00
if has_stage:
grab_focus()
2023-09-23 14:19:58 +00:00
#func _process(delta):
2025-05-21 17:42:45 +00:00
# # drops dragged area when Mouse is no longer pressed.
# if has_stage and !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and current_context == DRAG:
# currently_active_node.is_dragged = false
2023-07-02 13:10:33 +00:00
## Will be used later to spawn Cards and Post-Its and remember them in the dictionary
func populate_board(card_names: Array[StringName]):
2024-09-15 09:30:31 +00:00
mementos_collected += 1
var all_new:Dictionary = HardCards.get_cards_by_name_array(card_names)
2024-09-15 09:30:31 +00:00
# spawning the cards and adding them to the dictionary
for new_card: Card in all_new["cards"]:
add_card(new_card, false)
# marking the first card as random picks
new_card.picked_random = new_card.name == card_names[1]
for new_sticky_note: StickyNote in all_new["sticky_notes"]: # spawning a sticky note
add_sticky_note(new_sticky_note, false)
# marking the first sticky as random picks
new_sticky_note.picked_random = new_sticky_note.name == card_names[3]
2024-09-15 09:30:31 +00:00
#currently_active_node = area_dict["dropzone_content"][0] # set first Card as currently selected node by default
currently_active_node = dropzone.get_child(0)
2023-11-01 22:19:47 +00:00
func add_card(card: Card, reparent:bool = true):
if reparent:
card.reparent(self)
else:
add_child(card)
2024-09-15 09:30:31 +00:00
card.position = Vector2(randi_range(dropzone_padding, dropzone_size.x), randi_range(dropzone_padding, dropzone_size.y))
insert_area(dropzone, card)
card.set_owner(self)
card.is_dragable = true
func add_sticky_note(sticky: StickyNote, reparent:bool = true):
2025-02-24 15:14:08 +00:00
var new_panel = StickyNotePanel.new()
sticky_note_container.add_child(new_panel, true, Node.INTERNAL_MODE_DISABLED)
2025-02-24 15:14:08 +00:00
#WARNING this for some reason would break the tweens
2024-09-15 09:30:31 +00:00
new_panel.set_owner(self)
2025-02-24 15:14:08 +00:00
sticky.current_handle = self
new_panel.attatch_sticky_note(sticky, self, false, reparent)
2024-09-15 09:30:31 +00:00
# Checks if a Node is currently inside the dropzone
func is_in_dropzone(to_check: Node) -> bool:
2024-09-15 09:30:31 +00:00
return dropzone.get_rect().has_point(to_check.global_position)
2025-01-31 02:22:07 +00:00
# Called by notes when a mouse event needs handling
func handle_mouse_button(input: InputEventMouseButton, to_handle = currently_active_node):
# Makes sure that only the same area is dragged.
2024-09-15 09:30:31 +00:00
# Otherwise overlapping areas are dragged at the same time.
if current_context == DRAG and to_handle != currently_active_node:
return
2025-01-31 02:22:07 +00:00
if input.button_index == MOUSE_BUTTON_MASK_LEFT and input.pressed:
currently_active_node = to_handle
2024-09-15 09:30:31 +00:00
to_handle.is_dragged = true
if to_handle is StickyNote:
if not to_handle.on_board:
to_handle.reparent(dropzone)
to_handle.on_board = true
2025-02-24 15:14:08 +00:00
to_handle.attached_to = self
2024-09-15 09:30:31 +00:00
current_context = DRAG
2025-05-21 17:42:45 +00:00
2024-09-15 09:30:31 +00:00
# when Drag stops ...
2025-01-31 02:22:07 +00:00
if input.button_index == MOUSE_BUTTON_MASK_LEFT and not input.pressed:
2024-09-15 09:30:31 +00:00
to_handle.is_dragged = false
if to_handle is StickyNote:
if is_in_dropzone(to_handle):
if to_handle.has_overlapping_areas():
for area in to_handle.get_overlapping_areas():
if area is Card:
focus_stickies = false
if area.has_sticky_note_attached():
to_handle = area.exchange_sticky_note_with(to_handle)
to_handle.reparent(dropzone)
to_handle.on_board = true
if sticky_note_container.get_child_count() > 0:
sticky_note_container.get_child(current_sticky_note_id).attached_sticky_note = to_handle
to_handle.attached_to = sticky_note_container.get_child(current_sticky_note_id)
else:
var new_panel = StickyNotePanel.new()
sticky_note_container.add_child(new_panel, true, Node.INTERNAL_MODE_DISABLED)
new_panel.owner = self
new_panel.attatch_sticky_note(to_handle, self, false)
current_sticky_note_id = 0
2024-09-15 09:30:31 +00:00
to_handle.reset_drag()
current_context = NAVIGATE
_return_sticky_notes_to_panels()
2024-09-15 09:30:31 +00:00
return
else:
area.attach_sticky_note(to_handle)
to_handle.z_index = 0
2025-03-31 19:31:09 +00:00
if sticky_note_container.get_child_count() > 0:
sticky_note_container.get_child(current_sticky_note_id).clear_if_empty()
2024-09-15 09:30:31 +00:00
current_context = NAVIGATE
2025-05-30 14:10:44 +00:00
check_board_comnpletion()
2024-09-15 09:30:31 +00:00
return
else:
2025-02-24 15:14:08 +00:00
var i: int = 0
for panel: StickyNotePanel in sticky_note_container.get_children():
i += 1
if panel.is_empty:
if panel.get_global_rect().intersects(Rect2(to_handle.global_position - Vector2(to_handle.diameter/2, 10), Vector2(to_handle.diameter/2, 10))):
panel.attatch_sticky_note(to_handle, self)
elif panel.is_gapped or i == sticky_note_container.get_child_count():
2025-02-24 15:14:08 +00:00
panel.collapse_gap()
var new_panel = StickyNotePanel.new()
sticky_note_container.add_child(new_panel)
sticky_note_container.move_child(new_panel, i)
new_panel.attatch_sticky_note(to_handle, self)
new_panel.owner = self
panel.clear_if_empty()
2024-09-15 09:30:31 +00:00
_return_sticky_notes_to_panels()
2025-02-24 15:14:08 +00:00
current_context = NAVIGATE
2024-09-15 09:30:31 +00:00
return
## Dropping Cards and Sticky Notes not causing a return condition above.
2025-02-24 15:14:08 +00:00
if not (to_handle is StickyNote and to_handle.is_sticky_note_attached()):
2025-03-31 19:31:09 +00:00
if to_handle.get_parent() is Card:
insert_area(to_handle.get_parent().remove_sticky_note(), to_handle)
else:
insert_area(dropzone, to_handle)
2024-09-15 09:30:31 +00:00
current_context = NAVIGATE
focus_stickies = false
current_dropzone_id = dropzone.get_children().find(to_handle)
if to_handle is StickyNote:
to_handle.rotation = to_handle.base_rotation
to_handle.scale = to_handle.base_scale
2023-11-01 22:19:47 +00:00
2024-09-15 09:30:31 +00:00
if input.is_action_pressed("mouse_right") and current_context == DRAG:
to_handle.reset_drag()
2025-01-31 02:22:07 +00:00
2023-10-12 16:25:21 +00:00
func _return_sticky_notes_to_panels():
return #FIXME this is an early return to prevent race conditions. Check if it is save to be removed.
2025-02-24 15:14:08 +00:00
for panel:StickyNotePanel in sticky_note_container.get_children():
2024-09-15 09:30:31 +00:00
panel.reclaim_sticky_note()
for node in dropzone.get_children():
if node is StickyNote:
node.is_dragable = true
2025-05-30 14:10:44 +00:00
var board_was_completed: bool = false
func check_board_comnpletion():
if is_board_complete():
for child:StickyNotePanel in sticky_note_container.get_children():
child.clear_if_empty()
if not board_was_completed:
board_was_completed = true
board_completed.emit()
if board_was_completed:
give_lore_feedback()
func is_board_complete():
2024-09-15 09:30:31 +00:00
if mementos_collected == 4:
for card in dropzone.get_children():
if card is Card:
if not card.has_sticky_note_attached():
return false
return true
return false
2023-08-30 09:07:22 +00:00
2025-05-30 14:10:44 +00:00
var unfitting: bool = false
var incomplete: bool = false
var complete: bool = false
func give_lore_feedback():
var fitting_card_count: int = 0
var total_card_count: int = 0
for child in dropzone.get_children():
if child is Card:
if child.has_sticky_note_attached():
fitting_card_count += int(child.card_id == child.get_attached_sticky_note().parent_id)
total_card_count += 1
if float(fitting_card_count) / float(total_card_count) < 0.2:
instructions.text = "You can move on, but you may not have understood Lisa."
if not unfitting:
2025-07-21 12:33:04 +00:00
if State.speech_language == 2:
$AnimationPlayer.play("unfitting_de")
else:
$AnimationPlayer.play("unfitting")
2025-05-30 14:10:44 +00:00
unfitting = true
#FIXME: check if this logic (after the "or") is still needed.
elif fitting_card_count != total_card_count or (total_card_count != dropzone.get_child_count() and sticky_note_container.get_child_count() != 0):
2025-05-30 14:10:44 +00:00
instructions.text = TranslationServer.translate("You may leave the room, but Lisa only agrees with %d of the %d connections.") % [fitting_card_count, total_card_count]
if not incomplete:
2025-07-21 12:33:04 +00:00
if State.speech_language == 2:
$AnimationPlayer.play("incomplete_de")
else:
$AnimationPlayer.play("incomplete")
2025-05-30 14:10:44 +00:00
incomplete = true
else:
instructions.text = "Lisa would like you to leave her room and move on."
if not complete:
2025-07-21 12:33:04 +00:00
if State.speech_language == 2:
$AnimationPlayer.play("complete_de")
else:
$AnimationPlayer.play("complete")
2025-05-30 14:10:44 +00:00
complete = true
2023-08-30 09:07:22 +00:00
func is_board_lore() -> bool:
2024-09-15 09:30:31 +00:00
for card in dropzone.get_children():
if card is Card:
if card.has_sticky_note_attached():
if not card.current_sticky_note.sticky_id.contains(card.card_id): return false
2024-09-15 09:30:31 +00:00
return true
2023-07-02 13:10:33 +00:00
# Mark area that was hovered over as currently selected
func handle_hover(to_handle: Area2D):
2024-09-15 09:30:31 +00:00
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): return
currently_active_node = to_handle
if is_in_dropzone(to_handle) or to_handle is Card:
if not (to_handle is StickyNote and !to_handle.on_board):
current_dropzone_id = dropzone.get_children().find(to_handle)
focus_stickies = false
else:
current_sticky_note_id = sticky_note_container.get_children().find(to_handle.attached_to)
focus_stickies = true
2023-09-23 14:19:58 +00:00
# Adds a child at the correct child indext in an area
func insert_area(parent: Control, node: Area2D):
2024-09-15 09:30:31 +00:00
var children:Array = parent.get_children()
var i = 0
if not node in parent.get_children():
node.reparent(parent)
if node is StickyNote:
node.on_board = true
node.owner = self
if children.size() > 0:
children.erase(node)
while children[i].global_position.y < node.global_position.y and i+1 < children.size():
i+=1
parent.move_child(node, i)
2025-03-31 19:31:09 +00:00
if node is StickyNote:
node.attached_to = self
node.is_dragable = true
2024-09-15 09:30:31 +00:00
2023-07-02 13:10:33 +00:00
# Takes the inputs for control inputs
func _input(event):
2024-09-15 09:30:31 +00:00
2025-01-31 02:22:07 +00:00
if not has_stage or not is_instance_valid(currently_active_node): return
if event.is_action_pressed("ui_cancel"):
State.leave_stage(self)
get_viewport().set_input_as_handled()
2025-01-31 02:22:07 +00:00
2025-05-21 17:42:45 +00:00
if event is InputEventMouse:
# makes sure to pass release events so notes do not get attached to the mouse while the cursor leaves the area.
if event is InputEventMouseButton and current_context == DRAG:
if event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
handle_mouse_button(event)
get_viewport().set_input_as_handled()
else:
return
2025-02-24 15:14:08 +00:00
if current_context != DRAG:
2024-09-15 09:30:31 +00:00
if event.is_action_pressed("ui_up"):
if focus_stickies:
current_sticky_note_id -= 1
else:
current_dropzone_id -= 1
get_viewport().set_input_as_handled()
2024-09-15 09:30:31 +00:00
elif event.is_action_pressed("ui_down"): # down to select an element beneath
if focus_stickies:
current_sticky_note_id += 1
else:
current_dropzone_id += 1
get_viewport().set_input_as_handled()
2024-09-15 09:30:31 +00:00
elif event.is_action_pressed("ui_right"): # left to switch context to the left
if not focus_stickies:
if current_context == NAVIGATE:
focus_stickies = true
elif current_context == ASSIGN:
current_context = NAVIGATE
get_viewport().set_input_as_handled()
2024-09-15 09:30:31 +00:00
elif event.is_action_pressed("ui_left"): # right to switch context to the right
if focus_stickies:
if current_context == NAVIGATE:
focus_stickies = false
elif current_context == ASSIGN:
current_context = NAVIGATE
get_viewport().set_input_as_handled()
2024-09-15 09:30:31 +00:00
elif event.is_action_pressed("ui_accept"): # select the selected note it
if dropzone.get_child(current_dropzone_id) is Card:
var card:Card = dropzone.get_child(current_dropzone_id)
if current_context == ASSIGN: # to assign it to a card
if card.has_sticky_note_attached():
currently_active_node = card.exchange_sticky_note_with(currently_active_node)
current_dropzone_id = find_first_free_card()
else:
card.attach_sticky_note(sticky_note_container.get_child(current_sticky_note_id).attached_sticky_note)
current_context = NAVIGATE
current_sticky_note_id += 1
current_dropzone_id = find_first_free_card()
2025-05-30 14:10:44 +00:00
check_board_comnpletion()
2024-09-15 09:30:31 +00:00
else:
if !focus_stickies and card.has_sticky_note_attached():
currently_active_node = card.remove_sticky_note()
add_sticky_note(currently_active_node)
current_dropzone_id = -1
else: current_dropzone_id = find_first_free_card()
current_context = ASSIGN
focus_stickies = !focus_stickies
if focus_stickies:
current_sticky_note_id = current_sticky_note_id
else:
current_dropzone_id = current_dropzone_id
elif dropzone.get_child(current_dropzone_id) is StickyNote:
if currently_active_node is StickyNote:
currently_active_node = dropzone.get_child(current_dropzone_id)
focus_stickies = false
current_context = ASSIGN
current_dropzone_id += 1
currently_active_node.is_dragable = false
currently_active_node.z_index = 1
get_viewport().set_input_as_handled()
2023-07-02 13:10:33 +00:00
2023-10-12 16:25:21 +00:00
# move the note it so it floats next to the card where it should be attached
func _select_card_for_assigning(sticky_note: Area2D, card: Area2D):
2024-09-15 09:30:31 +00:00
sticky_note.tween_transform_to(card.get_child(3).global_position)
func on_scene_skipped(i: int):
2024-09-15 09:30:31 +00:00
mementos_collected += i
func claim_focus():
2024-09-15 09:30:31 +00:00
State.pass_stage_to(self)
func find_first_free_card() -> int:
2024-09-15 09:30:31 +00:00
for i in range(dropzone.get_child_count()):
# start searching at the current location, use modulo to avoid getting out of array bounds
if !dropzone.get_child((i+current_dropzone_id)%dropzone.get_child_count()).has_sticky_note_attached():
return (i+current_dropzone_id)%dropzone.get_child_count()
return -1
2023-11-01 22:19:47 +00:00
func on_sticky_panel_cleared():
2024-09-15 09:30:31 +00:00
if current_sticky_note_id == sticky_note_container.get_child_count() - 1:
current_sticky_note_id -= 1
func get_save_dict() -> Dictionary:
var cards: Dictionary = {}
var stickies: Dictionary = {}
var randoms: Array[StringName]
for child in dropzone.get_children():
if child is Card:
2025-03-25 21:34:13 +00:00
# Save position of Card.
cards[child.name] = child.transform.origin
if child.picked_random:
2025-06-03 21:18:34 +00:00
randoms.append(child.name)
2025-03-25 21:34:13 +00:00
if child.has_sticky_note_attached():
2025-03-25 21:34:13 +00:00
# Saves Card Name as position of it's children.
stickies[child.get_attached_sticky_note().name] = child.name
if child.get_attached_sticky_note().picked_random:
2025-06-03 21:18:34 +00:00
randoms.append(child.get_attached_sticky_note().name)
2025-03-25 21:34:13 +00:00
elif child is StickyNote:
2025-03-25 21:34:13 +00:00
# Save position of StickyNote.
cards[child.name] = child.transform.origin
for child in sticky_note_container.get_children():
2025-02-24 15:14:08 +00:00
if child is StickyNotePanel:
2025-03-25 21:34:13 +00:00
# Saves all collected Stickies that are not on board.
stickies[child.attached_sticky_note.name] = -1
return {
"cards": cards,
"stickies": stickies,
"randoms": randoms
2025-03-25 21:34:13 +00:00
}
2025-03-31 19:31:09 +00:00
func initialise_from_save(savegame: SaveGame):
2025-03-31 19:31:09 +00:00
last_save_dict = savegame.board_state.duplicate()
2024-10-06 09:31:47 +00:00
if savegame.board_state == {}: return
2025-03-31 19:31:09 +00:00
rebuild_from_savedict(savegame.board_state)
func rebuild_from_savedict(board_state:Dictionary):
2025-05-16 23:53:09 +00:00
var cards: Dictionary[StringName, Variant]
if board_state["cards"] != {} :
cards = board_state["cards"]
var stickies: Dictionary[StringName, Variant]
if board_state["stickies"] != {} :
stickies = board_state["stickies"]
var randoms: Array[StringName]
2025-06-03 21:18:34 +00:00
if board_state["randoms"] != [] :
randoms = board_state["randoms"]
2025-05-16 23:53:09 +00:00
if cards == null and stickies == null: return
var card_pile = HardCards.get_cards_by_name_array(cards.keys() + (stickies.keys()))
for card:Card in card_pile["cards"]:
add_card(card, false)
card.transform.origin = cards[card.name]# Replacing position reference with card reference! Needed in next loop.
cards[card.name] = card
2025-03-31 19:31:09 +00:00
text_recovery[card.name] = card.text
card.picked_random == randoms.has( card.card_id )
for sticky:StickyNote in card_pile["sticky_notes"]:
2025-03-31 19:31:09 +00:00
text_recovery[sticky.name] = sticky.text
if stickies[sticky.name] == -1:
add_sticky_note(sticky, false)
2025-03-25 21:34:13 +00:00
elif stickies[sticky.name] is String:
cards[stickies[sticky.name]].attach_sticky_note(sticky)
else:
insert_area(dropzone, sticky)
sticky.transform.origin = stickies[sticky.name]
sticky.picked_random == randoms.has( sticky.card_id )
2025-03-31 19:31:09 +00:00
func validate_board():
2025-04-28 13:46:50 +00:00
return
2025-03-31 19:31:09 +00:00
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:
if not get_viewport_rect().has_point(note.get_global_transform().origin):
return Error.OUT_OF_BOUNDS
if note.attached_to is StickyNotePanel:
if note.position != note.attached_to.ancor_position:
return Error.OUT_OF_BOUNDS
if (note.on_board and not is_in_dropzone(note)):
return Error.ILLEGAL_STATE
if not ((note.attached_to == self and dropzone.get_children().has(note)) or note.attached_to == note.get_parent()) or note.shift_tween != null:
return Error.ILLEGAL_STATE
return Error.OK
func validate_card(card: Card) -> CardBoard.Error:
if not is_in_dropzone(card):
return Error.OUT_OF_BOUNDS
if card.get_attached_sticky_note() != card.current_sticky_note:
#push_error("Card %s claims to have %s as current sticky note but has %s attached." % [card.name, card.current_sticky_note, card.get_attached_sticky_note()])
return Error.ILLEGAL_STATE
if not card.owner == self:
return Error.ILLEGAL_STATE
return CardBoard.Error.OK