extends GutTest ## Progression through a whole dungeon instance: forming, two trash waves, the ## boss, and the cleared state that sends the party home. var inst: Instance func before_each() -> void: inst = Instance.make_dungeon(2, 12345) inst.add_peer(1, "tester") func _step(n: int) -> void: for _i in n: inst.step() func _kill_all_enemies() -> void: for e in inst.world.enemies.values(): e.alive = false func test_a_forming_dungeon_locks_after_the_window() -> void: assert_eq(inst.state, Instance.State.FORMING) _step(SimConfig.DUNGEON_FORMING_TICKS + 2) assert_eq(inst.state, Instance.State.ACTIVE) func test_a_full_party_locks_the_dungeon_immediately() -> void: for peer in range(2, 2 + SimConfig.DUNGEON_PARTY_MAX - 1): inst.add_peer(peer, "p%d" % peer) _step(2) assert_eq(inst.state, Instance.State.ACTIVE) assert_false(inst.accepts_new_party_member()) func test_waves_gate_on_clearing_the_previous_one() -> void: _step(SimConfig.DUNGEON_FORMING_TICKS + 200) assert_eq(inst.stage, 0) var wave_one := inst.world.enemies.size() assert_gt(wave_one, 0) _step(200) assert_eq(inst.stage, 0, "a slow party must never be overrun by the next wave") _kill_all_enemies() _step(120) assert_eq(inst.stage, 1) assert_gt(inst.world.enemies.size(), wave_one) func test_the_boss_arrives_after_the_last_wave() -> void: _step(SimConfig.DUNGEON_FORMING_TICKS + 200) for _wave in 2: _kill_all_enemies() _step(120) assert_eq(inst.stage, 2) assert_not_null(inst.world.boss) assert_eq(inst.world.boss.def.id, Content.BOSS_WARDEN) func test_killing_the_boss_clears_the_instance() -> void: _step(SimConfig.DUNGEON_FORMING_TICKS + 200) for _wave in 2: _kill_all_enemies() _step(120) inst.world.boss.alive = false _step(5) assert_eq(inst.state, Instance.State.CLEARED) assert_almost_eq(inst.exit_countdown_seconds(), SimConfig.DUNGEON_CLEARED_EXIT_TICKS / SimConfig.TICK_RATE, 1, "the party gets a visible countdown, not an instant boot") # The exit timer has to run down, or the party would never be released. _step(SimConfig.DUNGEON_CLEARED_EXIT_TICKS + 10) assert_eq(inst.stage_delay, 0) assert_eq(inst.exit_countdown_seconds(), 0) func test_the_lobby_has_a_portal_and_no_hostiles() -> void: var lobby := Instance.make_lobby(SimConfig.LOBBY_INSTANCE_ID) lobby.add_peer(1, "tester") assert_true(lobby.world.portal_enabled) _step(1) for _i in 600: lobby.step() assert_eq(lobby.world.pool.live_count, 0, "nothing in the hub may shoot at you") assert_eq(lobby.world.players[1].hp, SimConfig.PLAYER_MAX_HP) func test_interacting_on_the_portal_asks_for_a_dungeon() -> void: var lobby := Instance.make_lobby(SimConfig.LOBBY_INSTANCE_ID) lobby.add_peer(1, "tester") lobby.world.players[1].pos = SimConfig.PORTAL_POS var frames: Array[InputFrame] = [ InputFrame.make(lobby.world.tick + 1, Vector2.ZERO, 0.0, InputFrame.BTN_INTERACT)] lobby.world.queue_input(1, frames) lobby.step() var used := lobby.world.events.filter( func(e: Dictionary) -> bool: return int(e["t"]) == SimEvent.Type.PORTAL_USED) assert_eq(used.size(), 1) func test_interacting_away_from_the_portal_does_nothing() -> void: var lobby := Instance.make_lobby(SimConfig.LOBBY_INSTANCE_ID) lobby.add_peer(1, "tester") lobby.world.players[1].pos = SimConfig.PORTAL_POS + Vector2(0.0, SimConfig.PORTAL_RADIUS + 50.0) var frames: Array[InputFrame] = [ InputFrame.make(lobby.world.tick + 1, Vector2.ZERO, 0.0, InputFrame.BTN_INTERACT)] lobby.world.queue_input(1, frames) lobby.step() var used := lobby.world.events.filter( func(e: Dictionary) -> bool: return int(e["t"]) == SimEvent.Type.PORTAL_USED) assert_eq(used.size(), 0)