Files
battery/tests/test_crush.py
James Campbell d84e4627c3 Initial commit
2026-07-21 19:36:02 -04:00

177 lines
3.8 KiB
Python

"""Crush death, shove/carry interactions, and the collision-resolution
regressions (corner warp, fits-under, cliff-shove)."""
from conftest import step, run, place, hold
def until_crushed(g, frames=200):
for _ in range(frames):
if g.state != "playing":
break
step(g)
if g.player.crushed:
return True
return False
def test_descend_crush(make_game):
g = make_game("""
name: t
tile_size: 32
map: |
#####
#...#
#P.G#
#####
traps:
- type: block
at: [1, 1]
move: [0, 2]
speed: 200
trigger: { within: 20 }
""")
# player stands on the floor under the descending block
assert until_crushed(g, 120)
def test_fits_under_no_false_crush(make_game):
# A block that stops with clearance must NOT crush a grounded player.
g = make_game("""
name: t
tile_size: 32
map: |
#####
#...#
#...#
#P.G#
#####
traps:
- type: block
at: [1, 1]
move: [0, 1]
speed: 160
trigger: { within: 20 }
""")
place(g, 1, 2)
for _ in range(120):
step(g)
assert not g.player.crushed
def test_shove_into_wall_crushes(make_game):
g = make_game("""
name: t
tile_size: 32
map: |
#######
#....G#
#.....#
#######
traps:
- type: block
at: [2, 2]
path: [[2, 2], [6, 2]]
mode: pingpong
speed: 200
""")
# player pinned against the right wall
place(g, 5, 2)
g.player.fx = float(6 * 32 - g.player.w)
g.player._sync_rect()
assert until_crushed(g)
def test_shove_along_not_into_floor(make_game):
# A block moving horizontally into a grounded player shoves them sideways,
# never buries them in the floor.
g = make_game("""
name: t
tile_size: 32
map: |
############
#..........#
#..........#
#.........G#
############
traps:
- type: block
at: [8, 3]
path: [[8, 3], [2, 3]]
mode: pingpong
speed: 160
""")
place(g, 4, 3) # on the floor, at the block's body level
floor_top = 4 * 32
start_x = g.player.rect.x
max_bottom = g.player.rect.bottom
for _ in range(120):
step(g)
max_bottom = max(max_bottom, g.player.rect.bottom)
if g.state != "playing":
break
assert max_bottom <= floor_top + 1 # never pushed into the floor
assert g.player.rect.x < start_x # got shoved along
def test_corner_clip_does_not_warp(make_game):
# Walking into a moving block near its corner must not fling the player
# across it (the old velocity-sign resolver bug).
g = make_game("""
name: t
tile_size: 32
map: |
#########
#.......#
#.......#
#.......#
#P.....G#
#########
traps:
- type: block
at: [5, 2]
path: [[5, 2], [2, 2]]
mode: pingpong
speed: 150
""")
place(g, 4, 3)
prev = g.player.rect.x
for _ in range(120):
step(g, hold(left=True))
assert g.player.rect.x - prev <= 28 # no sudden rightward warp
prev = g.player.rect.x
def test_cliff_shove_falls_on_first_pass(make_game):
# A block sweeping the player toward a ledge should push them off on the
# first pass (before it turns around).
g = make_game("""
name: t
tile_size: 32
map: |
###########
#.........#
#.........#
######....#
traps:
- type: block
at: [1, 2]
path: [[1, 2], [8, 2]]
mode: pingpong
speed: 150
""")
b = g.level.traps[0]
place(g, 4, 2)
reversalsN, pd, left_at = 0, 1, None
for i in range(240):
step(g)
if g.state != "playing":
break
d = 1 if b.x > b.prev[0] else (-1 if b.x < b.prev[0] else pd)
if d != pd:
reversalsN += 1
pd = d
if not g.player.on_ground and g.player.rect.bottom > 3 * 32:
left_at = reversalsN
break
assert left_at == 0 # fell before any block reversal