diff --git a/scripts/autoload/GameState.gd b/scripts/autoload/GameState.gd index 8f7d4eb..e7c82ee 100644 --- a/scripts/autoload/GameState.gd +++ b/scripts/autoload/GameState.gd @@ -8,6 +8,7 @@ var _character_positions: Dictionary = {} var _character_outfits: Dictionary = {} var _character_held_items: Dictionary = {} var _object_states: Dictionary = {} +var _chest_states: Dictionary = {} var current_room: String = "reception" var music_volume: float = 0.6 var sfx_volume: float = 1.0 @@ -58,17 +59,32 @@ func set_object_state(id: String, state: String) -> void: state_changed.emit() +func get_chest_state(chest_id: String) -> Array: + return _chest_states.get(chest_id, []) + + +func set_chest_state(chest_id: String, spawned_item_ids: Array) -> void: + _chest_states[chest_id] = spawned_item_ids + state_changed.emit() + + +func clear_chest_state(chest_id: String) -> void: + _chest_states.erase(chest_id) + state_changed.emit() + + func get_save_data() -> Dictionary: var positions: Dictionary = {} for key: String in _character_positions: var pos: Vector2 = _character_positions[key] positions[key] = [pos.x, pos.y] return { - "version": 2, + "version": 3, "character_positions": positions, "character_outfits": _character_outfits.duplicate(true), "character_held_items": _character_held_items.duplicate(true), "object_states": _object_states, + "chest_states": _chest_states.duplicate(true), "current_room": current_room, "music_volume": music_volume, "sfx_volume": sfx_volume, @@ -98,3 +114,7 @@ func apply_save_data(data: Dictionary) -> void: music_volume = data["music_volume"] if data.has("sfx_volume"): sfx_volume = data["sfx_volume"] + if data.has("chest_states"): + _chest_states = data["chest_states"].duplicate(true) + else: + _chest_states = {} diff --git a/scripts/objects/holdable_item.gd b/scripts/objects/holdable_item.gd index be93faa..a2f248d 100644 --- a/scripts/objects/holdable_item.gd +++ b/scripts/objects/holdable_item.gd @@ -7,6 +7,7 @@ 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 = "" @@ -27,6 +28,8 @@ func _on_drag_picked_up(_pos: Vector2) -> void: 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 @@ -35,6 +38,15 @@ func _on_drag_released(_pos: Vector2) -> void: 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: diff --git a/scripts/objects/outfit_item.gd b/scripts/objects/outfit_item.gd index d993c7d..b4c04e8 100644 --- a/scripts/objects/outfit_item.gd +++ b/scripts/objects/outfit_item.gd @@ -10,6 +10,8 @@ const OUTFIT_APPLY_RADIUS: float = 80.0 func _on_drag_released(_pos: Vector2) -> void: + if _try_return_to_chest(): + return var character: Character = _find_nearest_character() if character != null: character.apply_outfit_item(outfit_layer, item_id, outfit_sprite, self) diff --git a/test/unit/test_game_state.gd b/test/unit/test_game_state.gd index a8a8f9a..7ad6187 100644 --- a/test/unit/test_game_state.gd +++ b/test/unit/test_game_state.gd @@ -144,4 +144,40 @@ func test_apply_save_data_restores_held_items() -> void: func test_save_data_has_version_two() -> void: var data: Dictionary = _state.get_save_data() - assert_eq(data.get("version", 0), 2) + assert_eq(data.get("version", 0), 3) + + +func test_get_chest_state_returns_empty_for_unknown_id() -> void: + assert_eq(GameState.get_chest_state("nonexistent_chest_xyz"), []) + + +func test_set_and_get_chest_state() -> void: + GameState.set_chest_state("pharmacy_medicine_test", ["pill_bottle", "syrup"]) + assert_eq(GameState.get_chest_state("pharmacy_medicine_test"), ["pill_bottle", "syrup"]) + + +func test_clear_chest_state_removes_entry() -> void: + GameState.set_chest_state("lab_bench_test", ["test_tube"]) + GameState.clear_chest_state("lab_bench_test") + assert_eq(GameState.get_chest_state("lab_bench_test"), []) + + +func test_chest_state_included_in_save_data() -> void: + GameState.set_chest_state("xray_cabinet_test", ["xray_sheet"]) + var data: Dictionary = GameState.get_save_data() + assert_true(data.has("chest_states")) + assert_eq(data["chest_states"]["xray_cabinet_test"], ["xray_sheet"]) + + +func test_save_data_version_is_three() -> void: + var data: Dictionary = GameState.get_save_data() + assert_eq(data["version"], 3) + + +func test_apply_save_data_restores_chest_state() -> void: + var data: Dictionary = { + "version": 3, + "chest_states": {"reception_desk_test": ["clipboard", "pen"]}, + } + GameState.apply_save_data(data) + assert_eq(GameState.get_chest_state("reception_desk_test"), ["clipboard", "pen"]) diff --git a/test/unit/test_holdable_item.gd b/test/unit/test_holdable_item.gd index 5511cdc..97f9d33 100644 --- a/test/unit/test_holdable_item.gd +++ b/test/unit/test_holdable_item.gd @@ -69,3 +69,33 @@ func test_holdable_item_detach_preserves_global_position() -> void: var hand_pos: Vector2 = character.get_node("HandLeft").global_position item._on_drag_picked_up(hand_pos) assert_eq(item.global_position, hand_pos) + + +func test_try_return_to_chest_false_when_no_home_chest() -> void: + var item: HoldableItem = HoldableItem.new() + add_child_autofree(item) + assert_false(item._try_return_to_chest()) + + +func test_try_return_to_chest_false_when_beyond_radius() -> void: + var chest: RoomChest = RoomChest.new() + chest.chest_id = "reception_desk" + add_child_autofree(chest) + chest.global_position = Vector2.ZERO + var item: HoldableItem = HoldableItem.new() + add_child_autofree(item) + item.home_chest = chest + item.global_position = Vector2(200.0, 0.0) + assert_false(item._try_return_to_chest()) + + +func test_try_return_to_chest_true_when_within_radius() -> void: + var chest: RoomChest = RoomChest.new() + chest.chest_id = "reception_desk" + add_child_autofree(chest) + chest.global_position = Vector2.ZERO + var item: HoldableItem = HoldableItem.new() + add_child_autofree(item) + item.home_chest = chest + item.global_position = Vector2(40.0, 0.0) + assert_true(item._try_return_to_chest())