test: cover tests.autopilotRepairsBrokenGearAutomaticallyWhenAffordable
This commit is contained in:
1 parent
117119b11e
commit
d16250b6f9
1 file changed
+173
+173
@@ -9125,6 +9125,179 @@ function tests.gameRepairEquippedFailsAndLogsWhenGoldIsShort()
|
||||
local success = game:repairEquipped("weapon")
|
||||
eq(success, false, "an empty purse cannot repair")
|
||||
eq(game.player.weapon.durability, 0, "the weapon stays broken")
|
||||
ok(contains(game.log:last(), "cannot repair"), "the failure is logged")
|
||||
end
|
||||
|
||||
function tests.autopilotRepairsBrokenGearAutomaticallyWhenAffordable()
|
||||
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
|
||||
game.level.entities = {}
|
||||
game:choosePlayerAction()
|
||||
eq(game.player.weapon.durability, Durability.MAX,
|
||||
"the autopilot repairs a broken weapon on sight once it can afford to")
|
||||
end
|
||||
|
||||
function tests.durabilityFieldsSurviveSerialization()
|
||||
local game = Game.new(3)
|
||||
Items.equipWeapon(Items.weapon("sword", 4), game.player)
|
||||
game.player.weapon.durability = 7
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
eq(restored.player.weapon.durability, 7, "a weapon's own durability survives a save/load round trip")
|
||||
eq(restored.player.weapon.maxDurability, Durability.MAX, "a weapon's max durability survives a save/load round trip")
|
||||
end
|
||||
|
||||
function tests.renderPanelShowsWornGearOnlyOnceItHasTakenDamage()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
Items.equipWeapon(Items.weapon("sword", 4), game.player)
|
||||
ok(not contains(Render.panel(game), "sword ("), "a pristine weapon's label carries no wear indicator")
|
||||
game.player.weapon.durability = 10
|
||||
ok(contains(Render.panel(game), "sword (10/30)"), "a dinged weapon's label reports its remaining durability")
|
||||
game.player.weapon.durability = 0
|
||||
ok(contains(Render.panel(game), "sword (broken)"), "a broken weapon's label says so plainly")
|
||||
end
|
||||
|
||||
-- disarm.lua: passive trap sense and deliberate disarming.
|
||||
|
||||
function tests.disarmSweepDetectsAHiddenTrapWithinOneStepEventuallyAcrossAHandfulOfSeeds()
|
||||
local detected = false
|
||||
for seed = 1, 100 do
|
||||
local level = { traps = { { x = 5, y = 5, effect = "dart", revealed = false } } }
|
||||
if #Disarm.sweep(level, Rng.new(seed), 5, 6) > 0 then detected = true break end
|
||||
end
|
||||
ok(detected, "an adjacent hidden trap is eventually detected across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.disarmSweepNeverDetectsATrapTwoStepsAway()
|
||||
for seed = 1, 200 do
|
||||
local level = { traps = { { x = 5, y = 5, effect = "dart", revealed = false } } }
|
||||
eq(#Disarm.sweep(level, Rng.new(seed), 7, 7), 0,
|
||||
"a trap two steps away is never detected regardless of the roll")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.disarmSweepNeverRedetectsAnAlreadyDetectedOrRevealedTrap()
|
||||
local level = { traps = {
|
||||
{ x = 5, y = 5, effect = "dart", revealed = false, detected = true },
|
||||
{ x = 5, y = 6, effect = "dart", revealed = true },
|
||||
} }
|
||||
for seed = 1, 50 do
|
||||
eq(#Disarm.sweep(level, Rng.new(seed), 5, 5), 0,
|
||||
"neither an already-detected nor an already-sprung trap is swept again")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.disarmOddsForClimbWithLevelButNeverReachTheDenominator()
|
||||
local num1, den1 = Disarm.oddsFor({ level = 1 })
|
||||
eq(num1, Disarm.DISARM_BASE_NUMERATOR, "a fresh level-one player rolls the catalog's base odds")
|
||||
local num2, den2 = Disarm.oddsFor({ level = 100 })
|
||||
eq(den2, den1, "the denominator never changes with level")
|
||||
ok(num2 < den2, "even an extremely high level never reaches a guaranteed disarm")
|
||||
eq(num2, Disarm.DISARM_BASE_DENOMINATOR - 1, "the numerator caps a single point shy of the denominator")
|
||||
end
|
||||
|
||||
function tests.disarmAttemptOnSuccessRemovesTheTrapAndPaysSalvage()
|
||||
local succeeded = false
|
||||
for seed = 1, 300 do
|
||||
local game = stagedGame(seed, arena(21, 11), 3, 6)
|
||||
local trap = { x = 4, y = 6, effect = "dart", revealed = false, detected = true }
|
||||
game.level.traps = { trap }
|
||||
local essenceBefore = game.player.essence
|
||||
local success, line = Disarm.attempt(game, trap)
|
||||
if success then
|
||||
eq(#game.level.traps, 0, "a successfully disarmed trap is removed from the level")
|
||||
ok(game.player.essence > essenceBefore, "a successful disarm pays out salvage essence")
|
||||
ok(contains(line, "disarm"), "the success is reported")
|
||||
succeeded = true
|
||||
break
|
||||
end
|
||||
end
|
||||
ok(succeeded, "disarming eventually succeeds across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.disarmAttemptOnFailureSpringsTheTrapOnThePlayer()
|
||||
local failed = false
|
||||
for seed = 1, 300 do
|
||||
local game = stagedGame(seed, arena(21, 11), 3, 6)
|
||||
local trap = { x = 4, y = 6, effect = "dart", revealed = false, detected = true }
|
||||
game.level.traps = { trap }
|
||||
local hpBefore = game.player.hp
|
||||
local success = Disarm.attempt(game, trap)
|
||||
if not success then
|
||||
eq(trap.revealed, true, "a failed disarm springs the trap, revealing it")
|
||||
ok(game.player.hp < hpBefore, "a failed disarm's spring wounds the player exactly like a footstep would")
|
||||
failed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
ok(failed, "disarming eventually fails across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.gameDisarmTrapRefusesAnUndetectedOrAlreadySprungTrap()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local undetected = { x = 4, y = 6, effect = "dart", revealed = false }
|
||||
game.level.traps = { undetected }
|
||||
eq(game:disarmTrap(undetected), false, "an undetected trap refuses disarming outright")
|
||||
eq(#game.level.traps, 1, "the untouched trap is still there")
|
||||
|
||||
local sprung = { x = 5, y = 6, effect = "dart", revealed = true, detected = true }
|
||||
eq(game:disarmTrap(sprung), false, "an already-sprung trap refuses disarming outright")
|
||||
end
|
||||
|
||||
function tests.gameDisarmTrapSucceedsOrSpringsExactlyLikeDisarmAttempt()
|
||||
local sawSuccess, sawFailure = false, false
|
||||
for seed = 1, 300 do
|
||||
if sawSuccess and sawFailure then break end
|
||||
local game = stagedGame(seed, arena(21, 11), 3, 6)
|
||||
local trap = { x = 4, y = 6, effect = "dart", revealed = false, detected = true }
|
||||
game.level.traps = { trap }
|
||||
local hpBefore = game.player.hp
|
||||
if game:disarmTrap(trap) then
|
||||
eq(#game.level.traps, 0, "a successful disarm through the game wrapper removes the trap")
|
||||
sawSuccess = true
|
||||
else
|
||||
eq(trap.revealed, true, "a failed disarm through the game wrapper springs the trap")
|
||||
ok(game.player.hp <= hpBefore, "a failed disarm through the game wrapper can wound the player")
|
||||
sawFailure = true
|
||||
end
|
||||
end
|
||||
ok(sawSuccess, "the game wrapper eventually succeeds across a handful of seeds")
|
||||
ok(sawFailure, "the game wrapper eventually fails across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.gameEndPlayerTurnEventuallyDetectsAnAdjacentTrapAcrossAHandfulOfSeeds()
|
||||
local noticed = false
|
||||
for seed = 1, 100 do
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
game.rng = Rng.new(seed)
|
||||
game.level.traps = { { x = 4, y = 6, effect = "dart", revealed = false } }
|
||||
game:endPlayerTurn()
|
||||
if game.level.traps[1].detected then
|
||||
local reported = false
|
||||
for _, line in ipairs(game.log:recent(6)) do
|
||||
if contains(line, "notice") then reported = true end
|
||||
end
|
||||
ok(reported, "a freshly detected trap is reported somewhere in the turn's log lines")
|
||||
noticed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
ok(noticed, "an adjacent hidden trap is eventually detected during a normal turn across a handful of seeds")
|
||||
end
|
||||
|
||||
function tests.trapDetectedFieldSurvivesSerialization()
|
||||
local game = Game.new(3)
|
||||
game.level.traps = { { x = 1, y = 1, effect = "dart", revealed = false, detected = true } }
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
eq(restored.level.traps[1].detected, true, "a trap's detected flag survives a save/load round trip")
|
||||
end
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user