test: cover tests.gameUseItemDrinkingACurePotionLiftsTheInfectionAndI...

This commit is contained in:
dualfroz committed 2026-09-12 18:23:02 +02:00
1 parent 89e97d7b3a
commit fce4742c18
1 file changed
+173
+173
View File
@@ -12066,6 +12066,179 @@ function tests.gameEndPlayerTurnTicksThePlayersDiseaseAndLogsItsEruption()
Disease.infect(game.player, Disease.PARASITES)
local incubation = Disease.defs[Disease.PARASITES].incubation
for _ = 1, incubation - 1 do
game:endPlayerTurn()
eq(game.player.disease.stage, 0, "the infection keeps quietly incubating turn by turn")
end
game:endPlayerTurn()
eq(game.player.disease.stage, 1, "the infection erupts on schedule as the player's own turns tick past")
eq(game.log:last(), "you break out in gut parasites",
"the eruption is reported in the message log with correct you-are-the-subject grammar, not the third-person 'breaks out' a named monster would get")
end
function tests.gameUseItemDrinkingACurePotionLiftsTheInfectionAndIdentifiesThePotion()
local game = stagedGame(1, arena(21, 11), 3, 6)
Disease.infect(game.player, Disease.ROT)
game.player.inventory = { Items.potionOf("cure") }
local used = game:useItem(1)
eq(used, true, "drinking the potion succeeds")
ok(not Disease.isInfected(game.player), "the cure potion lifts the infection entirely")
ok(contains(game.log:last(), "cleansed"), "the log confirms the cure took effect")
eq(#game.player.inventory, 0, "the spent potion leaves the inventory like any other")
end
function tests.gameUseItemDrinkingACurePotionAlsoLiftsHostileStatusesNotJustDisease()
local game = stagedGame(1, arena(21, 11), 3, 6)
Status.apply(game.player, Status.POISON, 5, 2)
Status.apply(game.player, Status.CONFUSE, 6, 1)
Status.apply(game.player, Status.STRENGTH, 30, 3)
game.player.inventory = { Items.potionOf("cure") }
local used = game:useItem(1)
eq(used, true, "drinking the potion succeeds")
ok(not Status.has(game.player, Status.POISON), "the cure potion lifts poison even with no disease present")
ok(not Status.has(game.player, Status.CONFUSE), "the cure potion lifts confusion too")
ok(Status.has(game.player, Status.STRENGTH), "the cure potion never touches a buff like strength")
ok(contains(game.log:last(), "fades"), "the log reports the lifted statuses when there was no disease to mention")
end
function tests.gameUseItemDrinkingACurePotionReportsBothDiseaseAndStatusesWhenBothArePresent()
local game = stagedGame(1, arena(21, 11), 3, 6)
Disease.infect(game.player, Disease.ROT)
Status.apply(game.player, Status.POISON, 5, 2)
game.player.inventory = { Items.potionOf("cure") }
game:useItem(1)
ok(not Disease.isInfected(game.player), "the infection is lifted alongside the status effect")
ok(not Status.has(game.player, Status.POISON), "the status effect is lifted alongside the infection")
ok(contains(game.log:last(), "cleansed away") and contains(game.log:last(), "fades"),
"the single log line credits both the disease cure and the status cure")
end
function tests.gameUseItemDrinkingACurePotionWithNothingToCureIsHonestInTheLog()
local game = stagedGame(1, arena(21, 11), 3, 6)
game.player.inventory = { Items.potionOf("cure") }
local used = game:useItem(1)
eq(used, true, "the potion is still consumed even when there is nothing to cleanse")
ok(contains(game.log:last(), "nothing to cleanse"), "the log admits nothing was actually cured")
end
function tests.diseaseAndBiteDiseaseFieldsSurviveALevelSerializationRoundTrip()
local game = stagedGame(1, arena(21, 11), 5, 5)
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 5, 1)
Disease.infect(rat, Disease.PLAGUE)
rat.disease.stage = 2
game.level.entities = { rat }
local restored = Level.fromData(game.level:toData())
eq(restored.entities[1].biteDisease, Disease.PARASITES, "the species' own carried affliction survives a level round trip")
eq(restored.entities[1].disease.key, Disease.PLAGUE, "the active infection's key survives a level round trip")
eq(restored.entities[1].disease.stage, 2, "the active infection's progressed stage survives a level round trip")
end
-- captives.lua: netting a battered monster alive instead of finishing it
-- off, and cashing the resulting captive in for goodwill, gold or intel.
function tests.captivesEligibleAcceptsABatteredWildHostileAndRejectsATooHealthyOne()
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
rat.hp = 1
ok(Captives.eligible(rat), "a wild hostile battered down to a sliver of hp is eligible for a net")
rat.hp = rat.maxHp
ok(not Captives.eligible(rat), "a target still at full health is too fierce to net")
end
function tests.captivesEligibleExcludesBossesMimicsGravesNemesesAndTheVendingShopkeeper()
local orc = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 3)
orc.hp = 1
orc.isBoss = true
ok(not Captives.eligible(orc), "a boss is excluded from netting even when battered")
orc.isBoss = false
orc.mimic = true
ok(not Captives.eligible(orc), "a mimic is excluded from netting even when battered")
orc.mimic = false
orc.grave = true
ok(not Captives.eligible(orc), "a grave shade is excluded from netting even when battered")
orc.grave = false
orc.nemesis = true
ok(not Captives.eligible(orc), "a nemesis is excluded from netting even when battered")
orc.nemesis = false
ok(Captives.eligible(orc), "the same battered orc becomes eligible again once none of the exclusions apply")
local shopkeeper = Monsters.create(Monsters.byKey.shopkeeper, 2, 6, 6, 4)
shopkeeper.hp = 1
ok(not Captives.eligible(shopkeeper), "the vending shopkeeper is never eligible for a net even when battered")
end
function tests.captivesCanReachRespectsRangeAndLineOfSight()
local level = arena(21, 11)
ok(Captives.canReach(level.map, 3, 6, 3 + Captives.RANGE, 6), "a target at exactly max range with a clear line is reachable")
ok(not Captives.canReach(level.map, 3, 6, 3 + Captives.RANGE + 1, 6), "a target one cell beyond max range is unreachable")
level.map:set(5, 6, Tiles.WALL)
ok(not Captives.canReach(level.map, 3, 6, 7, 6), "a wall blocking the line of sight makes an in-range target unreachable")
end
function tests.captivesValueOfMatchesKillXpAndAddsAnEliteBonus()
local orc = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 3)
eq(Captives.valueOf(orc), Monsters.xpFor(orc), "a plain monster's capture value equals its kill xp")
orc.elite = true
orc.eliteTier = "champion"
local baseXp = Monsters.xpFor(orc)
eq(Captives.valueOf(orc), baseXp + Elites.xpBonus(orc, baseXp),
"an elite's capture value adds the same bonus a kill's xp would")
ok(Captives.valueOf(orc) > baseXp, "the elite bonus actually raises the capture value above the plain kill xp")
end
function tests.captivesResolveRefusesWithNoClearThrowWithoutSpendingTheNet()
local game = stagedGame(4, arena(21, 11), 2, 2)
local rat = Monsters.create(Monsters.byKey.rat, 1, 19, 9, 1)
rat.hp = 1
game.level.entities = { rat }
local net = Items.net()
local success, lines = Captives.resolve(game, game.player, net, rat)
eq(success, false, "a net thrown beyond range never leaves the hand")
ok(contains(lines[1], "clear throw"), "the reason given is the lack of a clear throw")
end
function tests.captivesResolveWastesTheNetOnATargetStillTooHealthyToSubdue()
local game = stagedGame(4, arena(21, 11), 3, 6)
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
game.level.entities = { rat }
local net = Items.net()
local success, lines = Captives.resolve(game, game.player, net, rat)
eq(success, true, "a net thrown at a still-healthy target still leaves the hand")
eq(#game.level.captives, 0, "no captive is created from a target too healthy to subdue")
eq(rat.hp, rat.maxHp, "the target takes no damage from a wasted net")
ok(contains(lines[1], "fierce"), "the log explains the target was too fierce to net")
end
function tests.captivesResolveCanThrashFreeAndStillSpendTheNet()
local game = stagedGame(4, arena(21, 11), 3, 6)
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
rat.hp = 1
game.level.entities = { rat }
game.rng = Rng.new(1)
local net = Items.net()
local success, lines = Captives.resolve(game, game.player, net, rat)
eq(success, true, "a lost catch roll still leaves the net thrown")
eq(#game.level.captives, 0, "no captive is created when the target thrashes free")
eq(rat.hp, 1, "a thrashing target takes no further damage")
ok(rat:isAlive(), "a target that thrashes free is still alive")
ok(contains(lines[1], "thrashes free"), "the log reports the target thrashing free")
end
function tests.captivesResolveCatchesABatteredTargetIntoACaptiveAndZeroesItsHp()
local game = stagedGame(4, arena(21, 11), 3, 6)
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
rat.hp = 1
game.level.entities = { rat }
game.rng = Rng.new(2)
local net = Items.net()
local success, lines = Captives.resolve(game, game.player, net, rat)
eq(success, true, "a successful catch leaves the net thrown")
eq(#game.level.captives, 1, "a successful catch adds exactly one captive")
local captive = game.level.captives[1]
eq(captive.name, rat.name, "the captive keeps the caught monster's name")
eq(captive.species, rat.species, "the captive keeps the caught monster's species")
eq(captive.faction, rat.faction, "the captive keeps the caught monster's faction")
eq(captive.value, Monsters.xpFor(rat), "the captive's value matches Captives.valueOf")
eq(rat.hp, 0, "the caught monster's hp is zeroed")
ok(not rat:isAlive(), "the caught monster is no longer alive")
end
local order = {