test: cover tests.momentumFieldSurvivesSerialization
This commit is contained in:
1 parent
3115db3fe3
commit
607c19a95f
1 file changed
+173
+173
@@ -7568,6 +7568,179 @@ function tests.renderPanelShowsComboOnlyOnceItIsBuilt()
|
|||||||
ok(contains(Render.panel(game), "combo x3"), "a built-up combo is reported in the status panel")
|
ok(contains(Render.panel(game), "combo x3"), "a built-up combo is reported in the status panel")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tests.momentumFieldSurvivesSerialization()
|
||||||
|
local game = Game.new(3)
|
||||||
|
game.player.combo = 4
|
||||||
|
local path = os.tmpname()
|
||||||
|
game:save(path)
|
||||||
|
local restored = Game.load(path)
|
||||||
|
os.remove(path)
|
||||||
|
eq(restored.player.combo, 4, "the player's momentum stack survives a save/load round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityIsWetReadsTheEntitysOwnWetField()
|
||||||
|
eq(Conductivity.isWet({}), false, "an entity with no wet field at all reads as dry")
|
||||||
|
eq(Conductivity.isWet({ wet = 0 }), false, "a wet counter already run down to zero reads as dry")
|
||||||
|
eq(Conductivity.isWet({ wet = 1 }), true, "any positive wet counter reads as wet")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityTickSoaksOnWaterAndDecaysOneStepAtATimeOffIt()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
level.map:set(6, 6, Tiles.WATER)
|
||||||
|
local entity = { x = 6, y = 6 }
|
||||||
|
Conductivity.tick(level, entity)
|
||||||
|
eq(entity.wet, Conductivity.SOAK_DURATION, "standing on water soaks an entity to the full duration")
|
||||||
|
entity.x = 7
|
||||||
|
for i = Conductivity.SOAK_DURATION - 1, 0, -1 do
|
||||||
|
Conductivity.tick(level, entity)
|
||||||
|
eq(entity.wet, i, "the soak counter decays by exactly one per turn spent off water")
|
||||||
|
end
|
||||||
|
eq(Conductivity.isWet(entity), false, "the counter bottoms out at zero rather than going negative")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityTickReSoaksImmediatelyOnSteppingBackOntoWater()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
level.map:set(6, 6, Tiles.WATER)
|
||||||
|
local entity = { x = 6, y = 6, wet = 1 }
|
||||||
|
Conductivity.tick(level, entity)
|
||||||
|
eq(entity.wet, Conductivity.SOAK_DURATION,
|
||||||
|
"stepping back onto water refreshes the counter to full rather than adding to it")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityApplyFireDampensDamageOnlyOnceSoaked()
|
||||||
|
eq(Conductivity.applyFire({}, 10), 10, "fire damage against a dry entity is untouched")
|
||||||
|
eq(Conductivity.applyFire({ wet = 2 }, 10), 5,
|
||||||
|
"fire damage against a soaked entity is halved on top of its resistance tier")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityApplyLightningBonusesDamageOnlyOnceSoaked()
|
||||||
|
eq(Conductivity.applyLightning({}, 10), 10, "lightning damage against a dry entity is untouched")
|
||||||
|
eq(Conductivity.applyLightning({ wet = 2 }, 10), 15,
|
||||||
|
"lightning damage against a soaked entity gets a 50 percent conductivity bonus")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityNeverConjuresDamageOutOfAnImmuneResistance()
|
||||||
|
eq(Conductivity.applyFire({ wet = 2, resist = { fire = Resistances.IMMUNE } }, 10), 0,
|
||||||
|
"fire immunity still floors damage at zero even while soaked")
|
||||||
|
eq(Conductivity.applyLightning({ wet = 2, resist = { lightning = Resistances.IMMUNE } }, 10), 0,
|
||||||
|
"lightning immunity still floors damage at zero even while soaked")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.conductivityResistsIgnitionOnlyWhileWet()
|
||||||
|
eq(Conductivity.resistsIgnition({}), false, "a dry entity does not resist ignition")
|
||||||
|
eq(Conductivity.resistsIgnition({ wet = 3 }), true, "a soaked entity resists catching fire")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.statusApplyRefusesBurningOnlyWhileSoakedButOtherEffectsStillApply()
|
||||||
|
local entity = Entity.new({ x = 1, y = 1, glyph = "@", name = "you", kind = "player", hp = 20, attack = 6, defense = 2 })
|
||||||
|
entity.wet = 2
|
||||||
|
local result = Status.apply(entity, Status.BURNING, 3, 2)
|
||||||
|
eq(result, nil, "applying burning to a soaked entity is refused outright")
|
||||||
|
eq(Status.has(entity, Status.BURNING), false, "a refused burning application leaves no trace on the entity")
|
||||||
|
Status.apply(entity, Status.POISON, 3, 2)
|
||||||
|
eq(Status.has(entity, Status.POISON), true, "a soaked entity still catches every other status effect normally")
|
||||||
|
entity.wet = 0
|
||||||
|
Status.apply(entity, Status.BURNING, 3, 2)
|
||||||
|
eq(Status.has(entity, Status.BURNING), true, "once dry again, the same entity catches fire normally")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.statusRemoveStripsANamedStatusRegardlessOfItsRemainingDuration()
|
||||||
|
local entity = Entity.new({ x = 1, y = 1, glyph = "@", name = "you", kind = "player", hp = 20, attack = 6, defense = 2 })
|
||||||
|
Status.apply(entity, Status.POISON, 99, 2)
|
||||||
|
eq(Status.remove(entity, Status.POISON), true, "removing a status that is present reports success")
|
||||||
|
eq(Status.has(entity, Status.POISON), false, "the removed status no longer reads as active")
|
||||||
|
eq(Status.remove(entity, Status.POISON), false, "removing an already-absent status reports nothing to do")
|
||||||
|
eq(Status.remove(entity, Status.CONFUSE), false, "removing a status that was never applied at all also reports nothing to do")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.statusCureHostileLiftsEveryDebuffButLeavesBuffsUntouched()
|
||||||
|
local entity = Entity.new({ x = 1, y = 1, glyph = "@", name = "you", kind = "player", hp = 20, attack = 6, defense = 2 })
|
||||||
|
Status.apply(entity, Status.POISON, 5, 2)
|
||||||
|
Status.apply(entity, Status.CONFUSE, 6, 1)
|
||||||
|
Status.apply(entity, Status.STUN, 2, 1)
|
||||||
|
Status.apply(entity, Status.STRENGTH, 30, 3)
|
||||||
|
Status.apply(entity, Status.SHIELD, 15, 1)
|
||||||
|
local lifted = Status.cureHostile(entity)
|
||||||
|
eq(#lifted, 3, "cureHostile reports exactly the three debuffs it lifted")
|
||||||
|
eq(Status.has(entity, Status.POISON), false, "poison is gone after cureHostile")
|
||||||
|
eq(Status.has(entity, Status.CONFUSE), false, "confuse is gone after cureHostile")
|
||||||
|
eq(Status.has(entity, Status.STUN), false, "stun is gone after cureHostile")
|
||||||
|
ok(Status.has(entity, Status.STRENGTH), "a buff like strength survives cureHostile untouched")
|
||||||
|
ok(Status.has(entity, Status.SHIELD), "a buff like shield survives cureHostile untouched")
|
||||||
|
eq(#Status.cureHostile(entity), 0, "calling cureHostile again with nothing hostile left returns an empty list")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.hazardsAfflictDampensFireAndBlocksIgnitionForASoakedVictim()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
Hazards.ignite(level, 5, 5, 3, 4)
|
||||||
|
local victim = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||||
|
victim.wet = 2
|
||||||
|
local hpBefore = victim.hp
|
||||||
|
local line = Hazards.afflict(level, victim)
|
||||||
|
eq(victim.hp, hpBefore - 2, "standing in fire while soaked only deals half the usual potency")
|
||||||
|
ok(contains(line, "soaked"), "the afflict message calls out the victim's own soaked skin")
|
||||||
|
eq(Status.has(victim, Status.BURNING), false, "a soaked victim standing in fire never actually catches alight")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameConductivityTicksAMonsterEachTurnBasedOnTheTileUnderfoot()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
level.map:set(6, 6, Tiles.WATER)
|
||||||
|
local game = stagedGame(1, level, 3, 6)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
|
||||||
|
game.level.entities = { rat }
|
||||||
|
game:takeMonsterTurn(rat)
|
||||||
|
eq(rat.wet, Conductivity.SOAK_DURATION, "a monster ending its turn on water is soaked to the full duration")
|
||||||
|
rat.x, rat.y = 7, 6
|
||||||
|
game:takeMonsterTurn(rat)
|
||||||
|
eq(rat.wet, Conductivity.SOAK_DURATION - 1, "moving off water the following turn lets the soak counter decay by one")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameConductivityTicksThePlayerEachAutoStepBasedOnTheTileUnderfoot()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
level.map:set(3, 6, Tiles.WATER)
|
||||||
|
local game = stagedGame(1, level, 3, 6)
|
||||||
|
game:autoStep()
|
||||||
|
eq(game.player.wet, Conductivity.SOAK_DURATION, "the player ending a turn on water is soaked to the full duration")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.spellShockBoltDealsMoreDamageToASoakedTargetThanADryOne()
|
||||||
|
local dryGame = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
Spells.learn(dryGame.player, "shock")
|
||||||
|
local dry = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||||
|
dry.hp, dry.maxHp = 100, 100
|
||||||
|
dryGame.level.entities = { dry }
|
||||||
|
local castOk = dryGame:castSpell("shock", dry)
|
||||||
|
ok(castOk, "casting a learned, in-range shock bolt succeeds")
|
||||||
|
local dryDealt = 100 - dry.hp
|
||||||
|
ok(dryDealt > 0, "shock bolt deals real lightning damage to a dry target")
|
||||||
|
|
||||||
|
local wetGame = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
Spells.learn(wetGame.player, "shock")
|
||||||
|
local soaked = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||||
|
soaked.hp, soaked.maxHp = 100, 100
|
||||||
|
soaked.wet = 2
|
||||||
|
wetGame.level.entities = { soaked }
|
||||||
|
wetGame:castSpell("shock", soaked)
|
||||||
|
local wetDealt = 100 - soaked.hp
|
||||||
|
eq(wetDealt, dryDealt + dryDealt // 2,
|
||||||
|
"shock bolt deals exactly its 50 percent conductivity bonus against a soaked target")
|
||||||
|
ok(contains(wetGame.log:last(), "water clinging"),
|
||||||
|
"casting shock bolt on a soaked target reports the conductivity through water")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.renderPanelShowsWetOnlyWhileSoaked()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
ok(not contains(Render.panel(game), "wet"), "a fresh dry player shows no wet line")
|
||||||
|
game.player.wet = 2
|
||||||
|
ok(contains(Render.panel(game), "wet (2)"), "a soaked player's status panel reports the remaining soak turns")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.builderCanRollATomeOfTheShockBoltSpell()
|
||||||
|
-- Range widened from 100 to 200: adding "cleanse" to Builder's `learnable`
|
||||||
|
-- list shifted rng:range(1, #learnable)'s result for effectively every
|
||||||
|
-- seed, and the nearest shock tome under the new list happens to sit at
|
||||||
|
-- seed 174 - still well within "a reasonable seed range".
|
||||||
|
local found
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user