extends PanelContainer var area_dict = { "dropzone_content": [], "cards": [], "post_its_in_list": [], "post_it_panels": [] } enum ui_context {DROPZONE, POST_IT_LIST, ASSIGN_POST_IT} var has_stage = false: set(focus): if focus: has_stage = true self.mouse_filter = Control.MOUSE_FILTER_PASS get_tree().call_group("interactables", "collapse") else: has_stage = false self.mouse_filter = Control.MOUSE_FILTER_IGNORE if is_node_ready(): for child in area_dict["dropzone_content"]+area_dict["post_its_in_list"]: if focus: child.process_mode = Node.PROCESS_MODE_INHERIT else: child.process_mode = Node.PROCESS_MODE_DISABLED visible = has_stage @onready var dropzone = $HBoxContainer/dropzone var dropzone_size: Vector2 @export var dropzone_padding = 100 @onready var postit_container = $HBoxContainer/ScrollContainer/VBoxContainer @onready var board_of_devs = $"board of devs" var base_postit_panel: Panel @onready var active_context = ui_context.DROPZONE # 0 = dropzone, 1 = post it list @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." var currently_selected_node: Area2D = null var currently_selected_card_for_assigning: Area2D = null var is_area_dragged: bool = false var currently_dragged_area: Area2D var selected_dropzone_element: int = -1 var selected_postit_list_element: int = 0 var selected_card_for_assignment var cache: Array = [] signal board_completed # Called when the node enters the scene tree for the first time. func _ready(): base_postit_panel = $HBoxContainer/ScrollContainer/VBoxContainer/Panel postit_container.remove_child(base_postit_panel) dropzone_size = get_viewport_rect().size - Vector2(dropzone_padding + base_postit_panel.custom_minimum_size.x, dropzone_padding) if get_parent() == get_tree().root: populate_board(["c_void", 'c_joy', "p_wet", "p_thomas"]) populate_board(["c_fighting", 'c_hit', "p_girly", "p_vent"]) active_context = ui_context.DROPZONE has_stage = has_stage # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): # Reset information about Areas being dragged, if the mouse is not longer pressed. # Needed because otherwise it can happen that the areas don't register it if you stop clicking on them. if has_stage and !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and is_area_dragged: currently_dragged_area.is_dragged = false is_area_dragged = false currently_dragged_area = null # Will be used later to spawn Cards and Post-Its and remember them in the dictionary func populate_board(card_names: Array): 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_postits:Array = all_new["postIts"] # spawning the cards and adding them to the dictionary for new_card in all_new["cards"]: new_card.position = Vector2(randi_range(dropzone_padding, dropzone_size.x), randi_range(dropzone_padding, dropzone_size.y)) new_card.reparent(dropzone, false) new_card.set_owner(self) area_dict["dropzone_content"].push_back(new_card) area_dict["cards"].push_back(new_card) new_card.is_dragable = true for new_postit in all_new["postIts"]: # spawning a post-it var new_panel = base_postit_panel.duplicate() postit_container.add_child(new_panel) new_panel.set_owner(self) area_dict["post_it_panels"].append(new_panel) new_panel.add_child(new_postit) new_postit.set_owner(self) area_dict["post_its_in_list"].push_back(new_postit) new_postit.position = new_panel.get_child(0).position new_postit.is_dragable = true currently_selected_node = area_dict["dropzone_content"][0] # set first Card as currently selected node by default reorder_areas("dropzone_content") reorder_areas("cards") reorder_areas("post_its_in_list") # Checks if a Node is currently inside the dropzone func is_in_dropzone(to_check: Node) -> bool: if (dropzone.size.x < to_check.global_position.x or dropzone.size.y < to_check.global_position.y): return false elif (to_check.global_position.x < 0 or to_check.global_position.y < 0): return false else: return true # called if a mouse button is pressed func handle_mouse_button(to_handle: Area2D, input: InputEvent): # No two areas can be dragged at the same time. # Make sure that only the same area is dragged. # Otherwise overlapping areas are dragged at the same time. if currently_dragged_area != null and to_handle != currently_dragged_area: return currently_selected_node = to_handle # update currently selected currently_dragged_area = to_handle to_handle.is_dragged = input.pressed is_area_dragged = input.pressed # TODO: We need a better way to recognize whether "to_handle" is a Card or a Post-It. # (Tried checking for a script, didn't work, because script has no name attached. # Alternative might be to check for specific values within the script ("is_card" f.e)) if to_handle is Card: active_context = ui_context.DROPZONE if input.is_pressed(): reorder_areas("dropzone_content") reorder_areas("cards") else: dropzone.move_child(currently_dragged_area, -1) currently_dragged_area = null elif to_handle is PostIt: if input.is_pressed(): to_handle.reparent(dropzone) to_handle.on_board = true to_handle.set_owner(self) # needs to be here otherwise the owner disappears area_dict["post_its_in_list"].erase(to_handle) area_dict["dropzone_content"].push_back(to_handle) # TODO (if needed): Add function to rearrange the array based on positions in the dropzone else: if is_in_dropzone(to_handle): if to_handle.has_overlapping_areas(): for area in to_handle.get_overlapping_areas(): if area is Card: if !area.has_postit_attached(): attach_postit_to_card(to_handle, area) else: to_handle.rotation = to_handle.base_rotation to_handle.scale = to_handle.base_scale else: active_context = ui_context.POST_IT_LIST _return_postit_to_panels(to_handle) currently_dragged_area = null # Logic for attaching a postit to a card. Also reset postit positions if the card cannot be attached func attach_postit_to_card(postit: Area2D, card: Area2D, update_dict = false): if postit.is_in_group(card.name): if card.has_postit_attached(): if active_context == ui_context.ASSIGN_POST_IT: _return_postit_to_panels(postit) # don't attach if card has already a post-it attached return postit.reparent(card.get_child(3, true)) postit.position = Vector2(0,0) postit.on_board = false postit.set_owner(self) postit.position = card.get_child(3).position if update_dict: area_dict["post_its_in_list"].erase(postit) area_dict["dropzone_content"].push_back(postit) reorder_areas("dropzone_content") reorder_areas("cards") reorder_areas("post_its_in_list") if mementos_collected == 4: for fluff in area_dict["dropzone_content"]: if fluff is Card: if not fluff.has_postit_attached(): return emit_signal("board_completed") # Mark area that was hovered over as currently selected func handle_hover(to_handle: Area2D): if to_handle != currently_selected_node: currently_selected_node.highlighted = false currently_selected_node = to_handle if is_in_dropzone(to_handle): selected_dropzone_element = area_dict["dropzone_content"].find(to_handle) active_context = ui_context.DROPZONE else: selected_postit_list_element = area_dict["post_its_in_list"].find(to_handle) active_context = ui_context.POST_IT_LIST # Reorders the areas in any of the dictionaries entries # Pass the entry's key in order to reorder it func reorder_areas(reorder: String): var old_order = area_dict[reorder] var new_order = Array() for obj in old_order: var i = 0 if !new_order.is_empty(): for obj_2 in new_order: if obj_2.global_position.y < obj.global_position.y: i += 1 new_order.insert(i, obj) area_dict[reorder] = new_order # 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 event is InputEventMouse or !has_stage or not is_instance_valid(currently_selected_node): return if event.is_action_pressed("ui_up"): # up to select an element above match active_context: ui_context.DROPZONE: selected_dropzone_element -= 1 ui_context.POST_IT_LIST: selected_postit_list_element -= 1 ui_context.ASSIGN_POST_IT: selected_card_for_assignment -= 1 elif event.is_action_pressed("ui_down"): # down to select an element beneath match active_context: ui_context.DROPZONE: selected_dropzone_element += 1 ui_context.POST_IT_LIST: selected_postit_list_element += 1 ui_context.ASSIGN_POST_IT: selected_card_for_assignment += 1 elif event.is_action_pressed("ui_left"): # left to switch context to the left active_context -= 1 if active_context <= -1: active_context = ui_context.POST_IT_LIST elif event.is_action_pressed("ui_right"): # right to switch context to the right active_context += 1 if active_context > 1: active_context = ui_context.DROPZONE elif event.is_action_pressed("ui_accept"): # select the selected post it if active_context == ui_context.ASSIGN_POST_IT: # to assign it to a card attach_postit_to_card(currently_selected_node, currently_selected_card_for_assigning, false) _leave_assignment_context() else: _enter_assignment_context() # TODO: I forgor the HECKING RIGHT-CLICK!!!!111 AAAAAAAAAAAAAAAAAAAA # do some adjustments to loop elements (after last element, select first one etc.) if selected_dropzone_element < 0: selected_dropzone_element = area_dict["dropzone_content"].size()-1 elif selected_dropzone_element > area_dict["dropzone_content"].size()-1: selected_dropzone_element = 0 if selected_postit_list_element < 0: selected_postit_list_element = area_dict["post_its_in_list"].size()-1 elif selected_postit_list_element > area_dict["post_its_in_list"].size()-1: selected_postit_list_element = 0 if active_context == ui_context.ASSIGN_POST_IT: # skip this if we're not in assign post it context if selected_card_for_assignment < 0: selected_card_for_assignment = area_dict["cards"].size()-1 elif selected_card_for_assignment > area_dict["cards"].size()-1: selected_card_for_assignment = 0 # highlight the selected element match active_context: ui_context.DROPZONE: currently_selected_node.highlighted = false currently_selected_node = area_dict["dropzone_content"][selected_dropzone_element] currently_selected_node.highlighted = true ui_context.POST_IT_LIST: currently_selected_node.highlighted = false currently_selected_node = area_dict["post_its_in_list"][selected_postit_list_element] currently_selected_node.highlighted = true ui_context.ASSIGN_POST_IT: currently_selected_card_for_assigning.highlighted = false currently_selected_card_for_assigning = area_dict["cards"][selected_card_for_assignment] currently_selected_card_for_assigning.highlighted = true _select_card_for_assigning(currently_selected_node, currently_selected_card_for_assigning) # update dictiornary orders reorder_areas("dropzone_content") reorder_areas("post_its_in_list") # Sets everything up to enter the context where postits can be assigned via button controls func _enter_assignment_context(): # cards are currently not moved, only post its. Exit function if a card should be moved. if currently_selected_node == null or not currently_selected_node is PostIt : return # if the postit is already attached, remove it and return it to the post it panels if currently_selected_node.is_postit_attached(): _return_postit_to_panels(currently_selected_node) active_context = ui_context.POST_IT_LIST return # adjust everything for the post it to select its attach-target active_context = ui_context.ASSIGN_POST_IT selected_card_for_assignment = 0 currently_selected_node.reparent(dropzone) # reparent to make it visible currently_selected_node.set_owner(self) area_dict["post_its_in_list"].erase(currently_selected_node) area_dict["dropzone_content"].push_back(currently_selected_node) currently_selected_card_for_assigning = area_dict["dropzone_content"][0] currently_selected_card_for_assigning.highlighted = true # move the post it so it floats next to the card where it should be attached func _select_card_for_assigning(post_it: Area2D, card: Area2D): post_it.tween_transform_to(card.get_child(3).global_position + Vector2(0, 50)) # leaves the context for assigning postit via button controls func _leave_assignment_context(): currently_selected_node.highlighted = false active_context = ui_context.DROPZONE currently_selected_node = currently_selected_card_for_assigning # handles everything to return a post it to the panels func _return_postit_to_panels(post_it: Area2D): for panel in area_dict["post_it_panels"]: print(area_dict["post_it_panels"]) if panel.get_child_count() == 1: area_dict["dropzone_content"].erase(post_it) post_it.on_board = false area_dict["post_its_in_list"].push_back(post_it) #post_it.tween_transform_to(panel.get_child(0).position) post_it.reparent(panel) post_it.transform = panel.get_child(0).transform post_it.set_owner(self) reorder_areas("dropzone_content") reorder_areas("post_its_in_list") break func on_scene_skipped(i: int): mementos_collected += i func claim_focus(): State.pass_stage_to(self)