extends GutTest ## Invariants every piece of content has to satisfy. These are cheap to write ## and they are what stops a new enemy from quietly reintroducing a mechanic the ## game has decided against. const HOSTILES := [ Content.ENEMY_DRIFTER, Content.ENEMY_TURRET, Content.ENEMY_STALKER, ] ## The rule: nothing in this game hurts you by touching you. Every threat is a ## bullet you can see and dodge, so an enemy with no emitters is either inert ## scenery or a design mistake. func test_every_hostile_enemy_actually_fires_something() -> void: for id in HOSTILES: var def := Content.enemy(id) assert_gt(def.emitters.size(), 0, "%s has no emitters -- it would be a harmless obstacle" % id) func test_the_practice_dummy_is_inert() -> void: var def := Content.enemy(Content.ENEMY_DUMMY) assert_eq(def.emitters.size(), 0, "the hub target must never shoot back") ## Standing inside an enemy costs nothing by itself. Uses the dummy so the test ## measures contact alone, with no bullets in play to confuse the result. func test_touching_an_enemy_deals_no_damage() -> void: var world := SimWorld.new(1) var p := world.add_player(1, "tester") var e := world.spawn_enemy(Content.dummy(), Vector2.ZERO) p.pos = e.pos p.spawn_grace = 0 for _i in 120: world.step() assert_eq(p.hp, SimConfig.PLAYER_MAX_HP, "contact damage is not a damage type in this game") ## The Stalker's burst replaces its old contact damage, so it has to be a real ## threat once it closes -- and harmless from across the arena. func test_the_stalker_threatens_at_point_blank_only() -> void: var near := SimWorld.new(1) var pn := near.add_player(1, "tester") pn.pos = Vector2.ZERO pn.spawn_grace = 0 near.spawn_enemy(Content.stalker(), Vector2(40.0, 0.0)) for _i in 90: near.step() assert_lt(pn.hp, SimConfig.PLAYER_MAX_HP, "point blank has to hurt") var far := SimWorld.new(1) var pf := far.add_player(1, "tester") pf.pos = Vector2(0.0, 300.0) pf.spawn_grace = 0 # Pinned in place so it cannot close the distance during the test. var e := far.spawn_enemy(Content.stalker(), Vector2(0.0, -300.0)) e.def = Content.stalker() e.def.speed = 0.0 for _i in 90: far.step() assert_eq(pf.hp, SimConfig.PLAYER_MAX_HP, "its bullets must expire long before they cross the arena") func test_enemy_bullets_from_the_stalker_do_not_litter_the_arena() -> void: var world := SimWorld.new(1) var p := world.add_player(1, "tester") p.pos = Vector2(0.0, 300.0) var e := world.spawn_enemy(Content.stalker(), Vector2(0.0, -300.0)) e.def = Content.stalker() e.def.speed = 0.0 for _i in 300: world.step() assert_lt(world.pool.live_count, 12, "a short lifetime should keep spent point-blank shots from accumulating")