from pathlib import Path import pytest from engine.defs import DefRegistry from engine.entity import Entity, EntityPosition from engine.map import Map from engine.tile import Tile, TileLayerInstance from engine.world import World DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs" @pytest.fixture() def registry(): return DefRegistry.load(DEFS_DIR) def make_cliff_world(registry): """A 2x1 map: x=0 is a 3-level-tall column (floored at z=0,1,2), x=1 has floor only at z=0 - everything above that at x=1 is bare/unset (no flooring), simulating the "open air above a lower column" gap engine/worldgen/terrain.py leaves when no slope/cave connects a steep drop. """ m = Map("cliff", 2, 1, 3) m.set_tile(0, 0, 0, Tile(flooring=TileLayerInstance("stone"))) m.set_tile(0, 0, 1, Tile(flooring=TileLayerInstance("stone"))) m.set_tile(0, 0, 2, Tile(flooring=TileLayerInstance("stone"))) m.set_tile(1, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) # (1, 0, 1) and (1, 0, 2) left as bare Tile() - no flooring world = World(registry=registry) world.add_map(m) return world def test_stepping_off_a_cliff_falls_straight_to_the_floor_below(registry): world = make_cliff_world(registry) walker = Entity(position=EntityPosition("cliff", 0, 0, 2)) assert world.try_move(walker, 1, 0, 0) is True assert (walker.position.x, walker.position.y, walker.position.z) == (1, 0, 0) def test_falling_skips_multiple_floorless_levels_to_the_first_real_floor(registry): world = make_cliff_world(registry) walker = Entity(position=EntityPosition("cliff", 0, 0, 1)) assert world.try_move(walker, 1, 0, 0) is True assert walker.position.z == 0 def test_moving_between_two_floored_tiles_does_not_trigger_gravity(registry): m = Map("level", 2, 1, 1) m.set_tile(0, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) m.set_tile(1, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) world = World(registry=registry) world.add_map(m) walker = Entity(position=EntityPosition("level", 0, 0, 0)) assert world.try_move(walker, 1, 0, 0) is True assert walker.position.z == 0 def test_gravity_also_applies_after_continuous_movement(registry): world = make_cliff_world(registry) walker = Entity(position=EntityPosition("cliff", 0.5, 0, 2)) assert world.try_move_continuous(walker, 1, 0, 0, distance=1.0) is True assert walker.position.z == 0 def test_gravity_does_not_fire_on_a_single_level_map(registry): m = Map("flat", 2, 1, 1) m.set_tile(0, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) m.set_tile(1, 0, 0, Tile()) # bare, but nothing below z=0 to fall to world = World(registry=registry) world.add_map(m) walker = Entity(position=EntityPosition("flat", 0, 0, 0)) assert world.try_move(walker, 1, 0, 0) is True assert (walker.position.x, walker.position.z) == (1, 0) # stays put, no lower floor exists def test_consume_fall_distance_reports_how_far_and_then_resets(registry): world = make_cliff_world(registry) walker = Entity(position=EntityPosition("cliff", 0, 0, 2)) assert world.consume_fall_distance(walker.entity_id) == 0 # nothing yet world.try_move(walker, 1, 0, 0) assert world.consume_fall_distance(walker.entity_id) == 2 # dropped from z=2 to z=0 assert world.consume_fall_distance(walker.entity_id) == 0 # one-shot, already consumed def test_consume_fall_distance_is_zero_when_no_fall_happens(registry): m = Map("level", 2, 1, 1) m.set_tile(0, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) m.set_tile(1, 0, 0, Tile(flooring=TileLayerInstance("dirt"))) world = World(registry=registry) world.add_map(m) walker = Entity(position=EntityPosition("level", 0, 0, 0)) world.try_move(walker, 1, 0, 0) assert world.consume_fall_distance(walker.entity_id) == 0