diff --git a/tests/run.lua b/tests/run.lua index 0139363..007b45d 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -11893,6 +11893,179 @@ function tests.gameCastSpellOnlyEmitsNoiseOnASuccessfulCastNeverOnAFailedOne() game:castSpell("missile", rat) end eq(bystander.awareness, Stealth.DORMANT, "two hundred failed casts for lack of mana never make a sound") + + game.player.mana = 999 + local stirred = false + for _ = 1, 200 do + rat.hp = rat.maxHp + game:castSpell("missile", rat) + if bystander.awareness ~= Stealth.DORMANT then stirred = true; break end + end + ok(stirred, "a spell that actually goes off is loud enough to eventually stir a nearby bystander") +end + +function tests.gameDigEmitsNoiseFromTheStruckCellEvenThoughItStartsUnwalkable() + local game = stagedGame(1, arena(21, 11), 3, 6) + game.level.map:set(4, 6, Tiles.WALL) + game.player.pick = Items.pick("miner's pick", 20) + local bystander = Monsters.create(Monsters.byKey.orc, 1, 9, 6, 1) + bystander.awareness = Stealth.DORMANT + game.level.entities = { bystander } + local stirred = false + for _ = 1, 200 do + game:dig(1, 0) + if bystander.awareness ~= Stealth.DORMANT then stirred = true; break end + if not game.player.pick then game.player.pick = Items.pick("miner's pick", 20) end + if game.level.map:get(4, 6) == Tiles.FLOOR then game.level.map:set(4, 6, Tiles.WALL) end + end + ok(stirred, "the racket of a pick striking solid rock still carries even though the struck cell starts unwalkable") +end + +function tests.diseaseInfectSeedsIncubationAndRefusesToStackASecondInfection() + local host = { name = "dummy", hp = 20 } + ok(Disease.infect(host, Disease.PARASITES), "infecting a clean host succeeds") + ok(Disease.isInfected(host), "the host now carries an infection") + eq(host.disease.incubation, Disease.defs[Disease.PARASITES].incubation, "incubation starts at the affliction's own listed value") + eq(host.disease.stage, 0, "a freshly seeded infection has not erupted yet") + ok(not Disease.infect(host, Disease.ROT), "a second affliction cannot take hold while one is already active") + eq(host.disease.key, Disease.PARASITES, "the original infection is left completely untouched by the refused attempt") +end + +function tests.diseaseUnknownKeyNeverInfects() + local host = { name = "dummy", hp = 20 } + ok(not Disease.infect(host, "swamp fever"), "an unrecognised affliction key never takes hold") + ok(not Disease.isInfected(host), "the host stays clean") +end + +function tests.diseaseIsInfectedAndHasEruptedTrackIncubationVsActiveStageSeparately() + local host = { name = "dummy", hp = 20 } + Disease.infect(host, Disease.ROT) + ok(Disease.isInfected(host), "an incubating host already counts as infected") + ok(not Disease.hasErupted(host), "but has not yet erupted while incubation is still counting down") + host.disease.stage = 1 + ok(Disease.hasErupted(host), "once staged past zero the infection counts as erupted") +end + +function tests.diseaseTickCountsIncubationDownInSilenceThenErupts() + local host = { name = "dummy", hp = 20 } + Disease.infect(host, Disease.PARASITES) + local incubation = Disease.defs[Disease.PARASITES].incubation + for i = 1, incubation - 1 do + local line = Disease.tick(host) + eq(line, nil, "each turn still incubating produces no visible symptom") + eq(host.disease.stage, 0, "the infection has not erupted yet at turn " .. i) + end + local eruptionLine = Disease.tick(host) + ok(contains(eruptionLine, "breaks out"), "the turn incubation runs out, the eruption is reported") + eq(host.disease.stage, 1, "the infection is now active at stage one") +end + +function tests.diseaseTickDealsStagePotencyThroughResistancesAndEscalatesOnItsFixedSchedule() + local host = { name = "dummy", hp = 1000 } + Disease.infect(host, Disease.ROT) + host.disease.stage = 1 + host.disease.sinceStage = 0 + local def = Disease.defs[Disease.ROT] + local hpBefore = host.hp + Disease.tick(host) + eq(host.hp, hpBefore - def.stagePotency[1], "a stage-one tick deals exactly that stage's listed potency") + for _ = 2, def.stageTurns - 1 do + Disease.tick(host) + end + eq(host.disease.stage, 1, "the stage holds steady right up until its full window has elapsed") + local escalationLine = Disease.tick(host) + ok(contains(escalationLine, "worsens"), "the tick that completes the window reports the escalation") + eq(host.disease.stage, 2, "the infection has moved on to stage two") + eq(host.disease.sinceStage, 0, "the new stage starts its own window fresh") +end + +function tests.diseaseTickNeverEscalatesPastTheTopStage() + local host = { name = "dummy", hp = 1000 } + Disease.infect(host, Disease.PLAGUE) + host.disease.stage = Disease.MAX_STAGE + host.disease.sinceStage = 0 + local def = Disease.defs[Disease.PLAGUE] + for _ = 1, def.stageTurns * 3 do + Disease.tick(host) + end + eq(host.disease.stage, Disease.MAX_STAGE, "the top stage never escalates any further, however long it lingers") +end + +function tests.diseaseAnImmuneHostTakesNoDamageButStillEscalatesOnSchedule() + local host = { name = "dummy", hp = 1000, resist = { poison = Resistances.IMMUNE } } + Disease.infect(host, Disease.ROT) + host.disease.stage = 1 + host.disease.sinceStage = 0 + local def = Disease.defs[Disease.ROT] + local hpBefore = host.hp + for _ = 1, def.stageTurns - 1 do + local line = Disease.tick(host) + eq(line, nil, "an immune host takes no damage, so a plain tick has nothing to report") + end + eq(host.hp, hpBefore, "an immune host never loses hp to the infection at all") + local escalationLine = Disease.tick(host) + ok(contains(escalationLine, "worsens"), "immunity blocks the damage but not the clock - the stage still worsens on schedule") +end + +function tests.diseaseCureLiftsAnInfectionAtAnyStageAndReportsFalseWhenThereWasNothingToLift() + local host = { name = "dummy", hp = 20 } + eq(Disease.cure(host), false, "curing a clean host reports nothing was lifted") + Disease.infect(host, Disease.PARASITES) + ok(Disease.cure(host), "curing an incubating infection succeeds") + ok(not Disease.isInfected(host), "the host is clean again") + Disease.infect(host, Disease.PLAGUE) + host.disease.stage = 3 + ok(Disease.cure(host), "curing works exactly the same on a fully erupted top-stage infection") + ok(not Disease.isInfected(host), "the host is clean again regardless of how far the infection had progressed") +end + +function tests.diseaseStagePotencyIsZeroWhileIncubatingOrUninfected() + local host = { name = "dummy", hp = 20 } + eq(Disease.stagePotency(host), 0, "an uninfected host has no stage potency at all") + Disease.infect(host, Disease.ROT) + eq(Disease.stagePotency(host), 0, "a still-incubating infection has not erupted into any potency yet") + host.disease.stage = 2 + eq(Disease.stagePotency(host), Disease.defs[Disease.ROT].stagePotency[2], "an erupted stage reports its own listed potency") +end + +function tests.gameMonsterMeleeCanInfectThePlayerViaABiteCarryingSpeciesButNeverStacksASecondInfection() + local game = stagedGame(1, arena(21, 11), 3, 6) + local rat = Monsters.create(Monsters.byKey.rat, 1, 4, 6, 1) + game.level.entities = { rat } + game.player.hp = 10000 + game.player.maxHp = 10000 + local infected = false + for _ = 1, 400 do + game:monsterMelee(rat) + if Disease.isInfected(game.player) then infected = true; break end + end + ok(infected, "enough bites from a parasite-carrying species eventually infect the player") + eq(game.player.disease.key, Disease.PARASITES, "the player caught exactly the species' own carried affliction") + local firstIncubation = game.player.disease.incubation + for _ = 1, 50 do + game:monsterMelee(rat) + end + ok(game.player.disease.incubation <= firstIncubation, "further bites while already sick never restart or stack a second infection") +end + +function tests.gameMonsterMeleeNeverInfectsFromASpeciesWithNoBiteDisease() + local game = stagedGame(1, arena(21, 11), 3, 6) + local goblin = Monsters.create(Monsters.byKey.goblin, 1, 4, 6, 1) + eq(goblin.biteDisease, nil, "a goblin carries no disease of its own to begin with") + game.level.entities = { goblin } + game.player.hp = 10000 + game.player.maxHp = 10000 + for _ = 1, 400 do + game:monsterMelee(goblin) + end + ok(not Disease.isInfected(game.player), "four hundred goblin bites never infect anyone, since goblins carry nothing to catch") +end + +function tests.gameEndPlayerTurnTicksThePlayersDiseaseAndLogsItsEruption() + local game = stagedGame(1, arena(21, 11), 3, 6) + Disease.infect(game.player, Disease.PARASITES) + local incubation = Disease.defs[Disease.PARASITES].incubation + for _ = 1, incubation - 1 do end local order = {