test: cover tests.builderOccasionallyRollsAPotionOfLevitationAsLoot
This commit is contained in:
1 parent
1a617008d4
commit
91171be9e1
1 file changed
+173
+173
@@ -8260,6 +8260,179 @@ function tests.builderOccasionallyRollsAPotionOfBlindnessAsLoot()
|
|||||||
if ground.item.kind == Items.POTION and ground.item.effect == "blind" then found = ground.item end
|
if ground.item.kind == Items.POTION and ground.item.effect == "blind" then found = ground.item end
|
||||||
end
|
end
|
||||||
if found then break end
|
if found then break end
|
||||||
|
end
|
||||||
|
ok(found ~= nil, "a potion of blindness eventually turns up in the depth-2 loot table across a handful of seeds")
|
||||||
|
ok(Shop.priceOf(found) > 0, "a found blindness potion still carries a positive catalog price")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.builderOccasionallyRollsAPotionOfLevitationAsLoot()
|
||||||
|
local found
|
||||||
|
for seed = 1, 200 do
|
||||||
|
local level = Builder.build(2, Rng.new(seed), {})
|
||||||
|
for _, ground in ipairs(level.floorItems) do
|
||||||
|
if ground.item.kind == Items.POTION and ground.item.effect == "levitate" then found = ground.item end
|
||||||
|
end
|
||||||
|
if found then break end
|
||||||
|
end
|
||||||
|
ok(found ~= nil, "a potion of levitation eventually turns up in the depth-2 loot table across a handful of seeds")
|
||||||
|
ok(Shop.priceOf(found) > 0, "a found levitation potion still carries a positive catalog price")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsCatalogEntriesEachHaveDistinctStartAndEndFlavorText()
|
||||||
|
for _, key in ipairs(Events.order) do
|
||||||
|
local start = Events.describe(key)
|
||||||
|
local ending = Events.endDescribe(key)
|
||||||
|
ok(start ~= nil, key .. " has a start line")
|
||||||
|
ok(ending ~= nil, key .. " has an end line")
|
||||||
|
ok(start ~= ending, key .. "'s start and end lines read differently")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsMonsterDamageMultiplierOnlyFiresDuringBloodmoon()
|
||||||
|
eq(Events.monsterDamageMultiplier(nil), 1, "no active event leaves monster damage unscaled")
|
||||||
|
eq(Events.monsterDamageMultiplier({ key = Events.RICHVEINS }), 1, "a non-bloodmoon event leaves monster damage unscaled")
|
||||||
|
eq(Events.monsterDamageMultiplier({ key = Events.BLOODMOON }), Events.BLOODMOON_MULTIPLIER,
|
||||||
|
"bloodmoon scales monster damage by its fixed multiplier")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsEssenceMultiplierOnlyFiresDuringRichVeins()
|
||||||
|
eq(Events.essenceMultiplier(nil), 1, "no active event leaves essence unscaled")
|
||||||
|
eq(Events.essenceMultiplier({ key = Events.BLOODMOON }), 1, "a non-richveins event leaves essence unscaled")
|
||||||
|
eq(Events.essenceMultiplier({ key = Events.RICHVEINS }), Events.RICHVEINS_MULTIPLIER,
|
||||||
|
"rich veins scales essence by its fixed multiplier")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsSightPenaltyOnlyFiresDuringHush()
|
||||||
|
eq(Events.sightPenalty(nil), 0, "no active event carries no sight penalty")
|
||||||
|
eq(Events.sightPenalty({ key = Events.BLOODMOON }), 0, "a non-hush event carries no sight penalty")
|
||||||
|
eq(Events.sightPenalty({ key = Events.HUSH }), Events.HUSH_SIGHT_PENALTY, "hush carries its fixed sight penalty")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsStepNeverStartsOnTheFirstFloorRegardlessOfTheRoll()
|
||||||
|
for seed = 1, 100 do
|
||||||
|
local level = { depth = 1 }
|
||||||
|
eq(Events.step(level, Rng.new(seed)), nil, "a depth-one floor never rolls an event")
|
||||||
|
eq(level.event, nil, "a depth-one floor's event stays nil across every seed")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsStepEventuallyStartsFromDepthTwoAcrossAHandfulOfSeeds()
|
||||||
|
local started = false
|
||||||
|
for seed = 1, 400 do
|
||||||
|
local level = { depth = 2 }
|
||||||
|
if Events.step(level, Rng.new(seed)) then started = true break end
|
||||||
|
end
|
||||||
|
ok(started, "a depth-two floor eventually rolls a fresh event across a handful of seeds")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventsStepCountsDownAndExpiresWithItsEndLine()
|
||||||
|
local level = { depth = 2, event = { key = Events.BLOODMOON, turnsLeft = 2 } }
|
||||||
|
eq(Events.step(level, Rng.new(1)), nil, "an ordinary tick of a running event reports no line")
|
||||||
|
eq(level.event.turnsLeft, 1, "the running event's clock ticks down by one")
|
||||||
|
eq(Events.step(level, Rng.new(1)), Events.endDescribe(Events.BLOODMOON),
|
||||||
|
"the event's expiry is reported the turn its clock runs out")
|
||||||
|
eq(level.event, nil, "an expired event clears itself from the level")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameMonsterMeleeDamageScalesDuringBloodmoon()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||||
|
local before = game.player.hp
|
||||||
|
game:monsterMelee(orc)
|
||||||
|
local plainDamage = before - game.player.hp
|
||||||
|
|
||||||
|
game.player.hp = before
|
||||||
|
game.level.event = { key = Events.BLOODMOON, turnsLeft = 5 }
|
||||||
|
game:monsterMelee(orc)
|
||||||
|
local bloodmoonDamage = before - game.player.hp
|
||||||
|
|
||||||
|
eq(bloodmoonDamage, math.floor(plainDamage * Events.BLOODMOON_MULTIPLIER),
|
||||||
|
"bloodmoon scales a monster's melee damage by its fixed multiplier")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameMonsterShootDamageScalesDuringBloodmoon()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local dragon = Monsters.create(Monsters.byKey.dragon, 1, 6, 6, 1)
|
||||||
|
local before = game.player.hp
|
||||||
|
game:monsterShoot(dragon)
|
||||||
|
local plainDamage = before - game.player.hp
|
||||||
|
|
||||||
|
game.player.hp = before
|
||||||
|
game.player.statuses = {}
|
||||||
|
game.level.event = { key = Events.BLOODMOON, turnsLeft = 5 }
|
||||||
|
game:monsterShoot(dragon)
|
||||||
|
local bloodmoonDamage = before - game.player.hp
|
||||||
|
|
||||||
|
eq(bloodmoonDamage, math.floor(plainDamage * Events.BLOODMOON_MULTIPLIER),
|
||||||
|
"bloodmoon scales a monster's ranged damage by its fixed multiplier")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameKillEssenceIsDoubledDuringRichVeins()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 4, 6, 1)
|
||||||
|
rat.hp = 1
|
||||||
|
game.level.entities = { rat }
|
||||||
|
game.level.event = { key = Events.RICHVEINS, turnsLeft = 5 }
|
||||||
|
local essenceBefore = game.player.essence
|
||||||
|
game:playerAttack(rat)
|
||||||
|
eq(game.player.essence, essenceBefore + Crafting.essenceFor(Monsters.xpFor(rat)) * Events.RICHVEINS_MULTIPLIER,
|
||||||
|
"rich veins doubles the essence earned from a kill")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameEffectiveRadiusShrinksDuringHush()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local plain = game:effectiveRadius()
|
||||||
|
game.level.event = { key = Events.HUSH, turnsLeft = 5 }
|
||||||
|
eq(game:effectiveRadius(), plain - Events.HUSH_SIGHT_PENALTY, "hush dulls the player's effective sight radius")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameEndPlayerTurnEventuallyRollsAFreshEventFromDepthTwo()
|
||||||
|
local triggered = false
|
||||||
|
for seed = 1, 400 do
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
game.level.depth = 2
|
||||||
|
game.rng = Rng.new(seed)
|
||||||
|
game:endPlayerTurn()
|
||||||
|
if game.level.event then triggered = true break end
|
||||||
|
end
|
||||||
|
ok(triggered, "ending a turn on a depth-two floor eventually rolls a fresh event across a handful of seeds")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameEndPlayerTurnAnnouncesAnEventEndingInTheLog()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
game.level.event = { key = Events.RICHVEINS, turnsLeft = 1 }
|
||||||
|
game:endPlayerTurn()
|
||||||
|
eq(game.level.event, nil, "the event's clock runs out and clears itself")
|
||||||
|
ok(contains(game.log:last(), "quiet"), "the event's end is reported in the message log")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.renderPanelShowsTheActiveEventAndItsRemainingTurns()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
ok(not contains(Render.panel(game), "turns left"), "no active event shows no event line at all")
|
||||||
|
game.level.event = { key = Events.BLOODMOON, turnsLeft = 7 }
|
||||||
|
ok(contains(Render.panel(game), "event bloodmoon (7 turns left)"),
|
||||||
|
"an active event reports its name and remaining turns")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.eventFieldSurvivesSerialization()
|
||||||
|
local game = Game.new(3)
|
||||||
|
game.level.event = { key = Events.HUSH, turnsLeft = 9 }
|
||||||
|
local path = os.tmpname()
|
||||||
|
game:save(path)
|
||||||
|
local restored = Game.load(path)
|
||||||
|
os.remove(path)
|
||||||
|
eq(restored.level.event.key, Events.HUSH, "the active event's key survives a save/load round trip")
|
||||||
|
eq(restored.level.event.turnsLeft, 9, "the active event's remaining turns survive a save/load round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- graves.lua: cross-run bones.
|
||||||
|
|
||||||
|
function tests.gravesRecordAppendsNewestFirstAndTrimsToMaxRecorded()
|
||||||
|
local meta = Meta.new()
|
||||||
|
for i = 1, Graves.MAX_RECORDED + 5 do
|
||||||
|
Graves.record(meta, { className = "fighter", depth = i, gold = i, essence = 0, turn = i })
|
||||||
|
end
|
||||||
|
eq(#meta.graves, Graves.MAX_RECORDED, "recording past the cap trims the oldest graves off")
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user