test: cover tests.autopilotHiresACarriedContractWhenNoHirelingIsYetUn...
This commit is contained in:
1 parent
277f28a49e
commit
4d07d9597f
1 file changed
+173
+173
@@ -4454,6 +4454,179 @@ function tests.shopStockCanRollAContractWithAPositiveCatalogPrice()
|
||||
local sawContract = false
|
||||
for seed = 1, 40 do
|
||||
for _, item in ipairs(Shop.stock(Rng.new(seed))) do
|
||||
if item.kind == Items.CONTRACT then
|
||||
sawContract = true
|
||||
ok(Shop.priceOf(item) > 0, "a rolled contract carries a positive catalog price")
|
||||
ok(Mercenaries.byKey[item.hireling] ~= nil, "a rolled contract names a real roster key")
|
||||
end
|
||||
end
|
||||
end
|
||||
ok(sawContract, "shop stock can roll a mercenary contract across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.autopilotHiresACarriedContractWhenNoHirelingIsYetUnderContract()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.level.entities = {}
|
||||
game.player.inventory = { Items.contract("skirmisher") }
|
||||
game:choosePlayerAction()
|
||||
eq(#game.player.inventory, 0, "the autopilot uses a carried contract on sight when no hireling is yet under contract")
|
||||
local hired = false
|
||||
for _, e in ipairs(game.level.entities) do
|
||||
if e.kind == "hireling" then hired = true end
|
||||
end
|
||||
ok(hired, "the autopilot's contract use actually hires the mercenary")
|
||||
end
|
||||
|
||||
function tests.artifactsCreateBuildsTheCatalogedItemShape()
|
||||
local blade = Artifacts.create("bloodfang")
|
||||
eq(blade.kind, Items.WEAPON, "bloodfang is a weapon-slot artifact")
|
||||
eq(blade.unique, Artifacts.LIFESTEAL, "bloodfang carries the lifesteal tag")
|
||||
eq(blade.artifact, "bloodfang", "the item remembers its catalog key")
|
||||
local ring = Artifacts.create("ring_of_the_tide")
|
||||
eq(ring.kind, Items.RING, "ring of the tide is a ring-slot artifact")
|
||||
eq(ring.unique, Artifacts.REGEN, "ring of the tide carries the regen tag")
|
||||
eq(Artifacts.create("nonexistent"), nil, "an unknown catalog key builds nothing")
|
||||
end
|
||||
|
||||
function tests.lifestealWeaponHealsThePlayerOnAHit()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipWeapon(Artifacts.create("bloodfang"), game.player)
|
||||
game.player.hp = game.player.maxHp - 10
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
orc.hp, orc.maxHp = 30, 30
|
||||
game.level.entities = { orc }
|
||||
local before = game.player.hp
|
||||
game:playerAttack(orc)
|
||||
ok(game.player.hp > before, "bloodfang heals the player for a share of the damage it deals")
|
||||
end
|
||||
|
||||
function tests.thornedArmorReflectsDamageBackAtAMeleeAttacker()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipArmor(Artifacts.create("aegis_of_embers"), game.player)
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
game.level.entities = { orc }
|
||||
local before = orc.hp
|
||||
game:monsterMelee(orc)
|
||||
ok(orc.hp < before, "aegis of embers burns the monster that hits its wearer")
|
||||
end
|
||||
|
||||
function tests.thornedArmorCanKillAWeakAttacker()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipArmor(Artifacts.create("aegis_of_embers"), game.player)
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 4, 6, 1)
|
||||
rat.hp, rat.maxHp = 1, 1
|
||||
game.level.entities = { rat }
|
||||
local xpBefore = game.player.xp
|
||||
game:monsterMelee(rat)
|
||||
ok(not rat:isAlive(), "a thorn burn can finish off a weak attacker")
|
||||
ok(game.player.xp > xpBefore, "the player is credited xp for a thorn kill")
|
||||
end
|
||||
|
||||
-- Aegis of Embers is fire damage by name ("Embers") and by its own log line
|
||||
-- ("your armor sears") - before this fix the reflect subtracted a raw amount
|
||||
-- straight off the attacker's hp with no Resistances.apply call at all, so a
|
||||
-- fire-immune dragon (bestiary-real, reachable from depth 6) burned through
|
||||
-- its own immunity attacking a thorned wearer. Same shape of bug
|
||||
-- fighterCleaveSplashRespectsAFireImmuneTargetLikeThePrimaryHitAlreadyDoes
|
||||
-- caught in skills.lua earlier the same day, this time in the thorns path.
|
||||
function tests.thornedArmorRespectsAFireImmuneAttacker()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipArmor(Artifacts.create("aegis_of_embers"), game.player)
|
||||
local dragon = Monsters.create(Monsters.byKey.dragon, 1, 4, 6, 1)
|
||||
game.level.entities = { dragon }
|
||||
local before = dragon.hp
|
||||
game:monsterMelee(dragon)
|
||||
eq(dragon.hp, before, "a fire-immune dragon takes zero thorns reflect from a fire-flavoured artifact")
|
||||
end
|
||||
|
||||
function tests.thornedArmorIsHalvedAgainstAFireResistantAttacker()
|
||||
local function reflectDealt(resistant)
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipArmor(Artifacts.create("aegis_of_embers"), game.player)
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
orc.hp, orc.maxHp = 100, 100
|
||||
if resistant then orc.resist = { fire = Resistances.RESIST } end
|
||||
game.level.entities = { orc }
|
||||
game:monsterMelee(orc)
|
||||
return 100 - orc.hp
|
||||
end
|
||||
local plain = reflectDealt(false)
|
||||
local resisted = reflectDealt(true)
|
||||
ok(resisted < plain, "a fire-resistant attacker takes measurably less thorns reflect than an unresisted one")
|
||||
eq(resisted, math.floor(plain / 2), "fire resistance halves the thorns reflect, the same mitigation Resistances.apply gives every other fire source")
|
||||
end
|
||||
|
||||
function tests.ringOfTheTideRegeneratesHpEachTurn()
|
||||
local game = Game.new(1)
|
||||
Items.equipRing(Artifacts.create("ring_of_the_tide"), game.player)
|
||||
game.player.hp = game.player.maxHp - 10
|
||||
local before = game.player.hp
|
||||
game:hungerTorchTick()
|
||||
eq(game.player.hp, before + 2, "ring of the tide regenerates its fixed amount each turn")
|
||||
end
|
||||
|
||||
function tests.piercingBowIgnoresPartOfTargetDefense()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.baseAttack = 5
|
||||
Items.equipBow(Artifacts.create("gale_bow"), game.player)
|
||||
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 5)
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
orc.defense, orc.baseDefense, orc.hp, orc.maxHp = 6, 6, 40, 40
|
||||
game.level.entities = { orc }
|
||||
game:fireAt(orc)
|
||||
eq(orc.hp, 35, "a piercing bow's shot ignores a flat share of the target's defense")
|
||||
end
|
||||
|
||||
function tests.builderOccasionallyPlacesAnArtifactFromDepthFive()
|
||||
local level = Builder.build(5, Rng.new(4), {})
|
||||
local found
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.artifact then found = ground.item end
|
||||
end
|
||||
ok(found ~= nil, "this seed's depth-5 floor places a named artifact")
|
||||
ok(Artifacts.byKey[found.artifact] ~= nil, "the artifact names a real catalog entry")
|
||||
end
|
||||
|
||||
function tests.artifactsStayOffFloorsAboveDepthFive()
|
||||
for seed = 1, 4 do
|
||||
for depth = 1, 4 do
|
||||
local level = Builder.build(depth, Rng.new(seed), {})
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
ok(not ground.item.artifact, "no artifact appears above depth 5")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function tests.artifactFieldsSurviveSerialization()
|
||||
local game = Game.new(3)
|
||||
Items.equipWeapon(Artifacts.create("bloodfang"), game.player)
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
eq(restored.player.weapon.artifact, "bloodfang", "an equipped artifact's catalog key survives a save/load round trip")
|
||||
eq(restored.player.weapon.unique, Artifacts.LIFESTEAL, "an equipped artifact's unique tag survives a save/load round trip")
|
||||
eq(restored.player.weapon.value, 0.5, "an equipped artifact's tuning value survives a save/load round trip")
|
||||
end
|
||||
|
||||
function tests.useItemOnAKitPlantsAHiddenTrapOnThePlayersTile()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.player.inventory = { Items.kit("dart") }
|
||||
ok(game:useItem(1), "using a trap kit succeeds")
|
||||
eq(#game.player.inventory, 0, "the kit leaves the inventory once planted")
|
||||
local trap = game.level:trapAt(5, 5)
|
||||
ok(trap ~= nil, "a trap is planted on the player's tile")
|
||||
eq(trap.effect, "dart", "the planted trap matches the kit's effect")
|
||||
eq(trap.revealed, false, "a freshly planted trap starts hidden")
|
||||
eq(game.level.map:get(5, 5), Tiles.FLOOR, "a hidden trap does not change the tile's glyph")
|
||||
end
|
||||
|
||||
function tests.plantingATrapWhereOneAlreadyExistsFails()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.level.traps = { { x = 5, y = 5, effect = "poison", revealed = false } }
|
||||
game.player.inventory = { Items.kit("dart") }
|
||||
ok(not game:useItem(1), "planting a trap on an occupied tile fails")
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user