test: cover tests.durabilityWearArmorBreaksAndSubtractsItsPowerFromDe...

This commit is contained in:
dualfroz committed 2026-09-11 18:49:15 +02:00
1 parent a9d2900e79
commit 117119b11e
1 file changed
+173
+173
View File
@@ -8952,6 +8952,179 @@ function tests.durabilityWearWeaponDecrementsAndBreaksAtZeroSubtractingItsPower(
end
function tests.durabilityWearWeaponIsANoOpOnceAlreadyBroken()
local item = Items.weapon("dagger", 2)
item.durability = 0
local hero = { weapon = item, attack = 10, kind = "player", name = "you" }
eq(Durability.wearWeapon(hero), nil, "wearing an already broken weapon reports no further break")
eq(item.durability, 0, "durability never drops below zero")
eq(hero.attack, 10, "wearing an already-broken weapon never touches attack again")
end
function tests.durabilityWearArmorBreaksAndSubtractsItsPowerFromDefense()
local hero = { defense = 1, inventory = {}, kind = "player", name = "you" }
Items.equipArmor(Items.armor("plate", 3), hero)
eq(hero.defense, 4, "the plate's power is baked into defense on equip")
hero.armor.durability = 1
local broke = Durability.wearArmor(hero)
ok(contains(broke, "battered"), "the break line reports the armor giving out")
eq(hero.defense, 1, "the armor's power is pulled back out of defense the instant it breaks")
end
function tests.durabilityWearBowBreaksWithoutTouchingAnyStatDirectly()
local hero = { bow = Items.bow("shortbow", 3, 6), attack = 5, kind = "player", name = "you" }
hero.bow.durability = 1
local broke = Durability.wearBow(hero)
ok(contains(broke, "snaps"), "the break line reports the bow giving out")
eq(hero.bow.durability, 0, "durability floors at zero")
eq(hero.attack, 5, "a bow's power was never baked into attack, so breaking it leaves attack untouched")
end
function tests.durabilityEffectivePowerIsZeroForABrokenItemAndFullOtherwise()
local bow = Items.bow("shortbow", 3, 6)
eq(Durability.effectivePower(bow), 3, "a pristine bow contributes its full power")
bow.durability = 0
eq(Durability.effectivePower(bow), 0, "a broken bow contributes nothing")
eq(Durability.effectivePower(nil), 0, "no bow equipped contributes nothing")
end
function tests.durabilityRepairFailsWithoutEnoughGoldOrOnAPristineItem()
local hero = { weapon = Items.weapon("sword", 4), gold = 0 }
local success, reason = Durability.repair(hero, "weapon")
eq(success, false, "a pristine weapon refuses repair")
eq(reason, "already in perfect condition", "the refusal explains why")
hero.weapon.durability = 10
success, reason = Durability.repair(hero, "weapon")
eq(success, false, "an empty purse refuses to cover the repair bill")
eq(reason, "not enough gold", "the refusal explains why")
success, reason = Durability.repair(hero, "bow")
eq(success, false, "repairing an empty slot fails")
eq(reason, "nothing equipped there", "the refusal explains why")
end
function tests.durabilityRepairRestoresFullDurabilityAndFoldsPowerBackInAfterABreak()
local hero = { attack = 5, gold = 100, inventory = {}, kind = "player", name = "you" }
Items.equipWeapon(Items.weapon("sword", 4), hero)
hero.weapon.durability = 0
hero.attack = hero.attack - 4
local success, cost = Durability.repair(hero, "weapon")
ok(success, "a full purse and a broken weapon repair successfully")
eq(hero.weapon.durability, Durability.MAX, "repairing restores full durability")
eq(cost, Durability.MAX * Durability.REPAIR_COST_PER_POINT, "repairing a fully broken item costs its full bill")
eq(hero.gold, 100 - cost, "the repair bill is deducted from gold")
eq(hero.attack, 9, "the weapon's power is folded back into attack once repaired")
end
function tests.durabilityRepairOnANotYetBrokenItemJustTopsUpDurabilityWithoutTouchingStats()
local hero = { attack = 9, gold = 100 }
hero.weapon = Items.weapon("sword", 4)
hero.weapon.durability = 20
local success, cost = Durability.repair(hero, "weapon")
ok(success, "a merely dinged weapon still repairs")
eq(hero.weapon.durability, Durability.MAX, "durability tops back up to max")
eq(cost, (Durability.MAX - 20) * Durability.REPAIR_COST_PER_POINT, "the bill only covers the missing points")
eq(hero.attack, 9, "attack is untouched since the weapon was never broken in the first place")
end
function tests.equipWeaponAddsOnlyEffectivePowerForAnAlreadyBrokenWeapon()
local hero = { attack = 5, inventory = {} }
local sword = Items.weapon("sword", 4)
sword.durability = 0
Items.equipWeapon(sword, hero)
eq(hero.attack, 5, "equipping an already-broken weapon adds none of its power")
end
function tests.rangedFireDealsNoBowBonusOnceTheBowIsBroken()
local game = stagedGame(1, arena(21, 11), 3, 6)
game.player.bow = Items.bow("shortbow", 5, 6)
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 10)
local orc = Monsters.create(Monsters.byKey.orc, 1, 9, 6, 1)
orc.hp, orc.maxHp = 999, 999
game:fireAt(orc)
local pristineDamage = 999 - orc.hp
orc.hp = 999
game.player.bow.durability = 0
game:fireAt(orc)
local brokenDamage = 999 - orc.hp
ok(brokenDamage < pristineDamage, "a broken bow deals strictly less damage than a working one")
eq(brokenDamage, pristineDamage - 5, "the broken bow's missing power matches its catalog power exactly")
end
function tests.gamePlayerAttackWearsTheEquippedWeaponAndLogsWhenItBreaks()
local game = stagedGame(1, arena(21, 11), 3, 6)
Items.equipWeapon(Items.weapon("dagger", 2), game.player)
game.player.weapon.durability = 1
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
orc.hp, orc.maxHp = 999, 999
game:playerAttack(orc)
eq(game.player.weapon.durability, 0, "the weapon's last durability point is spent on this hit")
local broke = false
for _, line in ipairs(game.log:recent(6)) do
if contains(line, "breaks apart") then broke = true end
end
ok(broke, "the weapon breaking is reported in the message log")
end
function tests.gameMonsterMeleeWearsThePlayersArmorAndLogsWhenItBreaks()
local game = stagedGame(1, arena(21, 11), 3, 6)
Items.equipArmor(Items.armor("plate", 3), game.player)
game.player.armor.durability = 1
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
game:monsterMelee(orc)
eq(game.player.armor.durability, 0, "the armor's last durability point is spent on this hit")
local broke = false
for _, line in ipairs(game.log:recent(6)) do
if contains(line, "battered") then broke = true end
end
ok(broke, "the armor breaking is reported in the message log")
end
function tests.gameFireAtWearsTheEquippedBowAndLogsWhenItBreaks()
local game = stagedGame(1, arena(21, 11), 3, 6)
game.player.bow = Items.bow("shortbow", 3, 6)
game.player.bow.durability = 1
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 5)
local orc = Monsters.create(Monsters.byKey.orc, 1, 9, 6, 1)
orc.hp, orc.maxHp = 999, 999
game:fireAt(orc)
eq(game.player.bow.durability, 0, "the bow's last durability point is spent on this shot")
ok(contains(game.log:last(), "snaps"), "the bow snapping is the shot's own last log line")
end
function tests.gameBrokenEquippedSlotFindsTheFirstBrokenPieceInPriorityOrder()
local game = stagedGame(1, arena(21, 11), 3, 6)
eq(game:brokenEquippedSlot(), nil, "a fresh player with no gear has nothing broken")
Items.equipArmor(Items.armor("plate", 3), game.player)
game.player.armor.durability = 0
eq(game:brokenEquippedSlot(), "armor", "the only broken piece is found")
Items.equipWeapon(Items.weapon("sword", 4), game.player)
game.player.weapon.durability = 0
eq(game:brokenEquippedSlot(), "weapon", "weapon takes priority over armor once both are broken")
end
function tests.gameRepairEquippedSpendsGoldAndLogsSuccess()
local game = stagedGame(1, arena(21, 11), 3, 6)
Items.equipWeapon(Items.weapon("sword", 4), game.player)
game.player.weapon.durability = 0
game.player.gold = 1000
local before = game.player.gold
local success = game:repairEquipped("weapon")
ok(success, "a full purse repairs the broken weapon")
eq(game.player.weapon.durability, Durability.MAX, "the weapon comes back to full durability")
ok(game.player.gold < before, "gold is spent on the repair")
ok(contains(game.log:last(), "repair"), "the repair is logged")
end
function tests.gameRepairEquippedFailsAndLogsWhenGoldIsShort()
local game = stagedGame(1, arena(21, 11), 3, 6)
Items.equipWeapon(Items.weapon("sword", 4), game.player)
game.player.weapon.durability = 0
game.player.gold = 0
local success = game:repairEquipped("weapon")
eq(success, false, "an empty purse cannot repair")
eq(game.player.weapon.durability, 0, "the weapon stays broken")
end
local order = {