feat(items): add RoomChest with spawn and receive logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Steven Wroblewski
2026-05-09 01:04:34 +02:00
parent 4e4743f14f
commit b9c73b80ea
3 changed files with 143 additions and 0 deletions
+2
View File
@@ -10,6 +10,8 @@ const HAND_SLOT_RADIUS: float = 60.0
@export var item_id: String = ""
var home_chest: Node2D = null
func _ready() -> void:
var drag: DragDropComponent = get_node_or_null("DragDropComponent") as DragDropComponent
+93
View File
@@ -0,0 +1,93 @@
## RoomChest — tappable storage node. Spawns HoldableItem/OutfitItem instances on demand.
## Items fly out with a tween. Receives items back via receive_item().
class_name RoomChest extends Node2D
signal items_spawned(chest: RoomChest)
signal item_received(chest: RoomChest, item_id: String)
const SPAWN_TWEEN_DURATION: float = 0.3
@export var chest_id: String = ""
var _spawned_items: Array = []
var _item_configs: Array[ChestItemData] = []
func _ready() -> void:
add_to_group("room_chests")
_item_configs = RoomChestConfig.get_items(chest_id)
if not chest_id.is_empty() and GameState.has_method("get_chest_state"):
if not GameState.get_chest_state(chest_id).is_empty():
spawn_items()
func spawn_items() -> void:
if not _spawned_items.is_empty():
return
var parent: Node = get_parent()
for config: ChestItemData in _item_configs:
var item: HoldableItem = _create_item(config)
item.home_chest = self
if parent != null:
parent.add_child(item)
else:
add_child(item)
item.global_position = global_position
_spawned_items.append(item)
_tween_item_out(item, config.spawn_offset)
if GameState.has_method("set_chest_state"):
GameState.set_chest_state(chest_id, _get_spawned_ids())
items_spawned.emit(self)
func receive_item(item: HoldableItem) -> void:
_spawned_items.erase(item)
if GameState.has_method("set_chest_state"):
if _spawned_items.is_empty():
GameState.clear_chest_state(chest_id)
else:
GameState.set_chest_state(chest_id, _get_spawned_ids())
item_received.emit(self, item.item_id)
_tween_item_in(item)
func are_items_spawned() -> bool:
return not _spawned_items.is_empty()
func get_spawned_count() -> int:
return _spawned_items.size()
func get_item_config_count() -> int:
return _item_configs.size()
func _create_item(config: ChestItemData) -> HoldableItem:
var item: HoldableItem
if config.item_type == ChestItemData.ItemType.OUTFIT:
var outfit: OutfitItem = OutfitItem.new()
outfit.outfit_layer = config.outfit_layer
item = outfit
else:
item = HoldableItem.new()
item.item_id = config.item_id
return item
func _get_spawned_ids() -> Array:
var ids: Array = []
for item: HoldableItem in _spawned_items:
ids.append(item.item_id)
return ids
func _tween_item_out(item: HoldableItem, offset: Vector2) -> void:
var tween: Tween = create_tween()
tween.tween_property(item, "global_position", global_position + offset, SPAWN_TWEEN_DURATION)
func _tween_item_in(item: HoldableItem) -> void:
var tween: Tween = create_tween()
tween.tween_property(item, "global_position", global_position, SPAWN_TWEEN_DURATION)
tween.tween_callback(item.queue_free)
+48
View File
@@ -35,3 +35,51 @@ func test_room_chest_config_patient_cabinet_stethoscope_outfit_layer_two() -> vo
assert_eq(stethoscope.item_id, "stethoscope")
assert_eq(stethoscope.item_type, ChestItemData.ItemType.OUTFIT)
assert_eq(stethoscope.outfit_layer, 2)
func test_are_items_spawned_false_initially() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
assert_false(chest.are_items_spawned())
func test_get_spawned_count_zero_initially() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
assert_eq(chest.get_spawned_count(), 0)
func test_get_item_config_count_matches_config() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
assert_eq(chest.get_item_config_count(), 3)
func test_spawn_items_creates_correct_count() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
chest.spawn_items()
assert_eq(chest.get_spawned_count(), 3)
func test_double_spawn_is_noop() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
chest.spawn_items()
chest.spawn_items()
assert_eq(chest.get_spawned_count(), 3)
func test_receive_item_decrements_spawned_count() -> void:
var chest: RoomChest = RoomChest.new()
chest.chest_id = "reception_desk"
add_child_autofree(chest)
chest.spawn_items()
var item: HoldableItem = chest._spawned_items[0] as HoldableItem
chest.receive_item(item)
assert_eq(chest.get_spawned_count(), 2)