test: cover tests.aMonsterSteppingOntoAPlayerSetTrapSpringsIt
This commit is contained in:
1 parent
4d07d9597f
commit
a408c1ebfc
1 file changed
+173
+173
@@ -4627,6 +4627,179 @@ function tests.plantingATrapWhereOneAlreadyExistsFails()
|
||||
game.level.traps = { { x = 5, y = 5, effect = "poison", revealed = false } }
|
||||
game.player.inventory = { Items.kit("dart") }
|
||||
ok(not game:useItem(1), "planting a trap on an occupied tile fails")
|
||||
eq(#game.player.inventory, 1, "a failed planting leaves the kit in the inventory")
|
||||
end
|
||||
|
||||
function tests.aMonsterSteppingOntoAPlayerSetTrapSpringsIt()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.level.traps = { { x = 6, y = 6, effect = "dart", revealed = false, placedByPlayer = true } }
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 7, 6, 1)
|
||||
game.level.entities = { orc }
|
||||
local hpBefore = orc.hp
|
||||
game:stepMonsterToward(orc, game.player.x, game.player.y)
|
||||
eq(orc.x, 6, "the orc steps onto the trapped cell while closing on the player")
|
||||
ok(orc.hp < hpBefore, "stepping onto a player-set dart trap wounds the monster")
|
||||
eq(game.level.traps[1].revealed, true, "the sprung trap becomes revealed")
|
||||
end
|
||||
|
||||
-- Status.LEVITATE (see status.lua) makes Game:checkTrapFor and movePlayer's
|
||||
-- own inline trap check both bail out before springTrap ever runs - and,
|
||||
-- unlike the lava/chasm skip in checkTerrainFor, deliberately leaves the
|
||||
-- trap unrevealed: floating clear of a pressure plate buys safety, not free
|
||||
-- detection of what was under it.
|
||||
function tests.checkTrapForSkipsAndLeavesUndetectedForALevitatingMonster()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.level.traps = { { x = 6, y = 6, effect = "dart", revealed = false } }
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 7, 6, 1)
|
||||
Status.apply(orc, Status.LEVITATE, 20, 1)
|
||||
game.level.entities = { orc }
|
||||
local hpBefore = orc.hp
|
||||
game:stepMonsterToward(orc, game.player.x, game.player.y)
|
||||
eq(orc.x, 6, "the levitating orc still steps onto the trapped cell while closing on the player")
|
||||
eq(orc.hp, hpBefore, "a levitating monster drifting over a trap takes no damage from it")
|
||||
eq(game.level.traps[1].revealed, false, "the trap it floated over is never revealed")
|
||||
end
|
||||
|
||||
function tests.movePlayerSkipsTheInlineTrapTriggerForALevitatingPlayer()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.level.traps = { { x = 6, y = 5, effect = "dart", revealed = false } }
|
||||
Status.apply(game.player, Status.LEVITATE, 20, 1)
|
||||
local hpBefore = game.player.hp
|
||||
game:movePlayer(1, 0)
|
||||
eq(game.player.x, 6, "the levitating player still moves onto the trapped cell")
|
||||
eq(game.player.hp, hpBefore, "a levitating player takes no damage from the trap")
|
||||
eq(game.level.traps[1].revealed, false, "the trap the player floated over stays hidden")
|
||||
end
|
||||
|
||||
function tests.aLethalTrapKillsAWeakMonsterAndCreditsThePlayer()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.level.traps = { { x = 6, y = 6, effect = "dart", revealed = false } }
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 7, 6, 1)
|
||||
rat.hp, rat.maxHp = 1, 1
|
||||
game.level.entities = { rat }
|
||||
local xpBefore = game.player.xp
|
||||
game:stepMonsterToward(rat, game.player.x, game.player.y)
|
||||
ok(not rat:isAlive(), "a dart trap can finish off a weak monster")
|
||||
ok(game.player.xp > xpBefore, "the player is credited xp for a trap kill")
|
||||
eq(#game.level.entities, 0, "the fallen monster is swept from the level")
|
||||
end
|
||||
|
||||
function tests.aTeleportTrapRelocatesTheMonsterThatSpringsIt()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.level.traps = { { x = 6, y = 6, effect = "teleport", revealed = false } }
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 7, 6, 1)
|
||||
game.level.entities = { orc }
|
||||
game:stepMonsterToward(orc, game.player.x, game.player.y)
|
||||
ok(not (orc.x == 6 and orc.y == 6), "a teleport trap relocates the monster off the trapped cell")
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyPlacesATrapKitFromDepthTwo()
|
||||
local level = Builder.build(3, Rng.new(3), {})
|
||||
local found
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.kind == Items.KIT then found = ground.item end
|
||||
end
|
||||
ok(found ~= nil, "this seed's depth-3 floor places a trap kit")
|
||||
local isKnownEffect = false
|
||||
for _, effect in ipairs(Builder.TRAP_EFFECTS) do
|
||||
if found.effect == effect then isKnownEffect = true end
|
||||
end
|
||||
ok(isKnownEffect, "the kit's effect is one of Builder.TRAP_EFFECTS")
|
||||
end
|
||||
|
||||
function tests.kitsStayOffTheEntranceFloor()
|
||||
for seed = 1, 5 do
|
||||
local level = Builder.build(1, Rng.new(seed), {})
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
ok(ground.item.kind ~= Items.KIT, "no trap kit appears on the entrance floor")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function tests.plantedTrapFieldsSurviveSerialization()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.player.inventory = { Items.kit("poison") }
|
||||
game:useItem(1)
|
||||
local restoredLevel = Level.fromData(game.level:toData())
|
||||
eq(#restoredLevel.traps, 1, "the planted trap survives a level round trip")
|
||||
eq(restoredLevel.traps[1].effect, "poison", "the planted trap's effect survives a round trip")
|
||||
eq(restoredLevel.traps[1].placedByPlayer, true, "the planted trap's origin flag survives a round trip")
|
||||
end
|
||||
|
||||
function tests.bossCreateBuildsAFreshUnenragedBoss()
|
||||
local warlord = Bosses.create(Bosses.byKey.warlord, 9, 4, 6)
|
||||
eq(warlord.isBoss, true, "a created boss is flagged isBoss")
|
||||
eq(warlord.bossKey, "warlord", "a created boss remembers its catalog key")
|
||||
eq(warlord.enraged, false, "a freshly created boss has not yet enraged")
|
||||
eq(warlord.hp, warlord.maxHp, "a created boss starts at full hp")
|
||||
eq(warlord.species, "boss_warlord", "a created boss's species is namespaced away from Monsters.byKey")
|
||||
end
|
||||
|
||||
function tests.bossAtFullHealthDoesNotEnrage()
|
||||
local warlord = Bosses.create(Bosses.byKey.warlord, 1, 1, 1)
|
||||
local before = warlord.attack
|
||||
local line = Bosses.tryEnrage(warlord)
|
||||
eq(line, nil, "a boss above its enrage threshold does not enrage")
|
||||
eq(warlord.enraged, false, "the boss is still marked as not enraged")
|
||||
eq(warlord.attack, before, "an unenraged boss keeps its base attack")
|
||||
end
|
||||
|
||||
function tests.bossEnragesOncePastItsHalfHpThresholdAndOnlyOnce()
|
||||
local warlord = Bosses.create(Bosses.byKey.warlord, 1, 1, 1)
|
||||
local spec = Bosses.byKey.warlord
|
||||
warlord.hp = math.floor(warlord.maxHp * spec.enrageAt)
|
||||
local attackBefore, speedBefore = warlord.attack, warlord.speed
|
||||
local line = Bosses.tryEnrage(warlord)
|
||||
ok(line ~= nil, "a bloodied boss enrages and logs a line")
|
||||
eq(warlord.enraged, true, "the boss is now flagged enraged")
|
||||
eq(warlord.attack, attackBefore + spec.enrageAttack, "enraging adds the catalog's flat attack bonus")
|
||||
eq(warlord.baseAttack, attackBefore + spec.enrageAttack, "enraging also lifts the boss's base attack")
|
||||
eq(warlord.speed, speedBefore + spec.enrageSpeed, "enraging adds the catalog's flat speed bonus")
|
||||
local hpAfterFirst = warlord.hp
|
||||
local second = Bosses.tryEnrage(warlord)
|
||||
eq(second, nil, "an already-enraged boss does not enrage a second time")
|
||||
eq(warlord.attack, attackBefore + spec.enrageAttack, "a second call never stacks the attack bonus again")
|
||||
eq(warlord.hp, hpAfterFirst, "a second call grants no further heal")
|
||||
end
|
||||
|
||||
function tests.bossLootMatchesItsCatalogEntry()
|
||||
local lich = Bosses.create(Bosses.byKey.lich, 1, 1, 1)
|
||||
local loot = Bosses.lootFor(lich)
|
||||
ok(loot ~= nil, "a boss with a valid bossKey drops its catalog loot")
|
||||
eq(loot.artifact, "lich_phylactery", "the dropped item is the boss's exact catalog artifact")
|
||||
eq(loot.unique, Artifacts.REGEN, "the boss loot carries its unique mechanic tag")
|
||||
local unknown = Bosses.create({ key = "ghost" }, 1, 1, 1)
|
||||
unknown.bossKey = "ghost"
|
||||
eq(Bosses.lootFor(unknown), nil, "a boss with no catalog entry drops nothing")
|
||||
end
|
||||
|
||||
function tests.bossOnlyArtifactsAreExcludedFromTheRandomBuilderRoll()
|
||||
local bossOnlyKeys = { "warlords_cleaver", "lich_phylactery", "bone_queen_carapace" }
|
||||
for _, key in ipairs(bossOnlyKeys) do
|
||||
ok(Artifacts.byKey[key] ~= nil, key .. " is a real catalog entry")
|
||||
local inOrder = false
|
||||
for _, orderKey in ipairs(Artifacts.order) do
|
||||
if orderKey == key then inOrder = true end
|
||||
end
|
||||
ok(not inOrder, key .. " never appears in the builder's random artifact roll")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyPlacesABossFromDepthSix()
|
||||
local level = Builder.build(6, Rng.new(8), {})
|
||||
local found
|
||||
for _, entity in ipairs(level.entities) do
|
||||
if entity.isBoss then found = entity end
|
||||
end
|
||||
ok(found ~= nil, "this seed's depth-6 floor places a named boss")
|
||||
eq(found.bossKey, "warlord", "the only boss eligible at depth 6 is the warlord")
|
||||
end
|
||||
|
||||
function tests.bossesStayOffFloorsAboveDepthSix()
|
||||
for seed = 1, 5 do
|
||||
for depth = 1, 5 do
|
||||
local level = Builder.build(depth, Rng.new(seed), {})
|
||||
for _, entity in ipairs(level.entities) do
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user