test: cover tests.throwingAndRangedDamageRespectResistance
This commit is contained in:
1 parent
3fe669ab4b
commit
90bf3238ac
1 file changed
+173
+173
@@ -5492,6 +5492,179 @@ function tests.hazardsAfflictAppliesTargetResistance()
|
||||
end
|
||||
|
||||
function tests.spellMissileAndFireballRespectTargetResistance()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local wisp = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
wisp.hp, wisp.maxHp = 40, 40
|
||||
wisp.resist = { arcane = Resistances.IMMUNE }
|
||||
game.level.entities = { wisp }
|
||||
game:castSpell("missile", wisp)
|
||||
eq(wisp.hp, 40, "an arcane-immune target takes no damage from magic missile")
|
||||
|
||||
local blastGame = stagedGame(2, arena(21, 11), 5, 6)
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
orc.hp, orc.maxHp = 20, 20
|
||||
orc.resist = { fire = Resistances.RESIST }
|
||||
blastGame.level.entities = { orc }
|
||||
Effects.apply("fireball", blastGame, blastGame.player, {})
|
||||
eq(orc.hp, 16, "a fire-resistant target only takes half of fireball's flat burn")
|
||||
end
|
||||
|
||||
function tests.throwingAndRangedDamageRespectResistance()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local flamingDagger = Affixes.decorate(Items.weapon("dagger", 3), Affixes.weapon[3])
|
||||
game.player.inventory[#game.player.inventory + 1] = flamingDagger
|
||||
local salamander = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
salamander.hp, salamander.maxHp = 40, 40
|
||||
salamander.resist = { fire = Resistances.IMMUNE }
|
||||
game.level.entities = { salamander }
|
||||
local success = game:throwAt(#game.player.inventory, salamander)
|
||||
ok(success, "the throw itself still leaves the thrower's hand")
|
||||
eq(salamander.hp, 40, "a fire-immune target takes no damage from a thrown flaming weapon")
|
||||
|
||||
local rangedGame = stagedGame(1, arena(21, 11), 3, 6)
|
||||
rangedGame.player.bow = Items.bow("longbow", 3, 6)
|
||||
rangedGame.player.inventory[#rangedGame.player.inventory + 1] = Items.ammo("arrow", 5)
|
||||
local armored = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
armored.hp, armored.maxHp = 40, 40
|
||||
armored.resist = { physical = Resistances.RESIST }
|
||||
rangedGame.level.entities = { armored }
|
||||
rangedGame:fireAt(armored)
|
||||
eq(armored.hp, 37, "physical resistance halves the arrow's already-defense-reduced damage")
|
||||
end
|
||||
|
||||
function tests.equippingCinderplateAndFrostbandGrantsTheirResist()
|
||||
local wearer = Entity.new({ x = 1, y = 1, glyph = "@", name = "you", kind = "player", hp = 20, maxHp = 20, attack = 5, defense = 1 })
|
||||
Items.equipArmor(Artifacts.create("cinderplate"), wearer)
|
||||
eq(Resistances.tierOf(wearer, Resistances.FIRE), Resistances.RESIST, "cinderplate grants fire resist while worn")
|
||||
Items.equipRing(Artifacts.create("frostband"), wearer)
|
||||
eq(Resistances.tierOf(wearer, Resistances.COLD), Resistances.RESIST, "frostband grants cold resist while worn")
|
||||
eq(Resistances.tierOf(wearer, Resistances.POISON), Resistances.NORMAL, "neither artifact grants a resist it was not built for")
|
||||
end
|
||||
|
||||
function tests.disenchantingAnElementalAffixClearsItsDamageType()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local weapon = Affixes.decorate(Items.weapon("dagger", 2), Affixes.weapon[4])
|
||||
Items.equipWeapon(weapon, game.player)
|
||||
eq(weapon.damageType, "poison", "venomed tags the weapon as poison-typed")
|
||||
Crafting.disenchant(game.player, weapon)
|
||||
eq(weapon.damageType, nil, "disenchanting clears the elemental typing along with the affix")
|
||||
end
|
||||
|
||||
function tests.bossBreathDamageTypeMatchesTheMonsterAndCanBeShruggedOff()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local dragon = Monsters.create(Monsters.byKey.dragon, 1, 6, 6, 1)
|
||||
game.level.entities = { dragon }
|
||||
eq(Resistances.tierOf(dragon, Resistances.FIRE), Resistances.IMMUNE, "the bestiary dragon is immune to its own breath element")
|
||||
eq(Resistances.tierOf(dragon, Resistances.COLD), Resistances.WEAK, "the bestiary dragon is innately weak to cold")
|
||||
|
||||
game.player.resist = { fire = Resistances.IMMUNE }
|
||||
local hpBefore = game.player.hp
|
||||
game:monsterShoot(dragon)
|
||||
eq(game.player.hp, hpBefore, "a fire-immune player takes no damage from dragon breath")
|
||||
eq(Status.has(game.player, Status.BURNING), false, "a fire-immune player never catches alight from the breath")
|
||||
end
|
||||
|
||||
function tests.resistFieldsSurviveEntitySerialization()
|
||||
local dragon = Monsters.create(Monsters.byKey.dragon, 1, 5, 5, 6)
|
||||
local restored = Entity.fromData(dragon:toData())
|
||||
eq(Resistances.tierOf(restored, Resistances.FIRE), Resistances.IMMUNE, "a restored entity keeps its innate resist profile")
|
||||
end
|
||||
|
||||
function tests.factionsTierBoundariesReflectReputationScore()
|
||||
eq(Factions.tier(0), "neutral", "a fresh reputation reads neutral")
|
||||
eq(Factions.tier(-10), "unfriendly", "the unfriendly ceiling is inclusive")
|
||||
eq(Factions.tier(-9), "neutral", "one point above the unfriendly ceiling is still neutral")
|
||||
eq(Factions.tier(-30), "hostile", "the hostile ceiling is inclusive")
|
||||
eq(Factions.tier(25), "friendly", "the friendly floor is inclusive")
|
||||
eq(Factions.tier(60), "honored", "the honored floor is inclusive")
|
||||
end
|
||||
|
||||
function tests.factionsAdjustAccumulatesAndClampsToTheHundredBounds()
|
||||
local player = {}
|
||||
Factions.adjust(player, Factions.GOBLINOID, -40)
|
||||
eq(Factions.reputationFor(player, Factions.GOBLINOID), -40, "a first adjustment lands from the implicit zero baseline")
|
||||
Factions.adjust(player, Factions.GOBLINOID, -80)
|
||||
eq(Factions.reputationFor(player, Factions.GOBLINOID), -100, "reputation floors at -100")
|
||||
Factions.adjust(player, Factions.GOBLINOID, 500)
|
||||
eq(Factions.reputationFor(player, Factions.GOBLINOID), 100, "reputation caps at 100")
|
||||
eq(Factions.reputationFor(player, Factions.MERCHANT), 0, "an untouched faction still reads neutral zero")
|
||||
end
|
||||
|
||||
function tests.factionsRegisterKillSoursOnlyTheFallensFaction()
|
||||
local player = {}
|
||||
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 1, 1, 2)
|
||||
Factions.registerKill(player, goblin)
|
||||
eq(Factions.reputationFor(player, Factions.GOBLINOID), -5, "felling a goblin sours goblinoid standing")
|
||||
eq(Factions.reputationFor(player, Factions.VERMIN), 0, "an unrelated faction is left untouched")
|
||||
end
|
||||
|
||||
function tests.factionsRegisterKillPenalizesABossFarMoreThanARegularKill()
|
||||
local player = {}
|
||||
local dragon = Monsters.create(Monsters.byKey.dragon, 1, 1, 1, 6)
|
||||
dragon.isBoss = true
|
||||
Factions.registerKill(player, dragon)
|
||||
eq(Factions.reputationFor(player, Factions.DRAKE), -15, "a boss kill costs three times a rank-and-file kill")
|
||||
end
|
||||
|
||||
function tests.factionsRegisterKillIgnoresAFactionlessTarget()
|
||||
local player = {}
|
||||
Factions.registerKill(player, { faction = nil })
|
||||
eq(player.reputation, nil, "a factionless kill never even creates a reputation table")
|
||||
end
|
||||
|
||||
function tests.factionsPriceMultiplierScalesFromHostileToHonored()
|
||||
local player = {}
|
||||
eq(Factions.priceMultiplier(player, Factions.MERCHANT), 1.0, "a fresh, neutral standing charges catalog price")
|
||||
Factions.adjust(player, Factions.MERCHANT, -40)
|
||||
eq(Factions.priceMultiplier(player, Factions.MERCHANT), 1.5, "a hostile guild marks its prices up")
|
||||
Factions.adjust(player, Factions.MERCHANT, 100)
|
||||
eq(Factions.priceMultiplier(player, Factions.MERCHANT), 0.65, "an honored guild discounts its prices")
|
||||
end
|
||||
|
||||
function tests.factionsIsWaryTrueForAFreshGoblinoidAndFalseOnceProvoked()
|
||||
local player = {}
|
||||
local kobold = Monsters.create(Monsters.byKey.kobold, 1, 1, 1, 1)
|
||||
eq(Factions.isWary(player, kobold), true, "an unprovoked goblinoid starts wary of a stranger")
|
||||
kobold.provoked = true
|
||||
eq(Factions.isWary(player, kobold), false, "a provoked goblinoid is no longer wary")
|
||||
end
|
||||
|
||||
function tests.factionsIsWaryIsFalseForNonTribalFactionsAndOnceTheTribeGoesHostile()
|
||||
local player = {}
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 1, 1, 1)
|
||||
eq(Factions.isWary(player, rat), false, "vermin were never a wary tribe to begin with")
|
||||
local kobold = Monsters.create(Monsters.byKey.kobold, 2, 1, 1, 1)
|
||||
Factions.adjust(player, Factions.GOBLINOID, -40)
|
||||
eq(Factions.isWary(player, kobold), false, "a tribe hated into hostility stops holding back even for a fresh member")
|
||||
end
|
||||
|
||||
function tests.factionsAppeaseSpendsGoldAndRaisesReputationOrFailsWithoutFunds()
|
||||
local player = { gold = 10 }
|
||||
local success, cost = Factions.appease(player, Factions.GOBLINOID)
|
||||
eq(success, false, "an empty purse cannot buy any goodwill")
|
||||
eq(cost, 20, "the failure reports the base tribute cost at neutral standing")
|
||||
eq(player.gold, 10, "a failed tribute spends nothing")
|
||||
player.gold = 100
|
||||
local success2, cost2 = Factions.appease(player, Factions.GOBLINOID)
|
||||
eq(success2, true, "a well-stocked purse can pay the tribute")
|
||||
eq(cost2, 20, "the neutral tribute costs its base amount")
|
||||
eq(player.gold, 80, "the tribute's cost is deducted")
|
||||
eq(Factions.reputationFor(player, Factions.GOBLINOID), 15, "the tribute raises standing by its fixed amount")
|
||||
end
|
||||
|
||||
function tests.factionsAppeaseCostsMoreTheDeeperTheGrudge()
|
||||
local player = { gold = 1000 }
|
||||
Factions.adjust(player, Factions.BANDIT, -30)
|
||||
local _, cost = Factions.appease(player, Factions.BANDIT)
|
||||
eq(cost, 80, "the tribute cost climbs with how negative the standing already is")
|
||||
end
|
||||
|
||||
function tests.factionsAppeaseFailsOnceAFactionIsAlreadyMaxedOut()
|
||||
local player = { gold = 1000, reputation = { [Factions.GOBLINOID] = 100 } }
|
||||
local success, cost = Factions.appease(player, Factions.GOBLINOID)
|
||||
eq(success, false, "an already-maxed relationship has nothing left to buy")
|
||||
eq(cost, 0, "the failure reports there was no cost, not an unaffordable one")
|
||||
eq(player.gold, 1000, "nothing is spent when there is nothing to buy")
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user