diff --git a/src/logic-scenes/board/card-board.gd b/src/logic-scenes/board/card-board.gd index 5dbec4d..ee53d88 100644 --- a/src/logic-scenes/board/card-board.gd +++ b/src/logic-scenes/board/card-board.gd @@ -262,7 +262,6 @@ func add_card(card: Card, re_parent:bool = true): add_child(card) insert_area(dropzone, card) card.position = _generate_random_position() - card.set_owner(self) card.is_dragable = true ## Unified function to reclaim any sticky note to a panel @@ -270,29 +269,28 @@ func add_card(card: Card, re_parent:bool = true): func reclaim_sticky_to_panel(sticky: StickyNote, animate: bool = true, prefer_panel_index: int = -1) -> void: # Find or create target panel var target_panel: StickyNotePanel = null - + # Try preferred panel first (for exchanges) if prefer_panel_index >= 0 and prefer_panel_index < sticky_note_container.get_child_count(): var panel = sticky_note_container.get_child(prefer_panel_index) if panel is StickyNotePanel and panel.is_empty(): target_panel = panel - + # Find any empty panel if not target_panel: for panel in sticky_note_container.get_children(): if panel is StickyNotePanel and panel.is_empty(): target_panel = panel break - + # Create new panel if needed if not target_panel: target_panel = StickyNotePanel.new() sticky_note_container.add_child(target_panel, true, Node.INTERNAL_MODE_DISABLED) - target_panel.set_owner(self) - + # Attach sticky to panel (handles all state setup and animation) target_panel.attatch_sticky_note(sticky, self, animate) - + # Clean up other empty panels if animate: # Only clean up during interactive use, not initial setup for panel in sticky_note_container.get_children(): @@ -467,9 +465,6 @@ func insert_area(parent: Control, node: Area2D): if not node in parent.get_children(): node.reparent(parent, false) # Don't preserve global transform - we set positions explicitly - if node is StickyNote: - node.on_board = true - node.owner = self if children.size() > 0: children.erase(node) @@ -478,7 +473,6 @@ func insert_area(parent: Control, node: Area2D): parent.move_child(node, i) if node is StickyNote: - node.attached_to = self node.is_dragable = true ## Sorts all children in dropzone by their Y position @@ -526,8 +520,6 @@ func handle_drop(draggable: Draggable) -> int: # Handle sticky note drop var sticky = draggable as StickyNote insert_area(dropzone, sticky) - sticky.attached_to = self - sticky.on_board = true sticky.is_dragable = true # Reset visual state sticky.rotation = 0.0 @@ -789,7 +781,6 @@ func initialise_from_save(savegame: SaveGame) -> void: # Add to board first add_child(card) - card.set_owner(self) card.is_dragable = true cards_by_name[card.name] = card card.picked_random = savegame.board_randoms.has(card.card_id) @@ -812,7 +803,6 @@ func initialise_from_save(savegame: SaveGame) -> void: if cards_by_name.has(card_name): # Must add sticky to scene tree BEFORE attach_sticky_note() can reparent it add_child(sticky) - sticky.set_owner(self) sticky.current_handle = self # Required for input handling cards_by_name[card_name].attach_sticky_note(sticky) print_debug(" Sticky '%s' attached to card '%s'" % [sticky.name, card_name]) @@ -833,10 +823,7 @@ func initialise_from_save(savegame: SaveGame) -> void: # Add to board first add_child(sticky) - sticky.set_owner(self) sticky.current_handle = self # Required for input handling - sticky.on_board = true - sticky.attached_to = self sticky.is_dragable = true # Move to dropzone and set position (position must be set after adding to scene) diff --git a/src/logic-scenes/board/card.gd b/src/logic-scenes/board/card.gd index bcaf79c..5a6208b 100644 --- a/src/logic-scenes/board/card.gd +++ b/src/logic-scenes/board/card.gd @@ -14,7 +14,6 @@ enum burned { var compatible_sticky_notes: Array[StickyNote] = [] @export var evil_sticky_notes: Array[StickyNote] = [] var own_sticky_notes: Array[StickyNote] = [] -var current_sticky_note: StickyNote = null var wiggle_pos: float = 0 var wiggle_intensity: float = 0 var noise: Noise = FastNoiseLite.new() @@ -215,11 +214,12 @@ func _input(event: InputEvent) -> void: func _on_mouse_entered() -> void: if not Input.is_action_pressed("mouse_left"): # Do nothing if mouse hovers over sticky_note (it has higher priority) - if has_sticky_note_attached(): - if current_sticky_note and current_sticky_note.highlighted: - return - if "handle_hover" in owner: - owner.handle_hover(self) + var sticky = get_attached_sticky_note() + if sticky and sticky.highlighted: + return + var parent = get_parent() + if parent and parent.has_method("handle_hover"): + parent.handle_hover(self) func _on_mouse_exited(): highlighted = false @@ -228,9 +228,10 @@ func _on_mouse_exited(): func _on_input_event(_viewport, event, _shape_idx): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: - if "handle_mouse_button" in owner and highlighted: + var parent = get_parent() + if parent and parent.has_method("handle_mouse_button") and highlighted: mouse_offset = get_viewport().get_mouse_position() - position - owner.handle_mouse_button(event, self) + parent.handle_mouse_button(event, self) func _move_card(): if is_dragged: @@ -249,8 +250,7 @@ func get_attached_sticky_note() -> StickyNote: func preview_sticky_note(sticky_note: StickyNote): if not is_instance_valid(sticky_note): return - sticky_note.reparent(self.get_parent()) - sticky_note.attached_to = self + # Keep sticky in current parent during preview (just move it visually) # Use a safe transform with validated position var target_pos := global_position + sticky_note_position if is_finite(target_pos.x) and is_finite(target_pos.y): @@ -264,11 +264,7 @@ func attach_sticky_note(sticky_note: StickyNote) -> bool: sticky_note.reparent(self) sticky_note.position = sticky_note_position - sticky_note.on_board = false sticky_note.is_dragable = false - current_sticky_note = sticky_note - #var former_parent = sticky_note.attached_to - sticky_note.attached_to = self if name == "c_hit" and sticky_note.name == "c_effort" and Steamworks.has_initialized: Steam.setAchievement("FIGHT_FOR_GOOD") @@ -277,12 +273,10 @@ func attach_sticky_note(sticky_note: StickyNote) -> bool: return true func remove_sticky_note() -> StickyNote: - var former_child:StickyNote = get_attached_sticky_note() - current_sticky_note = null + var former_child: StickyNote = get_attached_sticky_note() + if not former_child: + return null former_child.reparent(get_parent()) - former_child.owner = self.owner - former_child.on_board = true - former_child.attached_to = owner return former_child func exchange_sticky_note_with(new_note: StickyNote) -> StickyNote: @@ -292,15 +286,16 @@ func exchange_sticky_note_with(new_note: StickyNote) -> StickyNote: # This makes sure this node highlights itself when focus has left the sticky note. func check_hover(): - # Re-trigger hover handling - owner will decide if this should be highlighted + # Re-trigger hover handling - parent will decide if this should be highlighted _on_mouse_entered() func reclaim_sticky_note(): - current_sticky_note.on_board = false - current_sticky_note.tween_transform_to(Transform2D(0, to_global(sticky_note_position))) - await current_sticky_note.transform_tween_finished - current_sticky_note.reparent(self) - current_sticky_note.owner = self.owner + var sticky = get_attached_sticky_note() + if not sticky: + return + sticky.tween_transform_to(Transform2D(0, to_global(sticky_note_position))) + await sticky.transform_tween_finished + sticky.reparent(self) # === DROP TARGET PATTERN IMPLEMENTATION === @@ -346,4 +341,11 @@ func get_last_exchanged_sticky() -> StickyNote: ## Cards always drop back to board dropzone func find_drop_target() -> Node: - return owner if owner is CardBoard else get_parent() + var parent = get_parent() + # Walk up tree to find CardBoard + while parent: + if parent is CardBoard: + return parent + parent = parent.get_parent() + # Fallback to immediate parent + return get_parent() diff --git a/src/logic-scenes/board/sticky-note.gd b/src/logic-scenes/board/sticky-note.gd index 3957373..d694295 100644 --- a/src/logic-scenes/board/sticky-note.gd +++ b/src/logic-scenes/board/sticky-note.gd @@ -7,14 +7,17 @@ var parent_id var sibling: StickyNote var shift_tween: Tween var modulate_tween: Tween -var attached_to: Node = null: - set(new_attatchement): - attached_to = new_attatchement + # cannot be explicitly typed, as this can be both handled by picker and physics-board var current_handle: Node var position_locked: bool = false +## Computed property: Returns the current attachment (parent node) +## Replaces the need for tracking attached_to as state +var attached_to: Node: + get: return get_parent() + signal transform_tween_finished @onready var background_sprite: AnimatedSprite2D = %BackgroundSprite @@ -63,7 +66,13 @@ var mouse_offset: Vector2 @onready var diameter := 312.0 @export_range(1.0, 10.0) var bounce_speed: float = 8 -var on_board: bool = false + +## Computed property: Check if on the board (dropzone) +## Replaces on_board state tracking +var on_board: bool: + get: + var parent = get_parent() + return parent != null and parent.name == "dropzone" func init(sticky_name: String = "sticky_note", card_id: StringName = "-1") -> void: name = sticky_name @@ -108,18 +117,24 @@ func _on_mouse_entered(): func _on_mouse_exited(): highlighted = false # Let parent card re-check hover state if this sticky is attached to it - if is_sticky_note_attached() and "check_hover" in attached_to: - attached_to.check_hover() + if is_sticky_note_attached(): + var card = get_parent() + if card and card.has_method("check_hover"): + card.check_hover() func _on_area_enter(area: Area2D): # Handle sticky note panel gap creation if area is StickyNote and is_sticky_note_in_panel() and not is_dragged: - attached_to.create_gap() + var panel = get_parent() as StickyNotePanel + if panel: + panel.create_gap() func _on_area_exit(area: Area2D): # Handle sticky note panel gap collapse if area is StickyNote and is_sticky_note_in_panel(): - attached_to.collapse_gap() + var panel = get_parent() as StickyNotePanel + if panel: + panel.collapse_gap() func _on_input_event(_viewport, event, _shape_idx): if event is InputEventMouseButton and "handle_mouse_button" in current_handle: @@ -132,12 +147,12 @@ func _move_sticky_note(): update_drag_position(get_viewport().get_mouse_position()) func is_sticky_note_attached() -> bool: - # FIXME: this breaks if attatched to is previousely freed because GODOT IS FUCKING STUPID - return attached_to is Card + var parent = get_parent() + return is_instance_valid(parent) and parent is Card func is_sticky_note_in_panel() -> bool: - ## fixme ~> see above - return attached_to is StickyNotePanel + var parent = get_parent() + return is_instance_valid(parent) and parent is StickyNotePanel var transform_tween: Tween @@ -170,11 +185,11 @@ func start_drag(offset: Vector2) -> void: # If attached to a card, detach it first if is_sticky_note_attached(): - var card := attached_to as Card + var card := get_parent() as Card if card and card.has_method("remove_sticky_note"): card.remove_sticky_note() - # If in panel, immediately reparent to board for dragging + # If in panel, immediately reparent to board dropzone for dragging if _came_from_panel and current_handle: var board := current_handle var dropzone := board.get_node_or_null("HBoxContainer/dropzone") @@ -182,8 +197,6 @@ func start_drag(offset: Vector2) -> void: reparent(dropzone) else: reparent(board) - on_board = true - attached_to = board ## Find best drop target: Card > Panel > Board (in priority order) func find_drop_target() -> Node: diff --git a/src/logic-scenes/board/sticky_note_panel.gd b/src/logic-scenes/board/sticky_note_panel.gd index 5544ef0..042fa76 100644 --- a/src/logic-scenes/board/sticky_note_panel.gd +++ b/src/logic-scenes/board/sticky_note_panel.gd @@ -11,43 +11,40 @@ var ancor_position: Vector2 func _init(cstm_minimum_size: Vector2 = minimum_size, note_position: Vector2 = Vector2(105, 57)) -> void: minimum_size = cstm_minimum_size ancor_position = note_position - mouse_filter = MOUSE_FILTER_PASS + mouse_filter = MOUSE_FILTER_PASS self_modulate = Color(1, 1, 1, 0) func _ready(): custom_minimum_size = Vector2(custom_minimum_size.x, 0) var is_attatching: bool = false -func attatch_sticky_note(attatchment: StickyNote, custom_owner: Node, animate:bool = true): +func attatch_sticky_note(attatchment: StickyNote, custom_handle: Node, animate:bool = true): is_attatching = true attached_sticky_note = attatchment - attatchment.current_handle = custom_owner - attatchment.owner = custom_owner - + attatchment.current_handle = custom_handle + # Expand panel height if animate: var height_tween: Tween = create_tween() height_tween.tween_property(self, "custom_minimum_size", minimum_size, 0.1) else: custom_minimum_size = minimum_size - + # Position sticky if animate: await get_tree().process_frame - attatchment.on_board = false attatchment.z_index = 125 # On top during animation - + # Reparent while keeping world position for smooth animation attatchment.reparent(self, true) - attatchment.attached_to = self - + # Tween to anchor position in panel's coordinate space var tween := create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_BACK) tween.tween_property(attatchment, "position", ancor_position, 0.7) tween.tween_property(attatchment, "rotation", 0.0, 0.7) tween.parallel().tween_property(attatchment, "scale", Vector2.ONE, 0.7) await tween.finished - + attatchment.z_index = 0 else: # Immediate placement (for initial board setup) @@ -55,26 +52,25 @@ func attatch_sticky_note(attatchment: StickyNote, custom_owner: Node, animate:bo attatchment.reparent(self) else: add_child(attatchment) - attatchment.on_board = false - attatchment.attached_to = self attatchment.position = ancor_position attatchment.rotation = 0.0 attatchment.scale = Vector2.ONE - + is_attatching = false - + var is_gapped: bool = false func create_gap(): var self_id := get_parent().get_children().find(self) var next_id = min(self_id + 1, get_parent().get_child_count() - 1) var previous_id = max(self_id - 1, 0) - - if not (is_gapped or get_parent().get_child(next_id).attached_sticky_note.is_dragged or get_parent().get_child(previous_id).attached_sticky_note.is_dragged) and owner.current_context == CardBoard.DRAG: + + var board = _get_board() + if not (is_gapped or get_parent().get_child(next_id).attached_sticky_note.is_dragged or get_parent().get_child(previous_id).attached_sticky_note.is_dragged) and board and board.current_context == CardBoard.DRAG: is_gapped = true var height_tween: Tween = create_tween() height_tween.tween_property(self, "custom_minimum_size", minimum_size*Vector2(1.0, 1.8), 0.1) - + get_parent().get_child(next_id).collapse_gap() if not get_parent().get_children().find(self) == 0: get_parent().get_child(previous_id).collapse_gap() @@ -88,11 +84,13 @@ var invalid: bool = false func clear_if_empty(): if !is_empty(): return invalid = true - if attached_sticky_note.attached_to == self: attached_sticky_note.attached_to = null + # No need to manually clear attached_to - reparenting handles it var height_tween: Tween = create_tween() height_tween.tween_property(self, "custom_minimum_size", Vector2.ZERO, 0.3) await height_tween.finished - owner.on_sticky_panel_cleared(get_parent().get_children().find(self)) + var board = _get_board() + if board: + board.on_sticky_panel_cleared(get_parent().get_children().find(self)) self.queue_free() func replace_sticky_note_with(new_sticky_note: StickyNote): @@ -113,13 +111,19 @@ func can_accept_drop(draggable: Draggable) -> bool: func handle_drop(draggable: StickyNote) -> int: if not can_accept_drop(draggable): return Draggable.DropResult.REJECTED - + # Attach sticky to this panel with animation - attatch_sticky_note(draggable, owner, true) - + var board = _get_board() + if board: + attatch_sticky_note(draggable, board, true) + # Clean up other empty panels for panel in get_parent().get_children(): if panel is StickyNotePanel and panel != self: panel.clear_if_empty() - + return Draggable.DropResult.ACCEPTED + + +func _get_board() -> CardBoard: + return get_parent().get_parent() as CardBoard