143 lines
5.1 KiB
Python
143 lines
5.1 KiB
Python
import sqlite3
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from engine.character import Ailment, BodyPart, Character, ClothingPiece
|
|
from engine.db import WorldRepository
|
|
from engine.defs import DefRegistry
|
|
from engine.entity import EntityPosition
|
|
from engine.inventory import Inventory
|
|
from engine.item import ItemInstance
|
|
from engine.map_loader import MapLoader
|
|
from engine.world import World
|
|
|
|
DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs"
|
|
|
|
|
|
@pytest.fixture()
|
|
def registry():
|
|
return DefRegistry.load(DEFS_DIR)
|
|
|
|
|
|
def build_world(registry) -> World:
|
|
loader = MapLoader(DEFS_DIR / "maps")
|
|
demo_world = loader.load("demo_world.json")
|
|
ship = demo_world.embeddings[0].child_map
|
|
|
|
world = World(registry=registry)
|
|
world.add_map(demo_world)
|
|
world.add_map(ship)
|
|
|
|
player = Character(
|
|
entity_id="player-1",
|
|
name="Player",
|
|
def_id="player",
|
|
position=EntityPosition("demo_world", 7, 5, 0),
|
|
species_id="human",
|
|
gender="nonbinary",
|
|
blood_percentage=82.5,
|
|
body_parts=[
|
|
BodyPart("head", "human_head_hat"),
|
|
BodyPart("left_leg", "human_left_leg", integrity=40.0, ailments=[Ailment("frostbite", "Frostbite", 0.5)]),
|
|
],
|
|
default_body_parts=registry.new_default_body_parts("human"),
|
|
clothing=[ClothingPiece("torso", "leather_jacket")],
|
|
default_clothing=registry.new_default_clothing("player"),
|
|
mental_stats={"insanity": 12.5},
|
|
)
|
|
player.bio["stealth"] = 3
|
|
backpack_inventory = player.get_equipped_inventory("back", registry)
|
|
backpack_inventory.place(ItemInstance("rope-1", "sandwich"), registry.get_item_def("sandwich"), 0, 0)
|
|
player.inventory = Inventory(6, 5)
|
|
player.inventory.place(ItemInstance("staff-1", "staff_oak"), registry.get_item_def("staff_oak"), 0, 0)
|
|
player.inventory.place(ItemInstance("sandwich-1", "sandwich"), registry.get_item_def("sandwich"), 1, 0)
|
|
|
|
world.add_entity(player)
|
|
world.player = player
|
|
return world
|
|
|
|
|
|
def test_save_and_load_roundtrip_preserves_entity_and_inventory(registry):
|
|
world = build_world(registry)
|
|
repo = WorldRepository(sqlite3.connect(":memory:"))
|
|
repo.save_world(world)
|
|
|
|
loader = MapLoader(DEFS_DIR / "maps")
|
|
reloaded = repo.load_world(registry, loader)
|
|
|
|
assert reloaded is not None
|
|
assert reloaded.player is not None
|
|
assert reloaded.player.entity_id == "player-1"
|
|
assert (reloaded.player.position.map_id, reloaded.player.position.x, reloaded.player.position.y) == (
|
|
"demo_world",
|
|
7,
|
|
5,
|
|
)
|
|
|
|
assert isinstance(reloaded.player, Character)
|
|
assert reloaded.player.get_body_part("head").part_def_id == "human_head_hat"
|
|
assert reloaded.player.get_body_part("torso").part_def_id == "human_torso"
|
|
|
|
placed = {p.item.item_id: (p.x, p.y) for p in reloaded.player.inventory.items()}
|
|
assert placed == {"staff-1": (0, 0), "sandwich-1": (1, 0)}
|
|
|
|
|
|
def test_save_and_load_roundtrip_preserves_health_fields(registry):
|
|
world = build_world(registry)
|
|
repo = WorldRepository(sqlite3.connect(":memory:"))
|
|
repo.save_world(world)
|
|
|
|
loader = MapLoader(DEFS_DIR / "maps")
|
|
reloaded = repo.load_world(registry, loader)
|
|
player = reloaded.player
|
|
|
|
assert player.species_id == "human"
|
|
assert player.gender == "nonbinary"
|
|
assert player.blood_percentage == pytest.approx(82.5)
|
|
assert player.mental_stats == {"insanity": 12.5}
|
|
assert player.bio["stealth"] == 3
|
|
assert player.bio["athletics"] == 0
|
|
|
|
left_leg = player.get_body_part("left_leg")
|
|
assert left_leg.integrity == pytest.approx(40.0)
|
|
assert [a.id for a in left_leg.ailments] == ["frostbite"]
|
|
assert left_leg.ailments[0].severity == pytest.approx(0.5)
|
|
|
|
assert player.get_clothing("torso").item_def_id == "leather_jacket"
|
|
backpack = player.get_clothing("back")
|
|
assert backpack.item_def_id == "backpack_basic"
|
|
assert backpack.inventory is not None
|
|
assert (backpack.inventory.width, backpack.inventory.height) == (4, 4)
|
|
assert {p.item.item_id for p in backpack.inventory.items()} == {"rope-1"}
|
|
|
|
|
|
def test_load_world_returns_none_when_no_save_exists(registry):
|
|
repo = WorldRepository(sqlite3.connect(":memory:"))
|
|
loader = MapLoader(DEFS_DIR / "maps")
|
|
assert repo.load_world(registry, loader) is None
|
|
|
|
|
|
def test_runtime_tile_edits_survive_save_and_load(registry):
|
|
world = build_world(registry)
|
|
demo_world = world.maps["demo_world"]
|
|
|
|
# simulate base-building: knock a wall down on the ship, damage a flooring tile elsewhere
|
|
ship = world.maps["ship_small"]
|
|
ship.get_tile(0, 0, 0).room = None
|
|
demo_world.get_tile(3, 3, 0).flooring.integrity = 42.0
|
|
|
|
repo = WorldRepository(sqlite3.connect(":memory:"))
|
|
repo.save_world(world)
|
|
|
|
loader = MapLoader(DEFS_DIR / "maps")
|
|
reloaded = repo.load_world(registry, loader)
|
|
|
|
reloaded_ship = reloaded.maps["ship_small"]
|
|
assert reloaded_ship.get_tile(0, 0, 0).room is None
|
|
|
|
reloaded_demo = reloaded.maps["demo_world"]
|
|
edited_tile = reloaded_demo.get_tile(3, 3, 0)
|
|
assert edited_tile.flooring.def_id == "grass"
|
|
assert edited_tile.flooring.integrity == pytest.approx(42.0)
|