test: cover tests.commandsApplyHelpMentionsTheOptionalTargetNumberOnE...
This commit is contained in:
1 parent
851e57ec97
commit
0129c399f5
1 file changed
+173
+173
@@ -13969,6 +13969,179 @@ function tests.commandsApplyExploreDrivesGameAutoExploreAndReturnsItsResult()
|
||||
end
|
||||
|
||||
function tests.commandsApplyHelpMentionsExplore()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local _, message = Commands.apply(game, "help")
|
||||
ok(contains(message, "explore"), "help mentions explore")
|
||||
end
|
||||
|
||||
function tests.commandsApplyHelpMentionsTheOptionalTargetNumberOnEveryTargetedVerb()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local _, message = Commands.apply(game, "help")
|
||||
ok(contains(message, "throw <n> [target]"), "help spells out throw's optional target number")
|
||||
ok(contains(message, "fire [target]"), "help spells out fire's optional target number")
|
||||
ok(contains(message, "capture <n> [target]"), "help spells out capture's optional target number")
|
||||
ok(contains(message, "cast <spell> [target]"), "help spells out cast's optional target number")
|
||||
ok(contains(message, "useskill <skill> [target]"), "help spells out useskill's optional target number")
|
||||
end
|
||||
|
||||
function tests.gameRestUntilHealedRefusesWithoutSpendingATurnWhenAlreadyAtFullHealth()
|
||||
local game = stagedGame(1, arena(11, 9), 5, 5)
|
||||
local turnBefore = game.turn
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, false, "resting at full health spends no turn")
|
||||
eq(message, "you are already at full health", "the refusal explains why")
|
||||
eq(game.turn, turnBefore, "the turn counter never advances")
|
||||
end
|
||||
|
||||
function tests.gameRestUntilHealedRefusesWithoutSpendingATurnWhileAHostileIsAlreadyInSight()
|
||||
local level = arena(21, 11)
|
||||
local game = stagedGame(1, level, 5, 5)
|
||||
game.player.hp = game.player.maxHp - 5
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 7, 5, 1)
|
||||
orc.awareness = Stealth.DORMANT
|
||||
level.entities = { orc }
|
||||
game:computeVisible()
|
||||
local turnBefore = game.turn
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, false, "a hostile already visible refuses to even start")
|
||||
eq(message, "a monster is already in sight", "the refusal names the reason")
|
||||
eq(game.turn, turnBefore, "the turn counter never advances")
|
||||
end
|
||||
|
||||
function tests.gameRestUntilHealedHealsTurnByTurnUntilFullThenStops()
|
||||
local game = stagedGame(1, arena(11, 9), 5, 5)
|
||||
game.player.hp = game.player.maxHp - 6
|
||||
Status.apply(game.player, Status.REGEN, 20, 2)
|
||||
local turnBefore = game.turn
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, true, "a rest that actually heals spends turns")
|
||||
eq(message, "you rest until your wounds close", "a completed rest reports it finished")
|
||||
eq(game.player.hp, game.player.maxHp, "hp is capped exactly at maxHp, never over it")
|
||||
eq(game.turn, turnBefore + 3, "exactly ceil(6/2) turns of the regen tick were needed")
|
||||
end
|
||||
|
||||
-- Deliberately the same "nothing left to explore" shape as autoExplore's own
|
||||
-- steps==0 refusal, but rest's equivalent needs a *second* unchanged turn
|
||||
-- before it gives up rather than judging the first one alone - see
|
||||
-- Game:restUntilHealed's own comment for why: a real player's typed "rest"
|
||||
-- always runs through Game:manualStep, which already primes one turn of
|
||||
-- ticking before this function's loop ever gets to take its own first
|
||||
-- hpBefore snapshot, so that first reading alone cannot be trusted.
|
||||
function tests.gameRestUntilHealedStopsAfterTwoUnchangedTurnsWhenNothingIsHealingThePlayer()
|
||||
local game = stagedGame(1, arena(11, 9), 5, 5)
|
||||
game.player.hp = game.player.maxHp - 5
|
||||
local turnBefore = game.turn
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, true, "the turns spent checking still count as spent")
|
||||
eq(message, "you stop resting - nothing here is healing you", "the interrupt explains itself")
|
||||
eq(game.turn, turnBefore + 2, "exactly two turns were spent before giving up")
|
||||
eq(game.player.hp, game.player.maxHp - 5, "hp is unchanged - nothing was healing it in the first place")
|
||||
end
|
||||
|
||||
function tests.gameRestUntilHealedStopsTheInstantThePlayerTakesDamage()
|
||||
local game = stagedGame(1, arena(11, 9), 5, 5)
|
||||
game.player.hp = game.player.maxHp - 5
|
||||
Status.apply(game.player, Status.POISON, 5, 4)
|
||||
local turnBefore = game.turn
|
||||
local hpBefore = game.player.hp
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, true, "the interrupted turn itself still spends")
|
||||
eq(message, "you stop resting - you have taken damage", "the interrupt explains itself")
|
||||
eq(game.turn, turnBefore + 1, "exactly the one turn that took the damage was spent")
|
||||
eq(game.player.hp, hpBefore - 4, "the poison tick's own damage lands normally before the interrupt fires")
|
||||
end
|
||||
|
||||
-- Same row placement trick as autoExplore's own sight-interrupt test, but
|
||||
-- mirrored: here the *player* stands still (resting) and the orc is the one
|
||||
-- that has to close the distance on its own, so it starts HUNTING (already
|
||||
-- aware, not DORMANT) rather than relying on stealth.lua's wake roll - the
|
||||
-- point of this test is Game:canSeePlayer's own chase range (10) reaching
|
||||
-- further than the player's own vision radius (8), not the wake mechanic.
|
||||
-- Status.REGEN is applied so the run has real healing to interrupt (see
|
||||
-- Game:restUntilHealed's own comment - two turns are needed before "nothing
|
||||
-- is healing you" could even fire, and this scenario resolves before that).
|
||||
function tests.gameRestUntilHealedStopsTheMomentAHostileComesIntoSightWithoutEngagingIt()
|
||||
local level = arena(30, 11)
|
||||
local game = stagedGame(2, level, 20, 6)
|
||||
game.player.hp = game.player.maxHp - 20
|
||||
Status.apply(game.player, Status.REGEN, 50, 1)
|
||||
local orc = Monsters.create(Monsters.byKey.orc, 1, 11, 6, 1)
|
||||
orc.awareness = Stealth.HUNTING
|
||||
level.entities = { orc }
|
||||
game:computeVisible()
|
||||
ok(not game.visible[level.map:index(orc.x, orc.y)], "the orc starts out of sight")
|
||||
local turnBefore = game.turn
|
||||
local hpBefore = game.player.hp
|
||||
local orcHpBefore = orc.hp
|
||||
local consumesTurn, message = game:restUntilHealed()
|
||||
eq(consumesTurn, true, "real turns were spent healing before the interrupt fired")
|
||||
eq(message, "you stop resting - a monster is in sight", "the interrupt names a sighted hostile")
|
||||
eq(game.turn, turnBefore + 2, "exactly the steps needed to bring the orc within vision range 8 were taken")
|
||||
ok(game.player.hp > hpBefore, "the turns spent before the interrupt actually healed the player")
|
||||
eq(orc.hp, orcHpBefore, "the orc is only spotted, never engaged")
|
||||
ok(game.visible[level.map:index(orc.x, orc.y)], "the orc really is the thing that got seen")
|
||||
eq(orc.awareness, Stealth.HUNTING, "the orc's own awareness is unaffected by simply being spotted")
|
||||
end
|
||||
|
||||
function tests.gameManualStepDrivenRestSpendsExactlyAsManyTurnsAsCallingGameRestUntilHealedDirectly()
|
||||
local direct = stagedGame(9, arena(11, 9), 5, 5)
|
||||
direct.player.hp = direct.player.maxHp - 6
|
||||
Status.apply(direct.player, Status.REGEN, 20, 2)
|
||||
direct:restUntilHealed()
|
||||
local viaManualStep = stagedGame(9, arena(11, 9), 5, 5)
|
||||
viaManualStep.player.hp = viaManualStep.player.maxHp - 6
|
||||
Status.apply(viaManualStep.player, Status.REGEN, 20, 2)
|
||||
viaManualStep:manualStep("rest")
|
||||
eq(viaManualStep.turn, direct.turn,
|
||||
"routing rest through Game:manualStep must not end the turn a second time on top of what " ..
|
||||
"restUntilHealed already closed itself, and must credit the turn manualStep primes before " ..
|
||||
"Commands.apply ever runs to the same run rather than losing it")
|
||||
eq(viaManualStep.player.hp, direct.player.hp, "both paths heal the player by the same total amount")
|
||||
end
|
||||
|
||||
function tests.commandsApplyRestDrivesGameRestUntilHealedAndReturnsItsResult()
|
||||
local game = stagedGame(1, arena(11, 9), 5, 5)
|
||||
local consumesTurn, message = Commands.apply(game, "rest")
|
||||
eq(consumesTurn, false, "a player already at full health spends no turn")
|
||||
eq(message, "you are already at full health", "the command surfaces Game:restUntilHealed's own message verbatim")
|
||||
end
|
||||
|
||||
function tests.commandsApplyHelpMentionsRest()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
local _, message = Commands.apply(game, "help")
|
||||
ok(contains(message, "rest"), "help mentions rest")
|
||||
end
|
||||
|
||||
-- Splits an otherwise-open arena into two floor regions with a solid wall
|
||||
-- column at x == gapX between them - used only to build a destination that is
|
||||
-- provably unreachable from the player's own side, for Game:travelTo's "no
|
||||
-- route exists" refusal below.
|
||||
local function splitArena(w, h, gapX)
|
||||
local map = Map.new(w, h)
|
||||
for y = 2, h - 1 do
|
||||
for x = 2, gapX - 1 do map:set(x, y, Map.FLOOR) end
|
||||
for x = gapX + 1, w - 1 do map:set(x, y, Map.FLOOR) end
|
||||
end
|
||||
return Level.new({
|
||||
depth = 1, generator = "arena", map = map,
|
||||
entities = {}, floorItems = {}, traps = {}, lights = {}, dark = false, explored = {},
|
||||
upX = 2, upY = 2, downX = w - 1, downY = h - 1,
|
||||
})
|
||||
end
|
||||
|
||||
function tests.gameTravelToWalksTheShortestPathAndArrivesAtTheDestination()
|
||||
local level = arena(21, 11)
|
||||
local game = stagedGame(1, level, 3, 6)
|
||||
local expectedSteps = #game:playerPathTo(level.downX, level.downY) - 1
|
||||
local turnBefore = game.turn
|
||||
local consumesTurn, message = game:travelTo(level.downX, level.downY)
|
||||
eq(consumesTurn, true, "a real trip spends turns")
|
||||
eq(message, "you arrive", "arriving reports so")
|
||||
eq(game.player.x, level.downX, "the player actually reaches the destination x")
|
||||
eq(game.player.y, level.downY, "the player actually reaches the destination y")
|
||||
eq(game.turn, turnBefore + expectedSteps, "exactly the shortest path's own number of steps were spent")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user