from pathlib import Path import pytest from engine.defs import DefRegistry from engine.map_loader import MapLoader DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs" @pytest.fixture() def registry(): return DefRegistry.load(DEFS_DIR) def test_tile_layer_defs_load_from_json(registry): grass = registry.get_tile_layer_def("flooring", "grass") assert grass is not None assert grass.walkable is True wall = registry.get_tile_layer_def("room", "wood_wall") assert wall is not None assert wall.walkable is False assert wall.blocks_los is True def test_terrain_flooring_defs_load_with_speed_multipliers(registry): mud = registry.get_tile_layer_def("flooring", "mud") assert mud.walkable is True assert mud.speed_multiplier == 0.6 water = registry.get_tile_layer_def("flooring", "water") assert water.walkable is True assert water.speed_multiplier == 0.7 for def_id in ("dirt", "stone", "sand"): terrain = registry.get_tile_layer_def("flooring", def_id) assert terrain.walkable is True assert terrain.speed_multiplier == 1.0 def test_solid_rock_and_slope_room_defs_load(registry): rock = registry.get_tile_layer_def("room", "solid_rock") assert rock.walkable is False up = registry.get_tile_layer_def("room", "slope_up") assert up.staircase_direction == "up" down = registry.get_tile_layer_def("room", "slope_down") assert down.staircase_direction == "down" def test_item_defs_load_with_correct_footprints(registry): staff = registry.get_item_def("staff_oak") assert (staff.width, staff.height) == (1, 5) sandwich = registry.get_item_def("sandwich") assert (sandwich.width, sandwich.height) == (2, 2) assert sandwich.stackable is True def test_entity_def_references_species_and_inventory_size(registry): player = registry.get_entity_def("player") assert player.species_id == "human" assert player.inventory_size == (6, 5) assert [c.item_def_id for c in player.default_clothing] == ["backpack_basic"] assert player.default_clothing[0].slot == "back" def test_door_locked_tile_layer_def_parses_hack_fields(registry): door = registry.get_tile_layer_def("room", "door_locked") assert door.hack_difficulty == 12 assert door.hackable_unlocked_def_id == "door_open" assert door.walkable is False def test_wood_wall_tile_layer_def_is_not_hackable_by_default(registry): wall = registry.get_tile_layer_def("room", "wood_wall") assert wall.hack_difficulty is None assert wall.hackable_unlocked_def_id is None def test_turret_species_has_no_blood_and_synthetic_flag(registry): turret = registry.get_species_def("turret") assert turret.is_synthetic is True assert turret.blood_label == "Coolant" assert turret.blood_danger_threshold == 0.0 def test_turret_species_default_body_parts_are_the_five_turret_slots(registry): turret = registry.get_species_def("turret") slots = {bp.slot for bp in turret.default_body_parts} assert slots == {"psu", "cpu", "motors", "gun", "camera"} def test_turret_pistol_entity_def_parses_turret_fields(registry): entity_def = registry.get_entity_def("turret_pistol") assert entity_def.species_id == "turret" assert entity_def.turret_weapon_item_id == "pistol_basic" assert entity_def.turret_turn_rate_degrees_per_tick == 30 def test_turret_autocannon_entity_def_parses_turret_fields(registry): entity_def = registry.get_entity_def("turret_autocannon") assert entity_def.turret_weapon_item_id == "turret_autocannon" assert entity_def.turret_turn_rate_degrees_per_tick == 12 def test_non_turret_entity_def_has_no_turret_fields(registry): player = registry.get_entity_def("player") assert player.turret_weapon_item_id is None assert player.turret_turn_rate_degrees_per_tick is None def test_entity_def_parses_its_ai_behavior_id(registry): assert registry.get_entity_def("npc_reptilian").ai_behavior_id == "wander" def test_entity_def_ai_behavior_id_defaults_to_none(registry): assert registry.get_entity_def("player").ai_behavior_id is None def test_item_def_clothing_fields(registry): backpack = registry.get_item_def("backpack_basic") assert backpack.clothing_slot == "back" assert backpack.grants_inventory_size == (4, 4) staff = registry.get_item_def("staff_oak") assert staff.clothing_slot is None assert staff.grants_inventory_size is None def test_new_default_clothing_returns_independent_instances(registry): a = registry.new_default_clothing("player") b = registry.new_default_clothing("player") assert a is not b assert a[0] is not b[0] a[0].removed = True assert b[0].removed is False def test_species_def_resolves_default_body_parts_with_correct_slots(registry): human = registry.get_species_def("human") slots = {bp.slot for bp in human.default_body_parts} assert slots == {"head", "torso", "left_arm", "right_arm", "left_leg", "right_leg"} assert human.genders == ["male", "female", "nonbinary"] assert human.blood_danger_threshold == 50.0 assert human.blood_critical_threshold == 25.0 def test_new_default_body_parts_returns_independent_instances(registry): parts_a = registry.new_default_body_parts("human") parts_b = registry.new_default_body_parts("human") assert parts_a is not parts_b parts_a[0].integrity = 10.0 assert parts_b[0].integrity == 100.0 def test_body_part_def_carries_bleeding_and_skill_weights(registry): head = registry.get_body_part_def("human_head") assert head.bleeding_weight == pytest.approx(0.10) assert head.skill_weights["perception"] == pytest.approx(0.6) def test_demo_world_loads_with_ship_embedded_at_anchor(): loader = MapLoader(DEFS_DIR / "maps") world = loader.load("demo_world.json") assert (world.width, world.height, world.depth) == (10, 10, 1) assert len(world.embeddings) == 1 embedding = world.embeddings[0] assert embedding.anchor == (6, 6, 0) assert embedding.child_map.map_id == "ship_small" assert (embedding.child_map.width, embedding.child_map.height) == (4, 3) assert embedding.child_map.parent_embedding is embedding def test_demo_world_tiles_resolve_against_tile_defs(registry): loader = MapLoader(DEFS_DIR / "maps") world = loader.load("demo_world.json") tile = world.get_tile(0, 0, 0) assert tile.flooring.def_id == "grass" assert tile.is_walkable(registry) is True ship = world.embeddings[0].child_map wall_tile = ship.get_tile(0, 0, 0) assert wall_tile.room.def_id == "wood_wall" assert wall_tile.is_walkable(registry) is False door_tile = ship.get_tile(2, 0, 0) assert door_tile.room is None assert door_tile.is_walkable(registry) is True def test_map_loader_defaults_max_rotation_speed_to_90(registry): loader = MapLoader(DEFS_DIR / "maps") harbor = loader.load("harbor_world.json") assert harbor.embeddings[0].max_rotation_speed == 90.0 def test_map_loader_reads_a_custom_max_rotation_speed(tmp_path): import json maps_dir = tmp_path / "maps" maps_dir.mkdir() (maps_dir / "slow_ship.json").write_text(json.dumps({ "map_id": "slow_ship", "width": 2, "height": 2, "depth": 1, "default_tile": {"flooring": "wood_deck"}, "tiles": [], })) (maps_dir / "field.json").write_text(json.dumps({ "map_id": "field", "width": 5, "height": 5, "depth": 1, "default_tile": {"flooring": "grass"}, "tiles": [], "embeddings": [{"map_file": "slow_ship.json", "anchor": [1, 1, 0], "max_rotation_speed": 15.0}], })) loader = MapLoader(maps_dir) field = loader.load("field.json") assert field.embeddings[0].max_rotation_speed == 15.0