test: cover tests.fighterBerserkBoostsAttackAtLowHp
This commit is contained in:
1 parent
f5f4e93cd3
commit
1a36a061ba
1 file changed
+173
+173
@@ -2378,6 +2378,179 @@ function tests.fighterSecondWindRestoresPortionOfMaxHp()
|
||||
|
||||
game.player.skillCooldowns.secondWind = 0
|
||||
game.player.hp = game.player.maxHp - 1
|
||||
game:useSkill("secondWind")
|
||||
eq(game.player.hp, game.player.maxHp, "second wind never heals past max hp")
|
||||
end
|
||||
|
||||
function tests.fighterBerserkBoostsAttackAtLowHp()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "fighter"
|
||||
game.player.skills.berserk = true
|
||||
local full = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
game.level.entities = { full }
|
||||
game.player.hp = game.player.maxHp
|
||||
game:playerAttack(full)
|
||||
local dmgFull = full.maxHp - full.hp
|
||||
|
||||
local game2 = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game2.player.class = "fighter"
|
||||
game2.player.skills.berserk = true
|
||||
local low = Monsters.create(Monsters.byKey.orc, 2, 4, 6, 1)
|
||||
game2.level.entities = { low }
|
||||
game2.player.hp = math.floor(game2.player.maxHp * 0.3)
|
||||
game2:playerAttack(low)
|
||||
local dmgLow = low.maxHp - low.hp
|
||||
|
||||
ok(dmgLow > dmgFull, "berserk raises attack once hp drops to a third of max")
|
||||
end
|
||||
|
||||
function tests.rogueBackstabDoublesDamageOnFullHpTarget()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "rogue"
|
||||
game.player.skills.backstab = true
|
||||
local fresh = Monsters.create(Monsters.byKey.rat, 1, 4, 6, 1)
|
||||
game.level.entities = { fresh }
|
||||
game:playerAttack(fresh)
|
||||
local dmgFresh = fresh.maxHp - fresh.hp
|
||||
|
||||
local game2 = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game2.player.class = "rogue"
|
||||
game2.player.skills.backstab = true
|
||||
local hurt = Monsters.create(Monsters.byKey.rat, 2, 4, 6, 1)
|
||||
hurt.hp = hurt.hp - 1
|
||||
game2.level.entities = { hurt }
|
||||
game2:playerAttack(hurt)
|
||||
local dmgHurt = (hurt.maxHp - 1) - hurt.hp
|
||||
|
||||
eq(dmgFresh, dmgHurt * 2, "backstab doubles damage against a target still at full hp")
|
||||
end
|
||||
|
||||
function tests.rogueEvasionCanFullyNegateMeleeHit()
|
||||
local defender = { skills = { evasion = true } }
|
||||
local sawDodge, sawHit = false, false
|
||||
local rng = Rng.new(1)
|
||||
for _ = 1, 60 do
|
||||
if Skills.evades({ rng = rng }, defender) then sawDodge = true else sawHit = true end
|
||||
end
|
||||
ok(sawDodge, "evasion dodges at least once over enough attempts")
|
||||
ok(sawHit, "evasion is a chance, not a guarantee, over enough attempts")
|
||||
eq(Skills.evades({ rng = Rng.new(1) }, {}), false, "a defender without the skill never evades")
|
||||
end
|
||||
|
||||
function tests.poisonBladeAppliesPoisonOnNextMeleeHitOnly()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "rogue"
|
||||
game.player.skills.poisonBlade = true
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
orc.hp, orc.maxHp = 100, 100
|
||||
game.level.entities = { orc }
|
||||
eq(game:useSkill("poisonBlade"), true, "poison blade readies without needing a target")
|
||||
game:playerAttack(orc)
|
||||
ok(Status.has(orc, Status.POISON), "the readied venom lands on the very next melee hit")
|
||||
orc.statuses = {}
|
||||
game:playerAttack(orc)
|
||||
eq(Status.has(orc, Status.POISON), false, "poison blade is spent after one hit, not reapplied on the next")
|
||||
end
|
||||
|
||||
-- pendingPoisonBlade lives on the player between "ready the venom" and "land
|
||||
-- the next swing" - a window a save/quit can happen inside, exactly like
|
||||
-- reputation, sanity or the skill tree already have to survive Game:toData.
|
||||
function tests.pendingPoisonBladeReadinessSurvivesAGameSaveLoadRoundTrip()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "rogue"
|
||||
game.player.skills.poisonBlade = true
|
||||
eq(game:useSkill("poisonBlade"), true, "poison blade readies without needing a target")
|
||||
eq(game.player.pendingPoisonBlade, true, "readying the skill sets the pending flag before any save/load happens")
|
||||
local restored = Game.fromData(game:toData())
|
||||
eq(restored.player.pendingPoisonBlade, true, "a poison blade readied before a save is still primed after loading it back")
|
||||
ok(Skills.consumePoisonBlade(restored.player), "the restored pending venom is still consumable on the very next swing")
|
||||
end
|
||||
|
||||
function tests.mageOverloadBoostsMissileDamage()
|
||||
local game = stagedGame(5, arena(21, 11), 3, 6)
|
||||
local base = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
game.level.entities = { base }
|
||||
game:castSpell("missile", base)
|
||||
local dmgBase = base.maxHp - base.hp
|
||||
|
||||
local game2 = stagedGame(5, arena(21, 11), 3, 6)
|
||||
game2.player.class = "mage"
|
||||
game2.player.skills.overload = true
|
||||
local boosted = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
game2.level.entities = { boosted }
|
||||
game2:castSpell("missile", boosted)
|
||||
local dmgBoosted = boosted.maxHp - boosted.hp
|
||||
|
||||
ok(dmgBoosted > dmgBase, "overload raises missile spell damage")
|
||||
end
|
||||
|
||||
function tests.mageMeditateRestoresManaWithinCap()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "mage"
|
||||
game.player.skills.meditate = true
|
||||
game.player.mana = 2
|
||||
game:useSkill("meditate")
|
||||
eq(game.player.mana, 8, "meditate restores a flat amount of mana")
|
||||
|
||||
game.player.mana = game.player.maxMana - 1
|
||||
game:useSkill("meditate")
|
||||
eq(game.player.mana, game.player.maxMana, "meditate never overfills the mana pool")
|
||||
end
|
||||
|
||||
function tests.mageManaShieldRaisesDefenseWhileManaHeld()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "mage"
|
||||
game.player.skills.manaShield = true
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||
local before = game.player.hp
|
||||
game.player.mana = 10
|
||||
game:monsterMelee(orc)
|
||||
local dmgWithShield = before - game.player.hp
|
||||
|
||||
game.player.hp = before
|
||||
game.player.mana = 0
|
||||
game:monsterMelee(orc)
|
||||
local dmgWithoutShield = before - game.player.hp
|
||||
|
||||
ok(dmgWithoutShield > dmgWithShield, "mana shield reduces damage taken while mana holds")
|
||||
end
|
||||
|
||||
function tests.rangerMultishotHitsTwoTargetsForOneArrow()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "ranger"
|
||||
game.player.skills.multishot = true
|
||||
game.player.bow = Items.bow("shortbow", 3, 6)
|
||||
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 5)
|
||||
local first = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
local second = Monsters.create(Monsters.byKey.orc, 2, 3, 8, 1)
|
||||
game.level.entities = { first, second }
|
||||
local success = game:useSkill("multishot", first, second)
|
||||
eq(success, true, "multishot succeeds with two reachable targets")
|
||||
ok(first.hp < first.maxHp, "the primary target takes damage")
|
||||
ok(second.hp < second.maxHp, "the secondary target takes damage")
|
||||
local stack
|
||||
for _, item in ipairs(game.player.inventory) do
|
||||
if item.kind == Items.AMMO then stack = item end
|
||||
end
|
||||
eq(stack.count, 4, "multishot consumes only a single arrow for both targets")
|
||||
end
|
||||
|
||||
-- Multishot's split arrows must run through Resistances.apply exactly like a
|
||||
-- single Ranged.fire shot does (both always tag physical - arrows never
|
||||
-- carry an elemental damageType) - before this test the loop subtracted a
|
||||
-- raw attack-minus-defense number straight off hp for both targets with no
|
||||
-- mitigation call at all, so a physically resistant monster took a full,
|
||||
-- unresisted hit from a skill that is supposed to be "an arrow that splits",
|
||||
-- not a different damage model than the bow it comes out of.
|
||||
function tests.rangerMultishotRespectsPhysicalResistanceOnBothSplitArrows()
|
||||
local function primaryDamageDealt(resistant)
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.player.class = "ranger"
|
||||
game.player.skills.multishot = true
|
||||
game.player.bow = Items.bow("shortbow", 3, 6)
|
||||
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 5)
|
||||
local first = Monsters.create(Monsters.byKey.orc, 1, 6, 6, 1)
|
||||
first.hp, first.maxHp = 100, 100
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user