"""Mounting traps on other traps.""" from conftest import step, DT from game.traps import Block, Spike PLATFORM_WITH_SPIKE = """ name: t tile_size: 32 map: | ############ #..........# #..........# #.........G# #P.........# ############ traps: - type: block at: [3, 2] path: [[3, 2], [8, 2]] mode: pingpong speed: 120 sprite: patrol_block mounts: - type: spike at: [0, -1] trigger: always direction: up """ def test_spike_mount_follows_platform(make_game): g = make_game(PLATFORM_WITH_SPIKE) plat = g.level.traps[0] sp = plat.mounts[0] assert isinstance(sp, Spike) for _ in range(30): g.level.update(DT, g) p = plat.current_rect() hz = sp.hazard_rects()[0] # spike sits one tile above the platform and moves with it assert hz.centerx == p.centerx assert hz.bottom <= p.top + 1 def test_block_mounted_on_block(make_game): g = make_game(""" name: t tile_size: 32 map: | ############ #..........# #..........# #.........G# #P.........# ############ traps: - type: block at: [3, 2] path: [[3, 2], [8, 2]] mode: pingpong speed: 120 sprite: patrol_block mounts: - type: block at: [-1, 0] deadly: true - type: block at: [1, 0] deadly: true """) plat = g.level.traps[0] g.level.update(DT, g) for m in plat.mounts: assert m._mounted and m.deadly # each deadly mount tracks the platform at its offset and is lethal exp = (plat.current_rect().x + m._mount_off[0], plat.current_rect().y + m._mount_off[1]) assert (m.current_rect().x, m.current_rect().y) == exp assert m.hazard_rects() MOBILE_MOUNT = """ name: t tile_size: 32 map: | ################ #..............# #..............# #..............# #..............# #P............G# ################ traps: - type: block at: [3, 4] path: [[3, 4], [8, 4]] mode: pingpong speed: 120 sprite: patrol_block mounts: # Rides the patrol AND runs its own upward stroke when armed. - type: block at: [0, -1] move: [0, -3] speed: 240 mode: once trigger: { within: 40 } # player is always in range -> stays extended mounts: - type: spike at: [0, -1] trigger: always direction: up """ def test_block_mount_runs_own_motion_while_riding(make_game): g = make_game(MOBILE_MOUNT) plat = g.level.traps[0] mnt = plat.mounts[0] assert isinstance(mnt, Block) and mnt._mounted tile = g.level.tile # At rest the mount sits one tile above the patrol, tracking its column. assert mnt.current_rect().x == plat.current_rect().x assert mnt.current_rect().top == plat.current_rect().top - tile for _ in range(120): g.level.update(DT, g) pr, mr = plat.current_rect(), mnt.current_rect() # Still rides along horizontally (same column offset as home)... assert mr.x == pr.x # ...but has run its own three-tile upward stroke above the resting spot # (resting = 1 tile up; extended = 1 + 3 tiles up). assert mr.top == pr.top - 4 * tile # It reports as a solid carrier so a rider would be carried. assert mnt.solid_rects() and mnt.carriers() # The spike rides the lunging block, one tile above it. spike = mnt.mounts[0] hz = spike.hazard_rects()[0] assert hz.centerx == mr.centerx and hz.bottom <= mr.top + 1 def test_reset_repositions_mounts(make_game): g = make_game(PLATFORM_WITH_SPIKE) plat = g.level.traps[0] sp = plat.mounts[0] for _ in range(40): g.level.update(DT, g) g.level.reset() # after reset the platform is home and the mount snapped back onto it assert sp.base_rect.centerx == plat.current_rect().centerx