96ec053331
- HoldableItem._try_return_to_chest() snaps item back if within CHEST_RETURN_RADIUS (80px) - _on_drag_released checks chest return before hand-slot fallback - OutfitItem._on_drag_released checks chest return before outfit/hand-slot logic - GameState: _chest_states dict + get/set/clear_chest_state methods - GameState.get_save_data() bumped to version 3, includes chest_states - GameState.apply_save_data() restores chest_states from save data
88 lines
2.5 KiB
GDScript
88 lines
2.5 KiB
GDScript
## HoldableItem — Node2D that can be held in a Character's HandLeft or HandRight slot.
|
|
## Attach DragDropComponent as a child. On drag_released scans "characters" group for
|
|
## the nearest free hand slot within HAND_SLOT_RADIUS.
|
|
class_name HoldableItem extends Node2D
|
|
|
|
signal item_picked_up(item: HoldableItem)
|
|
signal item_placed(item: HoldableItem)
|
|
|
|
const HAND_SLOT_RADIUS: float = 60.0
|
|
const CHEST_RETURN_RADIUS: float = 80.0
|
|
|
|
@export var item_id: String = ""
|
|
|
|
var home_chest: Node2D = null
|
|
|
|
|
|
func _ready() -> void:
|
|
var drag: DragDropComponent = get_node_or_null("DragDropComponent") as DragDropComponent
|
|
if drag != null:
|
|
drag.drag_picked_up.connect(_on_drag_picked_up)
|
|
drag.drag_released.connect(_on_drag_released)
|
|
|
|
|
|
func _on_drag_picked_up(_pos: Vector2) -> void:
|
|
if is_in_hand_slot():
|
|
_detach_from_hand_slot()
|
|
item_picked_up.emit(self)
|
|
|
|
|
|
func _on_drag_released(_pos: Vector2) -> void:
|
|
if _try_return_to_chest():
|
|
return
|
|
var result: Array = _find_nearest_free_hand_slot()
|
|
if not result.is_empty():
|
|
var character: Character = result[0] as Character
|
|
var hand: String = result[1] as String
|
|
character.attach_item(hand, self)
|
|
item_placed.emit(self)
|
|
|
|
|
|
func _try_return_to_chest() -> bool:
|
|
if home_chest == null:
|
|
return false
|
|
if global_position.distance_to(home_chest.global_position) >= CHEST_RETURN_RADIUS:
|
|
return false
|
|
(home_chest as RoomChest).receive_item(self)
|
|
return true
|
|
|
|
|
|
func is_in_hand_slot() -> bool:
|
|
var p: Node = get_parent()
|
|
if p == null:
|
|
return false
|
|
return p.name == "HandLeft" or p.name == "HandRight"
|
|
|
|
|
|
func _detach_from_hand_slot() -> void:
|
|
var hand_slot: Node = get_parent()
|
|
var character: Character = hand_slot.get_parent() as Character
|
|
if character == null:
|
|
return
|
|
var hand: String = "left" if hand_slot.name == "HandLeft" else "right"
|
|
character.detach_item(hand)
|
|
|
|
|
|
func _find_nearest_free_hand_slot() -> Array:
|
|
var best_dist: float = HAND_SLOT_RADIUS
|
|
var best_character: Character = null
|
|
var best_hand: String = ""
|
|
for node: Node in get_tree().get_nodes_in_group("characters"):
|
|
var character: Character = node as Character
|
|
if character == null:
|
|
continue
|
|
for hand: String in ["left", "right"]:
|
|
if not character.is_hand_free(hand):
|
|
continue
|
|
var slot: Node2D = character.get_node_or_null("Hand" + hand.capitalize()) as Node2D
|
|
if slot == null:
|
|
continue
|
|
var dist: float = global_position.distance_to(slot.global_position)
|
|
if dist < best_dist:
|
|
best_dist = dist
|
|
best_character = character
|
|
best_hand = hand
|
|
if best_character == null:
|
|
return []
|
|
return [best_character, best_hand]
|