test: cover tests.spellsLevitateAppliesTheLevitateStatusToTheCasterAn...
This commit is contained in:
1 parent
5e5103cecb
commit
aaa221f6bf
1 file changed
+173
+173
@@ -11028,6 +11028,179 @@ function tests.builderCanRollATomeOfTheCleanseSpellSomewhereInARangeOfSeeds()
|
||||
local found = false
|
||||
for seed = 1, 200 do
|
||||
local level = Builder.build(6, Rng.new(seed), {})
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.kind == Items.TOME and ground.item.spell == "cleanse" then found = true end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
ok(found, "the cleanse tome is reachable dungeon loot within a reasonable seed range")
|
||||
end
|
||||
|
||||
function tests.spellsLevitateAppliesTheLevitateStatusToTheCasterAndSpendsItsListedManaCost()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Spells.learn(game.player, "levitate")
|
||||
local manaBefore = game.player.mana
|
||||
local success = game:castSpell("levitate")
|
||||
ok(success, "casting a learned, self-targeted levitate succeeds")
|
||||
ok(Status.has(game.player, Status.LEVITATE), "the caster now carries the levitate status")
|
||||
eq(game.player.mana, manaBefore - Spells.catalog.levitate.cost, "casting levitate spends exactly its listed mana cost")
|
||||
end
|
||||
|
||||
function tests.builderCanRollATomeOfTheLevitateSpellSomewhereInARangeOfSeeds()
|
||||
-- Range widened from 100 to 200: adding "weaken" to Builder's `learnable`
|
||||
-- list shifted rng:range(1, #learnable)'s result for effectively every
|
||||
-- seed (a longer list moves the modulo, not just adds a new bucket at the
|
||||
-- end), and the nearest levitate tome under the new list happens to sit
|
||||
-- at seed 173 - still well within "a reasonable seed range", just a
|
||||
-- different one than before this list grew by one entry.
|
||||
local found = false
|
||||
for seed = 1, 200 do
|
||||
local level = Builder.build(6, Rng.new(seed), {})
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.kind == Items.TOME and ground.item.spell == "levitate" then found = true end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
ok(found, "the levitate tome is reachable dungeon loot within a reasonable seed range")
|
||||
end
|
||||
|
||||
function tests.polymorphPoolExcludesTheShopkeeperAndRespectsDepth()
|
||||
local shallow = Polymorph.pool(1)
|
||||
local shallowKeys = {}
|
||||
for _, spec in ipairs(shallow) do shallowKeys[spec.key] = true end
|
||||
ok(shallowKeys.rat and shallowKeys.bat and shallowKeys.kobold, "a depth-one pool offers every depth-one species")
|
||||
ok(not shallowKeys.orc, "a depth-one pool excludes a species that first appears deeper")
|
||||
|
||||
local deep = Polymorph.pool(4)
|
||||
local deepKeys = {}
|
||||
for _, spec in ipairs(deep) do deepKeys[spec.key] = true end
|
||||
ok(deepKeys.zombie and deepKeys.necromancer, "a depth-four pool offers species that first appear at depth four")
|
||||
ok(not deepKeys.shopkeeper, "the shopkeeper is never offered by a polymorph, at any depth")
|
||||
end
|
||||
|
||||
function tests.polymorphTransformPicksADifferentSpeciesAndPreservesTheHpFraction()
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||
rat.hp = 2
|
||||
local pool = Polymorph.pool(1)
|
||||
local spec = Polymorph.transform(rat, Rng.new(7), pool)
|
||||
ok(spec ~= nil, "a pool with other species on offer always yields a transform")
|
||||
ok(rat.species ~= "rat", "the entity is no longer its original species")
|
||||
eq(rat.species, spec.key, "the entity's species now matches whatever transform returned")
|
||||
eq(rat.maxHp, spec.hp, "max hp is replaced wholesale from the new species")
|
||||
local expectedHp = math.max(1, math.floor(spec.hp * 0.5 + 0.5))
|
||||
eq(rat.hp, expectedHp, "current hp is rescaled to the same fraction the old body carried")
|
||||
eq(rat.attack, spec.attack, "attack is replaced wholesale from the new species")
|
||||
eq(rat.ai, spec.ai, "ai behaviour is replaced wholesale from the new species")
|
||||
end
|
||||
|
||||
function tests.polymorphTransformReturnsNilWhenThePoolOffersNothingButTheCurrentSpecies()
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||
local spec = Polymorph.transform(rat, Rng.new(3), { Monsters.byKey.rat })
|
||||
ok(spec == nil, "a pool with nothing but the entity's own species transforms nothing")
|
||||
eq(rat.species, "rat", "the entity is left untouched when there is nowhere else to go")
|
||||
end
|
||||
|
||||
function tests.spellsPolymorphTransformsTheTargetAndSpendsItsListedManaCost()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Spells.learn(game.player, "polymorph")
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
game.level.entities = { orc }
|
||||
local manaBefore = game.player.mana
|
||||
local success = game:castSpell("polymorph", orc)
|
||||
ok(success, "casting a learned, in-range polymorph succeeds")
|
||||
ok(orc.species ~= "orc", "the target's species actually changed")
|
||||
eq(game.player.mana, manaBefore - Spells.catalog.polymorph.cost, "casting polymorph spends exactly its listed mana cost")
|
||||
end
|
||||
|
||||
function tests.spellsPolymorphFailsOutOfRangeAndSpendsNothing()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Spells.learn(game.player, "polymorph")
|
||||
local farOrc = Monsters.create(Monsters.byKey.orc, 1, 19, 6, 1)
|
||||
game.level.entities = { farOrc }
|
||||
local manaBefore = game.player.mana
|
||||
local success = game:castSpell("polymorph", farOrc)
|
||||
ok(not success, "polymorph cast beyond its range fails")
|
||||
eq(farOrc.species, "orc", "a failed cast never transforms the target")
|
||||
eq(game.player.mana, manaBefore, "a failed cast spends no mana")
|
||||
end
|
||||
|
||||
function tests.builderCanRollATomeOfThePolymorphSpellSomewhereInARangeOfSeeds()
|
||||
-- Range widened from 100 to 200: adding "cleanse" to Builder's `learnable`
|
||||
-- list shifted rng:range(1, #learnable)'s result for effectively every
|
||||
-- seed, and the nearest polymorph tome under the new list happens to sit
|
||||
-- at seed 183 - still well within "a reasonable seed range".
|
||||
local found = false
|
||||
for seed = 1, 200 do
|
||||
local level = Builder.build(6, Rng.new(seed), {})
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.kind == Items.TOME and ground.item.spell == "polymorph" then found = true end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
ok(found, "the polymorph tome is reachable dungeon loot within a reasonable seed range")
|
||||
end
|
||||
|
||||
function tests.blocksCanReceiveRefusesWallsDoorsVaultsGatesBlocksAndEntities()
|
||||
local level = arena(9, 9)
|
||||
level.map:set(4, 4, Tiles.WALL)
|
||||
eq(Blocks.canReceive(level, 4, 4), false, "a wall cannot receive a shoved block")
|
||||
level.map:set(4, 5, Tiles.DOOR_CLOSED)
|
||||
eq(Blocks.canReceive(level, 4, 5), false, "a closed door cannot receive a shoved block")
|
||||
level.map:set(4, 6, Tiles.VAULT_DOOR)
|
||||
eq(Blocks.canReceive(level, 4, 6), false, "a sealed vault door cannot receive a shoved block")
|
||||
level.map:set(4, 7, Tiles.GATE_CLOSED)
|
||||
eq(Blocks.canReceive(level, 4, 7), false, "a closed gate cannot receive a shoved block")
|
||||
level.blocks = { { x = 3, y = 3 } }
|
||||
eq(Blocks.canReceive(level, 3, 3), false, "a cell already holding another block cannot receive a shove")
|
||||
level.entities = { Entity.new({ x = 3, y = 4, glyph = "r", name = "rat", kind = "monster", hp = 5, attack = 1, defense = 0 }) }
|
||||
eq(Blocks.canReceive(level, 3, 4), false, "a cell occupied by a living entity cannot receive a shove")
|
||||
eq(Blocks.canReceive(level, 5, 5), true, "plain open floor can receive a shoved block")
|
||||
eq(Blocks.canReceive(level, 20, 20), false, "an out-of-bounds cell cannot receive a shove")
|
||||
end
|
||||
|
||||
function tests.blocksPushRelocatesABlockOntoPlainFloor()
|
||||
local level = arena(9, 9)
|
||||
local block = { x = 3, y = 3 }
|
||||
level.blocks = { block }
|
||||
local pushed, line = Blocks.push(level, block, 1, 0)
|
||||
eq(pushed, true, "a shove onto open floor succeeds")
|
||||
eq(block.x, 4, "the block's own x relocates by the shove")
|
||||
eq(block.y, 3, "the block's own y is unchanged by a purely horizontal shove")
|
||||
ok(contains(line, "shove"), "a plain shove is logged as a shove")
|
||||
end
|
||||
|
||||
function tests.blocksPushIntoLavaSolidifiesTheCellAndConsumesTheBlock()
|
||||
local level = arena(9, 9)
|
||||
level.map:set(4, 3, Tiles.LAVA)
|
||||
local block = { x = 3, y = 3 }
|
||||
level.blocks = { block }
|
||||
local pushed, line = Blocks.push(level, block, 1, 0)
|
||||
eq(pushed, true, "a shove into lava still succeeds")
|
||||
eq(level.map:get(4, 3), Tiles.RUBBLE, "the lava cell solidifies into rubble")
|
||||
eq(#level.blocks, 0, "the block is consumed by the lava it just quenched")
|
||||
ok(contains(line, "lava"), "quenching lava is logged")
|
||||
end
|
||||
|
||||
function tests.blocksPushIntoAChasmFillsTheGapAndConsumesTheBlock()
|
||||
local level = arena(9, 9)
|
||||
level.map:set(4, 3, Tiles.CHASM)
|
||||
local block = { x = 3, y = 3 }
|
||||
level.blocks = { block }
|
||||
local pushed, line = Blocks.push(level, block, 1, 0)
|
||||
eq(pushed, true, "a shove into a chasm still succeeds")
|
||||
eq(level.map:get(4, 3), Tiles.FLOOR, "the chasm cell fills into plain floor")
|
||||
eq(#level.blocks, 0, "the block is consumed filling in the chasm")
|
||||
ok(contains(line, "chasm"), "filling a chasm is logged")
|
||||
end
|
||||
|
||||
function tests.blocksPushFailsAgainstAWallOrAnotherBlockOrAnEntity()
|
||||
local level = arena(9, 9)
|
||||
level.map:set(4, 3, Tiles.WALL)
|
||||
local block = { x = 3, y = 3 }
|
||||
level.blocks = { block }
|
||||
eq(Blocks.push(level, block, 1, 0), false, "a shove into a wall fails outright")
|
||||
eq(block.x, 3, "a failed shove leaves the block exactly where it was")
|
||||
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user