Mi2dRPGamEng/tests/test_map_embedding.py

142 lines
5.2 KiB
Python

from engine.entity import Entity, EntityPosition
from engine.map import Map
from engine.tile import Tile, TileLayerDef, TileLayerInstance
from engine.world import World
def make_world():
parent = Map("world", 10, 10, 1)
child = Map("ship", 4, 3, 1)
for x in range(4):
for y in range(3):
child.set_tile(x, y, 0, Tile(flooring=TileLayerInstance("wood_deck")))
# leave (2, 0, 0) open as the doorway, wall the rest of the front/back/sides
for x, y in [(0, 0), (1, 0), (3, 0), (0, 2), (3, 2)]:
tile = child.get_tile(x, y, 0)
tile.room = TileLayerInstance("wood_wall")
for x in range(10):
for y in range(10):
parent.set_tile(x, y, 0, Tile(flooring=TileLayerInstance("grass")))
parent.embed(child, (6, 6, 0))
return parent, child
def test_local_to_parent_and_back_are_inverses():
_parent, child = make_world()
embedding = child.parent_embedding
for lx, ly, lz in [(0, 0, 0), (2, 0, 0), (3, 2, 0)]:
px, py, pz = embedding.local_to_parent(lx, ly, lz)
assert embedding.parent_to_local(px, py, pz) == (lx, ly, lz)
def test_embedding_at_detects_child_footprint():
parent, child = make_world()
embedding = child.parent_embedding
assert parent.embedding_at(8, 6, 0) is embedding # inside ship footprint (6..9, 6..8)
assert parent.embedding_at(0, 0, 0) is None # outside ship footprint
class FakeRegistry:
def get_tile_layer_def(self, layer, def_id):
if layer == "room" and def_id == "wood_wall":
return TileLayerDef(id="wood_wall", layer="room", walkable=False, blocks_los=True)
return None
def test_try_move_boards_ship_from_parent_map():
parent, child = make_world()
world = World()
world.maps = {"world": parent, "ship": child}
world.registry = FakeRegistry()
player = Entity(position=EntityPosition("world", 7, 5, 0)) # just below the doorway at (8,6)
assert world.try_move(player, 1, 1, 0) is True
assert player.position.map_id == "ship"
assert (player.position.x, player.position.y, player.position.z) == (2, 0, 0)
def test_try_move_disembarks_ship_back_to_parent_map():
parent, child = make_world()
world = World()
world.maps = {"world": parent, "ship": child}
world.registry = FakeRegistry()
# standing in the doorway (ship-local 2,0,0), step north off the ship's edge
player = Entity(position=EntityPosition("ship", 2, 0, 0))
assert world.try_move(player, 0, -1, 0) is True
assert player.position.map_id == "world"
assert (player.position.x, player.position.y, player.position.z) == (8, 5, 0)
def test_try_move_blocked_by_wall():
parent, child = make_world()
world = World()
world.maps = {"world": parent, "ship": child}
world.registry = FakeRegistry()
player = Entity(position=EntityPosition("ship", 1, 1, 0))
assert world.try_move(player, -1, -1, 0) is False # (0,0) is a wood_wall
assert player.position.map_id == "ship"
assert (player.position.x, player.position.y, player.position.z) == (1, 1, 0)
def test_rotated_embedding_local_to_parent_and_back_are_inverses():
_parent, child = make_world()
embedding = child.parent_embedding
embedding.rotate_to(1) # 90 degrees clockwise: 4x3 footprint becomes 3x4
assert embedding.footprint_size() == (3, 4)
for lx, ly, lz in [(0, 0, 0), (2, 0, 0), (3, 2, 0), (1, 1, 0)]:
px, py, pz = embedding.local_to_parent(lx, ly, lz)
assert embedding.parent_to_local(px, py, pz) == (lx, ly, lz)
def test_boarding_still_works_after_ship_rotates():
parent, child = make_world()
embedding = child.parent_embedding
embedding.rotate_to(1)
world = World()
world.maps = {"world": parent, "ship": child}
world.registry = FakeRegistry()
# the doorway (ship-local 2,0) now lands at a different parent cell post-rotation
door_parent = embedding.local_to_parent(2, 0, 0)
approach = (door_parent[0] - 1, door_parent[1] - 1, 0)
player = Entity(position=EntityPosition("world", *approach))
assert world.try_move(player, 1, 1, 0) is True
assert player.position.map_id == "ship"
assert (player.position.x, player.position.y, player.position.z) == (2, 0, 0)
def test_moving_and_rotating_ship_does_not_touch_aboard_entities_local_position():
_parent, child = make_world()
embedding = child.parent_embedding
sailor = Entity(position=EntityPosition("ship", 2, 1, 0))
original_local = (sailor.position.x, sailor.position.y, sailor.position.z)
embedding.move_to((0, 0, 0))
embedding.rotate_to(2)
assert (sailor.position.x, sailor.position.y, sailor.position.z) == original_local
def test_disembarking_resolves_against_current_anchor_after_ship_moves():
parent, child = make_world()
embedding = child.parent_embedding
world = World()
world.maps = {"world": parent, "ship": child}
world.registry = FakeRegistry()
embedding.move_to((5, 5, 0)) # ship has sailed elsewhere since boarding
player = Entity(position=EntityPosition("ship", 2, 0, 0))
assert world.try_move(player, 0, -1, 0) is True
assert player.position.map_id == "world"
# disembarks relative to the ship's *current* anchor, not the original (6,6,0)
assert (player.position.x, player.position.y, player.position.z) == (7, 4, 0)