"""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