test: cover tests.terrainIceSlideStopsBeforeAWall
This commit is contained in:
1 parent
a24ad322c5
commit
aca2e06b3c
1 file changed
+173
+173
@@ -6011,6 +6011,179 @@ function tests.terrainIceSlidesATravellerUntilSomethingStopsIt()
|
|||||||
eq(game.player.y, 6, "sliding on ice does not drift off the axis of travel")
|
eq(game.player.y, 6, "sliding on ice does not drift off the axis of travel")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tests.terrainIceSlideStopsBeforeAWall()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 2, 6)
|
||||||
|
game.level.map:set(3, 6, Tiles.ICE)
|
||||||
|
game.level.map:set(4, 6, Tiles.ICE)
|
||||||
|
game.level.map:set(5, 6, Tiles.WALL)
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.x, 4, "an ice slide stops on the last ice tile before a wall")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.terrainIceSlideStopsAtAnOccupiedCell()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 2, 6)
|
||||||
|
game.level.map:set(3, 6, Tiles.ICE)
|
||||||
|
game.level.map:set(4, 6, Tiles.ICE)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
game.level.entities = { rat }
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.x, 4, "an ice slide stops just short of another actor")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Status.LEVITATE (see status.lua and Game:checkTerrainFor) short-circuits
|
||||||
|
-- every branch below before any of it runs - no burn, no fall, no slide -
|
||||||
|
-- so these mirror the three terrain tests directly above/below them with
|
||||||
|
-- one difference: the mover carries the status first.
|
||||||
|
function tests.checkTerrainForSkipsLavaDamageAndIgnitionForALevitatingPlayer()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
game.level.map:set(4, 6, Tiles.LAVA)
|
||||||
|
Status.apply(game.player, Status.LEVITATE, 20, 1)
|
||||||
|
local hpBefore = game.player.hp
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.hp, hpBefore, "a levitating player takes no damage crossing lava")
|
||||||
|
eq(Status.has(game.player, Status.BURNING), false, "a levitating player is never set alight by lava")
|
||||||
|
ok(contains(game.log:last(), "drift"), "the skip over a visible hazard is still logged, not silent")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.checkTerrainForSkipsTheChasmFallForALevitatingPlayer()
|
||||||
|
local game = stagedGame(3, arena(21, 11), 5, 6)
|
||||||
|
game.level.map:set(6, 6, Tiles.CHASM)
|
||||||
|
Status.apply(game.player, Status.LEVITATE, 20, 1)
|
||||||
|
local hpBefore = game.player.hp
|
||||||
|
local depthBefore = game.depth
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.x, 6, "a levitating player actually reaches the chasm cell instead of refusing to enter it")
|
||||||
|
eq(game.player.hp, hpBefore, "a levitating player takes no fall damage over a chasm")
|
||||||
|
eq(game.depth, depthBefore, "a levitating player drifts over a chasm instead of dropping to the floor below")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.checkTerrainForSkipsTheIceSlideForALevitatingPlayer()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 2, 6)
|
||||||
|
for x = 3, 6 do game.level.map:set(x, 6, Tiles.ICE) end
|
||||||
|
Status.apply(game.player, Status.LEVITATE, 20, 1)
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.x, 3, "a levitating player enters the first ice cell but never slides across the rest")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.checkTerrainForSkipsLavaForALevitatingMonsterToo()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 2, 2)
|
||||||
|
game.level.map:set(6, 6, Tiles.LAVA)
|
||||||
|
local bat = Monsters.create(Monsters.byKey.bat, 1, 5, 6, 1)
|
||||||
|
Status.apply(bat, Status.LEVITATE, 20, 1)
|
||||||
|
game.level.entities = { bat }
|
||||||
|
local hpBefore = bat.hp
|
||||||
|
game:moveMonster(bat, 1, 0)
|
||||||
|
eq(bat.x, 6, "the levitating monster still moves onto the lava cell")
|
||||||
|
eq(bat.hp, hpBefore, "a levitating monster crossing lava takes no damage either - the guard is not player-only")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.terrainGlyphsSurviveMapSerialization()
|
||||||
|
local map = Map.new(10, 6)
|
||||||
|
for y = 2, 5 do for x = 2, 9 do map:set(x, y, Map.FLOOR) end end
|
||||||
|
map:set(4, 4, Tiles.LAVA)
|
||||||
|
map:set(5, 4, Tiles.CHASM)
|
||||||
|
map:set(6, 4, Tiles.ICE)
|
||||||
|
local restored = Map.fromData(map:toData())
|
||||||
|
eq(restored:get(4, 4), Tiles.LAVA, "a lava tile survives a map round trip")
|
||||||
|
eq(restored:get(5, 4), Tiles.CHASM, "a chasm tile survives a map round trip")
|
||||||
|
eq(restored:get(6, 4), Tiles.ICE, "an ice tile survives a map round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.chasmFallFieldsSurviveGameSaveLoad()
|
||||||
|
local game = stagedGame(3, arena(21, 11), 5, 6)
|
||||||
|
game.level.map:set(6, 6, Tiles.CHASM)
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
local path = os.tmpname()
|
||||||
|
game:save(path)
|
||||||
|
local restored = Game.load(path)
|
||||||
|
os.remove(path)
|
||||||
|
eq(restored.depth, game.depth, "the depth reached by falling survives a save/load round trip")
|
||||||
|
eq(restored.player.hp, game.player.hp, "hp after a chasm fall survives a save/load round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.lavaChasmAndIceStayOffTheShallowFloors()
|
||||||
|
for seed = 1, 5 do
|
||||||
|
for depth = 1, 3 do
|
||||||
|
local level = Builder.build(depth, Rng.new(seed), {})
|
||||||
|
for _, tile in ipairs(level.map.tiles) do
|
||||||
|
ok(tile ~= Tiles.LAVA and tile ~= Tiles.CHASM and tile ~= Tiles.ICE,
|
||||||
|
"no volatile terrain appears above depth 4")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.builderOccasionallyPlacesLavaChasmAndIceFromDepthFour()
|
||||||
|
local sawLava, sawChasm, sawIce = false, false, false
|
||||||
|
for seed = 1, 60 do
|
||||||
|
local level = Builder.build(4, Rng.new(seed), {})
|
||||||
|
for _, tile in ipairs(level.map.tiles) do
|
||||||
|
if tile == Tiles.LAVA then sawLava = true end
|
||||||
|
if tile == Tiles.CHASM then sawChasm = true end
|
||||||
|
if tile == Tiles.ICE then sawIce = true end
|
||||||
|
end
|
||||||
|
if sawLava and sawChasm and sawIce then break end
|
||||||
|
end
|
||||||
|
ok(sawLava, "a depth-4 floor eventually places lava on some seed")
|
||||||
|
ok(sawChasm, "a depth-4 floor eventually places a chasm on some seed")
|
||||||
|
ok(sawIce, "a depth-4 floor eventually places ice on some seed")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.chasmNeverAppearsOnTheFinalFloor()
|
||||||
|
for seed = 1, 30 do
|
||||||
|
local level = Builder.build(Builder.MAX_DEPTH, Rng.new(seed), {})
|
||||||
|
for _, tile in ipairs(level.map.tiles) do
|
||||||
|
ok(tile ~= Tiles.CHASM, "no chasm appears on the final floor since there is no floor below it")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eliteNeverPromotesBelowMinDepth()
|
||||||
|
for seed = 1, 40 do
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 5, 5, 2)
|
||||||
|
Elites.maybePromote(Rng.new(seed), orc, 2)
|
||||||
|
ok(not orc.elite, "no promotion below depth 3 regardless of the roll")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eliteEligibleExcludesBossesAndTheShopkeeper()
|
||||||
|
local boss = Bosses.create(Bosses.byKey.warlord, 1, 5, 5)
|
||||||
|
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 2, 6, 5, 4)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 3, 7, 5, 3)
|
||||||
|
ok(not Elites.eligible(boss), "a boss is never eligible for elite promotion")
|
||||||
|
ok(not Elites.eligible(keeper), "the shopkeeper is never eligible for elite promotion")
|
||||||
|
ok(Elites.eligible(orc), "a plain bestiary spawn is eligible for elite promotion")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eliteArmoredAffixAddsFlatDefenseAndPrefixesTheName()
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 5, 5, 3)
|
||||||
|
local baseDefense = orc.defense
|
||||||
|
Elites.maybePromote(Rng.new(8), orc, 3)
|
||||||
|
eq(orc.eliteTier, "elite", "a single-affix promotion is a plain elite, not a champion")
|
||||||
|
eq(orc.eliteAffixes[1], "armored", "seed 8 rolls the armored affix at depth 3")
|
||||||
|
eq(orc.defense, baseDefense + 3, "armored adds its flat defense bonus")
|
||||||
|
eq(orc.baseDefense, baseDefense + 3, "armored's bonus also lands on baseDefense")
|
||||||
|
eq(orc.name, "armored orc", "the affix name prefixes the species name")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eliteChampionTierAtDeepDepthRollsTwoDistinctAffixes()
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 5, 5, 7)
|
||||||
|
Elites.maybePromote(Rng.new(9), orc, 7)
|
||||||
|
eq(orc.eliteTier, "champion", "seed 9 at depth 7 rolls a champion")
|
||||||
|
eq(#orc.eliteAffixes, 2, "a champion carries exactly two affixes")
|
||||||
|
ok(orc.eliteAffixes[1] ~= orc.eliteAffixes[2], "a champion never doubles up on the same affix")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eliteFieldsSurviveSerialization()
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 5, 5, 3)
|
||||||
|
Elites.maybePromote(Rng.new(2), orc, 3)
|
||||||
|
local restored = Entity.fromData(orc:toData())
|
||||||
|
eq(restored.elite, true, "the elite flag survives serialization")
|
||||||
|
eq(restored.eliteTier, "elite", "the elite tier survives serialization")
|
||||||
|
eq(restored.eliteAffixes[1], "swift", "the rolled affix list survives serialization")
|
||||||
|
eq(restored.speed, orc.speed, "the swift affix's speed bonus survives serialization")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user