class_name CardBoard extends PanelContainer #var area_dict = { # "dropzone_content": [], # "cards": [], # "sticky_notes_in_list": [], # "sticky_note_panels": [] #} enum {NAVIGATE, ASSIGN, DRAG} var focus_stickies:bool = true: set(stickies): if stickies and sticky_note_container.get_child_count() == 0: return # 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 var has_stage = false: set(focus): if focus: has_stage = true get_tree().call_group("interactables", "collapse") else: has_stage = false if is_node_ready(): if focus: process_mode = Node.PROCESS_MODE_INHERIT else: process_mode = Node.PROCESS_MODE_DISABLED for sticky in dropzone.get_children(): if sticky is StickyNote: sticky.is_dragged = false visible = has_stage @onready var dropzone = $HBoxContainer/dropzone var dropzone_size: Vector2 @export var dropzone_padding = 100 @onready var sticky_note_container = $HBoxContainer/ScrollContainer/VBoxContainer @onready var board_of_devs = $"board of devs" @onready var current_context:int = NAVIGATE: 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 @onready var instructions = $instructions_panel/HBoxContainer/cards_remaining var mementos_collected: int = 0: 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." @onready var currently_active_node: Area2D = null: set(new_node): # this makes sure no accidental context switches can happen while a card is being dragged. if not (current_context == DRAG): 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 @onready var current_dropzone_id: int = 0: set(new_id): 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) % 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) @onready var current_sticky_note_id: int = 0: set(new_id): 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) 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) var cache: Array = [] signal board_completed # Called when the node enters the scene tree for the first time. func _ready(): var size_reference = StickyNotePanel.new() dropzone_size = get_viewport_rect().size - Vector2(dropzone_padding + size_reference.minimum_size.x, dropzone_padding) if get_parent() == get_tree().root: populate_board(["c_void", 'c_joy', "p_wet", "p_effort"]) populate_board(["c_fighting", 'c_hit', "p_girly", "p_vent"]) mementos_collected = 2 has_stage = has_stage get_viewport().gui_focus_changed.connect(reclaim_lost_focus) func reclaim_lost_focus(): if has_stage: grab_focus() #func _process(delta): # # drops dragged area when Mouse is no longer pressed. # if has_stage and !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and current_context == DRAGGING: # currently_active_node.is_dragged = false # Will be used later to spawn Cards and Post-Its and remember them in the dictionary func populate_board(card_names: Array[String]): mementos_collected += 1 var all_new:Dictionary = board_of_devs.get_cards_by_name_array(card_names) var new_cards:Array = all_new["cards"] var new_sticky_notes:Array = all_new["sticky_notes"] # spawning the cards and adding them to the dictionary for new_card in all_new["cards"]: add_card(new_card) for new_sticky_note in all_new["sticky_notes"]: # spawning a sticky note add_sticky_note(new_sticky_note) #currently_active_node = area_dict["dropzone_content"][0] # set first Card as currently selected node by default currently_active_node = dropzone.get_child(0) func add_card(card: Card): card.reparent(self) 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): var new_panel = StickyNotePanel.new() sticky_note_container.add_child(new_panel, false, Node.INTERNAL_MODE_DISABLED) #WARNING this for some reason would break the tweens new_panel.set_owner(self) sticky.current_handle = self new_panel.attatch_sticky_note(sticky, self, false) # Checks if a Node is currently inside the dropzone func is_in_dropzone(to_check: Node) -> bool: return dropzone.get_rect().has_point(to_check.global_position) # 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. # Otherwise overlapping areas are dragged at the same time. if current_context == DRAG and to_handle != currently_active_node: return if input.button_index == MOUSE_BUTTON_MASK_LEFT and input.pressed: currently_active_node = to_handle 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 to_handle.attached_to = self current_context = DRAG # when Drag stops ... if input.button_index == MOUSE_BUTTON_MASK_LEFT and not input.pressed: 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 # FIXME: this caused an error when all stickies were attatched ... 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) to_handle.reset_drag() current_context = NAVIGATE return else: area.attach_sticky_note(to_handle) sticky_note_container.get_child(current_sticky_note_id).clear_if_empty() current_context = NAVIGATE if is_board_complete(): emit_signal("board_completed") return else: var i: int = 0 for panel: StickyNotePanel in sticky_note_container.get_children(): i += 1 if panel.is_gapped or i == sticky_note_container.get_child_count(): 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() _return_sticky_notes_to_panels() current_context = NAVIGATE return ## Dropping Cards and Sticky Notes not causing a return condition above. if not (to_handle is StickyNote and to_handle.is_sticky_note_attached()): insert_area(dropzone, to_handle) 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 if input.is_action_pressed("mouse_right") and current_context == DRAG: to_handle.reset_drag() func _return_sticky_notes_to_panels(): for panel:StickyNotePanel in sticky_note_container.get_children(): panel.reclaim_sticky_note() func is_board_complete() -> bool: 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 func is_board_lore() -> bool: for card in dropzone.get_children(): if card.has_sticky_note_attached(): if not card.current_sticky_note.is_in_group(card.name): return false return true # Mark area that was hovered over as currently selected func handle_hover(to_handle: Area2D): 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 # Adds a child at the correct child indext in an area func insert_area(parent: Control, node: Area2D): 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) # Takes the inputs for control inputs func _input(event): if event.is_action_pressed("ui_cancel"): State.leave_stage(self) # Return, if the input is a mouse event (mouse events are handled separately) if not has_stage or not is_instance_valid(currently_active_node): return 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) else: return if current_context != DRAG: if event.is_action_pressed("ui_up"): if focus_stickies: current_sticky_note_id -= 1 else: current_dropzone_id -= 1 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 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 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 elif event.is_action_pressed("ui_accept"): # select the selected note it var card:Card if dropzone.get_child(current_dropzone_id) is 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() if is_board_complete(): emit_signal("board_completed") 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 # 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): sticky_note.tween_transform_to(card.get_child(3).global_position) func on_scene_skipped(i: int): mementos_collected += i func claim_focus(): State.pass_stage_to(self) func find_first_free_card() -> int: 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 func on_sticky_panel_cleared(): 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 = {} for child in dropzone.get_children(): if child is Card: if child.has_sticky_note_attached(): stickies[child.get_attached_sticky_note().name] = child.name cards[child.name] = child.transform.origin elif child is StickyNote: cards[child.name] = child.transform.origin for child in sticky_note_container.get_children(): if child is StickyNotePanel: stickies[child.attached_sticky_note.name] = -1 return { "cards": cards, "stickies": stickies } if cards != {} and stickies != {} else {} func initialise_from_save(savegame: SaveGame): if savegame.board_state == {}: return var cards: Dictionary = savegame.board_state["cards"] var stickies: Dictionary = savegame.board_state["stickies"] var card_pile = board_of_devs.get_cards_by_name_array(cards.keys() + (stickies.keys())) for card:Card in card_pile["cards"]: add_card(card) card.transform.origin = cards[card.name] cards[card.name] = card for sticky:StickyNote in card_pile["sticky_notes"]: if stickies[sticky.name] == -1: add_sticky_note(sticky) if stickies[sticky.name] is String: cards[stickies[sticky.name]].attach_sticky_note(sticky) else: insert_area(dropzone, sticky) sticky.transform.origin = stickies[sticky.name]