test: cover tests.sanityTickRecoversAndAnnouncesClimbingBackOutOfBroken
This commit is contained in:
1 parent
0db5c1683d
commit
1a617008d4
1 file changed
+173
+173
@@ -8089,6 +8089,179 @@ function tests.sanityTickAnnouncesReachingTerrifiedAndBroken()
|
||||
eq(game.player.sanity, 0, "broken is a floor, not a negative value")
|
||||
end
|
||||
|
||||
function tests.sanityTickRecoversAndAnnouncesClimbingBackOutOfBroken()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 0
|
||||
eq(Sanity.tick(game), "your nerves start to steady",
|
||||
"recovering out of broken is announced as steadying, never as fresh dread")
|
||||
eq(game.player.sanity, 1, "a calm turn only ever recovers its small fixed amount")
|
||||
end
|
||||
|
||||
function tests.sanityTickAnnouncesFullyRegainingComposure()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 60
|
||||
eq(Sanity.tick(game), "your mind is your own again", "climbing back above the shaken ceiling is announced")
|
||||
end
|
||||
|
||||
function tests.sanityTickNeverClimbsPastTheMaxOrReportsAPhantomCrossing()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 100
|
||||
eq(Sanity.tick(game), nil, "an already-composed mind with nothing to recover reports no line")
|
||||
eq(game.player.sanity, 100, "recovery never climbs the meter past its own maximum")
|
||||
end
|
||||
|
||||
function tests.sanityRollPanicNeverFiresAboveBroken()
|
||||
local entity = { sanity = 1 }
|
||||
for seed = 1, 50 do
|
||||
ok(not Sanity.rollPanic(Rng.new(seed), entity), "terrified never risks losing the turn to panic")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.sanityRollPanicRollsAgainstItsFixedChanceOnceBroken()
|
||||
local entity = { sanity = 0 }
|
||||
local sawPanic, sawComposure = false, false
|
||||
for seed = 1, 50 do
|
||||
if Sanity.rollPanic(Rng.new(seed), entity) then sawPanic = true else sawComposure = true end
|
||||
end
|
||||
ok(sawPanic, "broken panics on at least some rolls across a handful of seeds")
|
||||
ok(sawComposure, "broken does not panic on every single roll")
|
||||
end
|
||||
|
||||
function tests.sanityRollScreamNeverFiresAboveTerrified()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 31
|
||||
for seed = 1, 50 do
|
||||
game.rng = Rng.new(seed)
|
||||
ok(not Sanity.rollScream(game.rng, game), "merely shaken never risks an involuntary scream")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.sanityRollScreamAlertsEveryDormantMonsterWithinItsRadius()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 0
|
||||
local zombie = Monsters.create(Monsters.byKey.zombie, 1, 5, 6, 1)
|
||||
zombie.awareness = Stealth.DORMANT
|
||||
game.level.entities = { zombie }
|
||||
local triggered = false
|
||||
for seed = 1, 80 do
|
||||
game.rng = Rng.new(seed)
|
||||
if Sanity.rollScream(game.rng, game) then triggered = true break end
|
||||
end
|
||||
ok(triggered, "a broken mind eventually screams across a handful of seeds")
|
||||
eq(zombie.awareness, Stealth.HUNTING, "the scream startles a nearby dormant monster fully awake")
|
||||
eq(zombie.lastKnownX, game.player.x, "the alerted monster now knows exactly where the scream came from")
|
||||
end
|
||||
|
||||
function tests.sanityFieldSurvivesSerialization()
|
||||
local game = Game.new(3)
|
||||
game.player.sanity = 37
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
eq(restored.player.sanity, 37, "the player's sanity survives a save/load round trip")
|
||||
end
|
||||
|
||||
function tests.gameEndPlayerTurnTicksSanityAndTheLogReportsATierCrossing()
|
||||
local game = stagedGame(1, arenaDark(21, 11), 3, 6)
|
||||
game.player.light.fuel = 0
|
||||
game.player.sanity = 63
|
||||
game:endPlayerTurn()
|
||||
eq(game.player.sanity, 61, "ending a turn on a dark, torchless floor drains the fixed darkness dread")
|
||||
game:endPlayerTurn()
|
||||
ok(contains(game.log:last(), "fray"), "crossing into shaken is reported in the message log")
|
||||
eq(game.player:effectiveAttack(), game.player.attack - 1, "the fresh shaken penalty is already live in effectiveAttack")
|
||||
end
|
||||
|
||||
function tests.gameAutoStepSkipsThePlayerTurnWhenPanicFires()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 0
|
||||
local px, py = game.player.x, game.player.y
|
||||
local sawPanic = false
|
||||
for seed = 1, 80 do
|
||||
game.rng = Rng.new(seed)
|
||||
game.player.x, game.player.y = px, py
|
||||
game.player.sanity = 0
|
||||
-- endPlayerTurn's own Sanity.tick line (recovery or otherwise) always
|
||||
-- lands after any panic line within the same turn, so the panic line
|
||||
-- itself has to be found among the turn's recent lines rather than
|
||||
-- assumed to be the very last one.
|
||||
game:autoStep()
|
||||
if contains(table.concat(game.log:recent(3), " "), "terror seizes you") then sawPanic = true break end
|
||||
end
|
||||
ok(sawPanic, "a broken mind eventually loses a whole turn to panic across a handful of seeds")
|
||||
eq(game.player.x, px, "a panicked turn never moves the player")
|
||||
eq(game.player.y, py, "a panicked turn never moves the player")
|
||||
end
|
||||
|
||||
function tests.gameUseItemPotionOfClarityRestoresSanity()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.sanity = 40
|
||||
game.player.inventory = { Items.potionOf("clarity", 30) }
|
||||
ok(game:useItem(1), "drinking the potion of clarity succeeds")
|
||||
eq(game.player.sanity, 70, "clarity restores its fixed power to the drinker's sanity")
|
||||
ok(contains(game.log:last(), "steadies"), "the log reports the mind steadying")
|
||||
end
|
||||
|
||||
function tests.renderPanelShowsSanityOnlyOnceItDropsBelowComposed()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
ok(not contains(Render.panel(game), "sanity"), "a fully composed player shows no sanity line at all")
|
||||
game.player.sanity = 30
|
||||
ok(contains(Render.panel(game), "sanity 30/100 (terrified)"), "a shaken mind is reported in the status panel")
|
||||
end
|
||||
|
||||
-- Disease used to be invisible outside the transient log lines Disease.tick
|
||||
-- emits (the eruption, a damage tick, an escalation) - once one of those
|
||||
-- scrolled off the log, a player mid-incubation or mid-plague had no
|
||||
-- persistent way to check their own infection at all, unlike every timed
|
||||
-- status statusTags already folds into this same line.
|
||||
function tests.renderPanelShowsTheDiseaseStageOnceThePlayerIsInfectedAndNothingBeforeInfection()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
ok(not contains(Render.panel(game), "parasites"), "an uninfected player's status line mentions no disease")
|
||||
Disease.infect(game.player, Disease.PARASITES)
|
||||
ok(contains(Render.panel(game), "gut parasites(incubating)"),
|
||||
"an incubating infection shows up in the status panel even before it erupts")
|
||||
game.player.disease.stage = 2
|
||||
ok(contains(Render.panel(game), "gut parasites(stage 2)"),
|
||||
"an erupted infection reports its current stage in the status panel")
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyRollsAPotionOfClarityAsLoot()
|
||||
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 == "clarity" then found = ground.item end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
ok(found ~= nil, "a potion of clarity eventually turns up in the depth-2 loot table across a handful of seeds")
|
||||
ok(Shop.priceOf(found) > 0, "a found clarity potion still carries a positive catalog price")
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyRollsAPotionOfConfusionAsLoot()
|
||||
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 == "confuse" then found = ground.item end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
ok(found ~= nil, "a potion of confusion eventually turns up in the depth-2 loot table across a handful of seeds")
|
||||
ok(Shop.priceOf(found) > 0, "a found confusion potion still carries a positive catalog price")
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyRollsAPotionOfBlindnessAsLoot()
|
||||
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 == "blind" then found = ground.item end
|
||||
end
|
||||
if found then break end
|
||||
end
|
||||
|
||||
local order = {
|
||||
"rngDeterminism", "mapDeterminism", "tilesRegistry", "fovKnownScene", "losSightLine",
|
||||
"astarPathing", "combatResolution", "itemsAndEquipment", "affixes", "statusEffects",
|
||||
|
||||
Reference in new issue
Block a user