96 lines
4.2 KiB
Python
96 lines
4.2 KiB
Python
import pytest
|
|
|
|
from engine.entity import Entity, EntityPosition
|
|
from engine.map import Map
|
|
from engine.tile import Tile, TileLayerDef, TileLayerInstance
|
|
from engine.world import World
|
|
|
|
|
|
class FakeRegistry:
|
|
def get_tile_layer_def(self, layer, def_id):
|
|
if layer == "room" and def_id == "stairs_up":
|
|
return TileLayerDef(id="stairs_up", layer="room", walkable=True, staircase_direction="up")
|
|
if layer == "room" and def_id == "stairs_down":
|
|
return TileLayerDef(id="stairs_down", layer="room", walkable=True, staircase_direction="down")
|
|
if layer == "room" and def_id == "wood_wall":
|
|
return TileLayerDef(id="wood_wall", layer="room", walkable=False)
|
|
return None
|
|
|
|
|
|
def make_two_story_map():
|
|
tower = Map("tower", 3, 3, 2)
|
|
for x in range(3):
|
|
for y in range(3):
|
|
for z in range(2):
|
|
tower.set_tile(x, y, z, Tile(flooring=TileLayerInstance("wood_deck")))
|
|
tower.get_tile(1, 1, 0).room = TileLayerInstance("stairs_up")
|
|
tower.get_tile(1, 1, 1).room = TileLayerInstance("stairs_down")
|
|
|
|
world = World(registry=FakeRegistry())
|
|
world.add_map(tower)
|
|
return world, tower
|
|
|
|
|
|
def test_tile_staircase_direction_reads_room_layer():
|
|
tower = make_two_story_map()[1]
|
|
registry = FakeRegistry()
|
|
assert tower.get_tile(1, 1, 0).staircase_direction(registry) == "up"
|
|
assert tower.get_tile(1, 1, 1).staircase_direction(registry) == "down"
|
|
assert tower.get_tile(0, 0, 0).staircase_direction(registry) is None
|
|
|
|
|
|
def test_walking_onto_stairs_up_carries_entity_to_next_floor():
|
|
world, _tower = make_two_story_map()
|
|
player = Entity(position=EntityPosition("tower", 0, 1, 0))
|
|
assert world.try_move(player, 1, 0, 0) is True
|
|
assert (player.position.x, player.position.y, player.position.z) == (1, 1, 1)
|
|
|
|
|
|
def test_walking_onto_stairs_down_carries_entity_to_floor_below():
|
|
world, _tower = make_two_story_map()
|
|
player = Entity(position=EntityPosition("tower", 0, 1, 1))
|
|
assert world.try_move(player, 1, 0, 0) is True
|
|
assert (player.position.x, player.position.y, player.position.z) == (1, 1, 0)
|
|
|
|
|
|
def test_landing_on_staircase_does_not_cascade_further():
|
|
# standing on the stairs_down tile at z=1 doesn't repeatedly bounce back down on each call
|
|
world, _tower = make_two_story_map()
|
|
player = Entity(position=EntityPosition("tower", 1, 1, 1))
|
|
# a no-op self-check: player is already there; simulate a step off and back via two moves
|
|
assert world.try_move(player, 1, 0, 0) is True # off the stairs, to (2,1,1)
|
|
assert player.position.z == 1
|
|
assert world.try_move(player, -1, 0, 0) is True # back onto stairs_down at (1,1,1)
|
|
assert player.position.z == 0 # single hop down, landed on ground floor
|
|
|
|
|
|
def test_staircase_at_top_floor_edge_does_not_crash_or_move_out_of_bounds():
|
|
tower = Map("tower", 3, 3, 1) # only one floor - "up" has nowhere to go
|
|
for x in range(3):
|
|
for y in range(3):
|
|
tower.set_tile(x, y, 0, Tile(flooring=TileLayerInstance("wood_deck")))
|
|
tower.get_tile(1, 1, 0).room = TileLayerInstance("stairs_up")
|
|
world = World(registry=FakeRegistry())
|
|
world.add_map(tower)
|
|
|
|
player = Entity(position=EntityPosition("tower", 0, 1, 0))
|
|
assert world.try_move(player, 1, 0, 0) is True
|
|
assert (player.position.x, player.position.y, player.position.z) == (1, 1, 0) # stayed put, no crash
|
|
|
|
|
|
def test_staircase_blocked_if_target_floor_tile_unwalkable():
|
|
world, tower = make_two_story_map()
|
|
tower.get_tile(1, 1, 1).room = TileLayerInstance("wood_wall") # block the landing spot above
|
|
player = Entity(position=EntityPosition("tower", 0, 1, 0))
|
|
assert world.try_move(player, 1, 0, 0) is True # the horizontal step itself still succeeds
|
|
assert (player.position.x, player.position.y, player.position.z) == (1, 1, 0) # but no ascent
|
|
|
|
|
|
def test_continuous_move_onto_staircase_also_transitions_floor():
|
|
world, _tower = make_two_story_map()
|
|
player = Entity(position=EntityPosition("tower", 0.3, 1.4, 0))
|
|
assert world.try_move_continuous(player, 1, 0, 0, distance=0.8) is True
|
|
assert player.position.z == 1
|
|
assert player.position.x == pytest.approx(1.1)
|
|
assert player.position.y == pytest.approx(1.4)
|