test: cover tests.potionOfFortificationAppliesAShield
This commit is contained in:
1 parent
73de8d4a93
commit
bc7d3c88d5
1 file changed
+173
+173
@@ -3762,6 +3762,179 @@ function tests.herbItemsSurviveSerialization()
|
||||
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
|
||||
local restoredHerb
|
||||
for _, item in ipairs(restored.player.inventory) do
|
||||
if item.kind == Items.HERB then restoredHerb = item end
|
||||
end
|
||||
ok(restoredHerb ~= nil, "a foraged herb survives a save/load round trip")
|
||||
eq(restoredHerb.herb, Alchemy.NIGHTCAP, "a herb's species survives a save/load round trip")
|
||||
end
|
||||
|
||||
function tests.potionOfFortificationAppliesAShield()
|
||||
local game = Game.new(31)
|
||||
Effects.apply("fortify", game, game.player, {})
|
||||
ok(Status.has(game.player, Status.SHIELD), "a fortify effect wards the drinker")
|
||||
end
|
||||
|
||||
function tests.usingAFortifyPotionAppliesShieldAndConsumesIt()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local potion = Items.potionOf("fortify")
|
||||
game.player.inventory = { potion }
|
||||
ok(game:useItem(1), "drinking a fortify potion succeeds")
|
||||
eq(#game.player.inventory, 0, "drinking the potion consumes it")
|
||||
ok(Status.has(game.player, Status.SHIELD), "the fortify potion wards the player")
|
||||
end
|
||||
|
||||
function tests.potionOfLevitationAppliesTheLevitateStatus()
|
||||
local game = Game.new(31)
|
||||
Effects.apply("levitate", game, game.player, {})
|
||||
ok(Status.has(game.player, Status.LEVITATE), "a levitate effect lifts the drinker off the ground")
|
||||
end
|
||||
|
||||
function tests.usingAPotionOfLevitationAppliesLevitateAndConsumesIt()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local potion = Items.potionOf("levitate")
|
||||
game.player.inventory = { potion }
|
||||
ok(game:useItem(1), "drinking a levitation potion succeeds")
|
||||
eq(#game.player.inventory, 0, "drinking the potion consumes it")
|
||||
ok(Status.has(game.player, Status.LEVITATE), "the levitation potion lifts the player off the ground")
|
||||
end
|
||||
|
||||
function tests.companionSummonPlacesItAdjacentToThePlayer()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
ok(hound ~= nil, "summoning a valid species succeeds next to the player")
|
||||
eq(hound.kind, "companion", "a summoned companion is tagged with the companion kind")
|
||||
eq(math.max(math.abs(hound.x - 5), math.abs(hound.y - 5)), 1, "the companion lands adjacent to the player")
|
||||
eq(#game.level.entities, 1, "the companion joins the level's entity list")
|
||||
end
|
||||
|
||||
function tests.companionSummonRejectsAnUnknownSpecies()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
eq(Companions.summon(game, "wyrm"), nil, "an unknown species key summons nothing")
|
||||
eq(#game.level.entities, 0, "no entity is added for an unknown species")
|
||||
end
|
||||
|
||||
function tests.companionSummonReplacesAnEarlierBond()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local first = Companions.summon(game, "hound")
|
||||
local second = Companions.summon(game, "golem")
|
||||
ok(not first:isAlive(), "bonding a new companion retires the earlier one")
|
||||
ok(second:isAlive(), "the freshly bonded companion is alive")
|
||||
local alive = 0
|
||||
for _, e in ipairs(game.level.entities) do
|
||||
if e.kind == "companion" and e:isAlive() then alive = alive + 1 end
|
||||
end
|
||||
eq(alive, 1, "only one companion is ever alive at a time")
|
||||
end
|
||||
|
||||
function tests.companionAttacksAdjacentHostileMonsterAndCanKillIt()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 50, hound.x + 1, hound.y, 1)
|
||||
game.level.entities[#game.level.entities + 1] = rat
|
||||
local xpBefore = game.player.xp
|
||||
Companions.act(game, hound)
|
||||
eq(rat.hp, 0, "a hound's hit kills the weak rat standing next to it")
|
||||
ok(game.player.xp > xpBefore, "the player is credited xp for its companion's kill")
|
||||
end
|
||||
|
||||
-- Before this fix, companions.lua's own "adjacent" helper was Manhattan-1
|
||||
-- (cardinal only) while mercenaries.lua's and reanimation.lua's were
|
||||
-- Chebyshev-1 (8-directional) despite both explicitly claiming to mirror
|
||||
-- Companions.act's "same three-branch shape" - a hound diagonally next to a
|
||||
-- monster fell through to stepMonsterToward instead of attacking, unlike a
|
||||
-- hireling or thrall caught in the identical geometry.
|
||||
function tests.companionAttacksADiagonallyAdjacentHostileMonsterJustLikeACardinalOne()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 50, hound.x + 1, hound.y + 1, 1)
|
||||
game.level.entities[#game.level.entities + 1] = rat
|
||||
Companions.act(game, hound)
|
||||
eq(rat.hp, 0, "a hound's hit kills a weak rat standing diagonally next to it, not just cardinally")
|
||||
end
|
||||
|
||||
function tests.companionAdvancesOnAVisibleMonsterItCannotYetReach()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 50, hound.x + 5, hound.y, 1)
|
||||
game.level.entities[#game.level.entities + 1] = orc
|
||||
local startX = hound.x
|
||||
Companions.act(game, hound)
|
||||
ok(hound.x > startX, "the companion closes the distance to a monster it can see but not reach")
|
||||
end
|
||||
|
||||
function tests.companionIgnoresAMonsterBeyondItsSightRadius()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 50, 19, 9, 1)
|
||||
game.level.entities[#game.level.entities + 1] = orc
|
||||
local startX, startY = hound.x, hound.y
|
||||
Companions.act(game, hound)
|
||||
eq(hound.x, startX, "a monster far outside sight range does not pull the companion off course (x)")
|
||||
eq(hound.y, startY, "a monster far outside sight range does not pull the companion off course (y)")
|
||||
end
|
||||
|
||||
-- Before Companions.act's own nearestHostile clamped its sight to melee
|
||||
-- range under Status.BLIND, a blinded companion kept its full listed sight
|
||||
-- radius - the same gap Game:canSeePlayer's own clamp already closed for a
|
||||
-- blinded hostile monster (canSeePlayerBlindedMonsterOnlyDetectsThePlayer
|
||||
-- AtMeleeRange), just never mirrored onto the ally side.
|
||||
function tests.companionActBlindedCompanionOnlyDetectsAnAdjacentHostileNotOneWithinItsSightRadius()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local farOrc = Monsters.create(Monsters.byKey.orc, 50, hound.x + 5, hound.y, 1)
|
||||
game.level.entities[#game.level.entities + 1] = farOrc
|
||||
Status.apply(hound, Status.BLIND, 6, 1)
|
||||
local startX = hound.x
|
||||
Companions.act(game, hound)
|
||||
eq(hound.x, startX, "a blinded companion loses a sighting well within its listed sight radius")
|
||||
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 51, hound.x + 1, hound.y, 1)
|
||||
game.level.entities[#game.level.entities + 1] = rat
|
||||
local ratHpBefore = rat.hp
|
||||
Companions.act(game, hound)
|
||||
ok(rat.hp < ratHpBefore, "a blinded companion still fights a hostile once it stands adjacent")
|
||||
end
|
||||
|
||||
-- Companions.act called Combat.attack directly without ever routing through
|
||||
-- Game:emitNoise, unlike Game:playerAttack/Game:monsterMelee which both do
|
||||
-- (see gamePlayerAttackCanStirADormantBystanderThatIsNotEvenTheTarget and
|
||||
-- gameMonsterMeleeCanStirADormantBystanderTooNotJustPlayerActions) - a
|
||||
-- companion's own melee was silent to every dormant monster nearby, no
|
||||
-- matter how loud its species' attack would be for the player or a hostile.
|
||||
-- Fresh game per seed (unlike those two tests' single reused game) since a
|
||||
-- companion attack, unlike a repeatable playerAttack/monsterMelee call, can
|
||||
-- kill its one-hp-pool rat target outright.
|
||||
function tests.companionActAttackingAnAdjacentMonsterEmitsNoiseThatCanStirADormantBystander()
|
||||
local stirred = false
|
||||
for seed = 1, 200 do
|
||||
local game = stagedGame(seed, arena(21, 11), 3, 6)
|
||||
local hound = Companions.summon(game, "hound")
|
||||
local target = Monsters.create(Monsters.byKey.rat, 50, hound.x + 1, hound.y, 1)
|
||||
local bystander = Monsters.create(Monsters.byKey.orc, 51, hound.x + 4, hound.y, 1)
|
||||
bystander.awareness = Stealth.DORMANT
|
||||
game.level.entities[#game.level.entities + 1] = target
|
||||
game.level.entities[#game.level.entities + 1] = bystander
|
||||
Companions.act(game, hound)
|
||||
if bystander.awareness ~= Stealth.DORMANT then stirred = true; break end
|
||||
end
|
||||
ok(stirred, "a companion's own melee is exactly as loud as the player's or a hostile monster's")
|
||||
end
|
||||
|
||||
function tests.companionFollowsThePlayerWhenNoMonsterIsVisible()
|
||||
local game = stagedGame(1, arena(21, 11), 10, 5)
|
||||
local golem = Companions.summon(game, "golem")
|
||||
golem.x, golem.y = 3, 5
|
||||
local startDist = math.abs(golem.x - game.player.x)
|
||||
Companions.act(game, golem)
|
||||
ok(math.abs(golem.x - game.player.x) < startDist, "a companion with no monster in sight closes in on the player")
|
||||
end
|
||||
|
||||
-- Companions.act never dispatches through ai.lua, so without Game:allyActs
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user