Initial commit
This commit is contained in:
176
tests/test_crush.py
Normal file
176
tests/test_crush.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user