test: cover tests.commandsApplyCastWithAnExplicitTargetNumberHitsThat...
This commit is contained in:
1 parent
ef064dfe9d
commit
64d37536f1
1 file changed
+173
+173
@@ -13104,6 +13104,179 @@ function tests.commandsApplyFireWithAnExplicitTargetNumberShootsThatHostileInste
|
|||||||
game.level.entities = { near, far }
|
game.level.entities = { near, far }
|
||||||
game.player.bow = Items.bow("short bow", 2, 6)
|
game.player.bow = Items.bow("short bow", 2, 6)
|
||||||
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 2)
|
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 2)
|
||||||
|
local consumesTurn = Commands.apply(game, "fire 2")
|
||||||
|
eq(consumesTurn, true, "firing at an explicit in-sight target number spends the turn")
|
||||||
|
ok(far.hp < 20, "the explicitly named second hostile takes the shot")
|
||||||
|
eq(near.hp, 20, "the nearer, non-targeted hostile is left untouched")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyCastWithAnExplicitTargetNumberHitsThatHostileInsteadOfTheNearestOne()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
local near = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
local far = Monsters.create(Monsters.byKey.rat, 1, 5, 8, 1)
|
||||||
|
near.hp, far.hp = 20, 20
|
||||||
|
game.level.entities = { near, far }
|
||||||
|
local consumesTurn = Commands.apply(game, "cast missile 2")
|
||||||
|
eq(consumesTurn, true, "casting at an explicit in-sight target number spends the turn")
|
||||||
|
ok(far.hp < 20, "the explicitly named second hostile takes the hit")
|
||||||
|
eq(near.hp, 20, "the nearer, non-targeted hostile is left untouched")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyCaptureWithAnExplicitTargetNumberTargetsThatHostileInsteadOfTheNearestOne()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
local near = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
local far = Monsters.create(Monsters.byKey.rat, 1, 5, 8, 1)
|
||||||
|
near.hp, far.hp = 1, 1
|
||||||
|
game.level.entities = { near, far }
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.net()
|
||||||
|
local index = #game.player.inventory
|
||||||
|
game.rng = Rng.new(2)
|
||||||
|
local consumesTurn = Commands.apply(game, "capture " .. index .. " 2")
|
||||||
|
eq(consumesTurn, true, "capturing at an explicit in-sight target number spends the turn")
|
||||||
|
eq(#game.level.captives, 1, "exactly one captive results from the attempt")
|
||||||
|
eq(game.level.captives[1].x, far.x, "the explicitly named second hostile is the one caught")
|
||||||
|
eq(game.level.captives[1].y, far.y, "the explicitly named second hostile is the one caught")
|
||||||
|
ok(near:isAlive(), "the nearer, non-targeted hostile is left alive and free")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cleave hits its named target through the full attack path and every other
|
||||||
|
-- monster standing next to the player for a halved splash (see skills.lua's
|
||||||
|
-- Skills.useCleave) - so with two rats both adjacent to the player, an
|
||||||
|
-- explicit target number cannot be proven by "the other one is untouched"
|
||||||
|
-- (the splash still reaches it), only by which one takes the bigger, full
|
||||||
|
-- hit. Combat.damage is a plain, RNG-free formula (attack minus defense,
|
||||||
|
-- floored, minimum 1 - see combat.lua), so two identical rats make that
|
||||||
|
-- comparison deterministic.
|
||||||
|
function tests.commandsApplyUseskillCleaveWithAnExplicitTargetNumberHitsThatAdjacentHostileInsteadOfTheDefaultNearestOne()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "fighter"
|
||||||
|
Skills.learn(game.player, "cleave")
|
||||||
|
local ratA = Monsters.create(Monsters.byKey.rat, 1, 6, 5, 1)
|
||||||
|
local ratB = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
ratA.hp, ratB.hp = 20, 20
|
||||||
|
game.level.entities = { ratA, ratB }
|
||||||
|
local consumesTurn = Commands.apply(game, "useskill cleave 2")
|
||||||
|
eq(consumesTurn, true, "cleave against an explicit in-sight target number spends the turn")
|
||||||
|
local dealtToB, dealtToA = 20 - ratB.hp, 20 - ratA.hp
|
||||||
|
ok(dealtToB > dealtToA, "the explicitly named second hostile takes cleave's full hit, not just its splash")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyUseskillMultishotWithExplicitTargetNumbersHitsExactlyThoseTwoHostiles()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "ranger"
|
||||||
|
Skills.learn(game.player, "multishot")
|
||||||
|
game.player.bow = Items.bow("short bow", 2, 6)
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 2)
|
||||||
|
local first = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
local middle = Monsters.create(Monsters.byKey.rat, 1, 6, 5, 1)
|
||||||
|
local third = Monsters.create(Monsters.byKey.rat, 1, 5, 8, 1)
|
||||||
|
first.hp, middle.hp, third.hp = 20, 20, 20
|
||||||
|
game.level.entities = { first, middle, third }
|
||||||
|
local consumesTurn = Commands.apply(game, "useskill multishot 1 3")
|
||||||
|
eq(consumesTurn, true, "multishot against two explicit in-sight target numbers spends the turn")
|
||||||
|
ok(first.hp < 20, "the first explicitly named hostile takes a shot")
|
||||||
|
ok(third.hp < 20, "the second explicitly named hostile takes a shot")
|
||||||
|
eq(middle.hp, 20, "the un-named, nearer-by-distance hostile in between is left untouched")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyUseskillMultishotWithOnlyOneExplicitTargetNumberFallsBackToAutoTargetingBoth()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "ranger"
|
||||||
|
Skills.learn(game.player, "multishot")
|
||||||
|
game.player.bow = Items.bow("short bow", 2, 6)
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.ammo("arrow", 2)
|
||||||
|
local near = Monsters.create(Monsters.byKey.rat, 1, 5, 6, 1)
|
||||||
|
near.hp = 20
|
||||||
|
game.level.entities = { near }
|
||||||
|
local consumesTurn = Commands.apply(game, "useskill multishot 1")
|
||||||
|
eq(consumesTurn, true, "an ambiguous single explicit target still falls back to auto-targeting")
|
||||||
|
ok(near.hp < 20, "the only visible hostile still takes a shot via the auto-target fallback")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyContextActionsFailCleanlyWithNothingHereWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
for _, verb in ipairs({
|
||||||
|
"open", "pray", "quest", "butcher", "raise", "scavenge", "harvest",
|
||||||
|
"ransom", "sellcaptive", "interrogate", "descend", "ascend", "enterrift", "exitrift",
|
||||||
|
}) do
|
||||||
|
local consumesTurn, message = Commands.apply(game, verb)
|
||||||
|
eq(consumesTurn, false, verb .. " with nothing here spends no turn")
|
||||||
|
ok(message ~= nil and #message > 0, verb .. " gives a reason")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyDigRejectsAnUnknownDirectionAndAnUnreadiedPickWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local badDirection, message1 = Commands.apply(game, "dig sideways")
|
||||||
|
eq(badDirection, false, "an unrecognized direction word spends no turn")
|
||||||
|
eq(message1, "dig which direction?", "the failure names what is missing")
|
||||||
|
local noPick, message2 = Commands.apply(game, "dig north")
|
||||||
|
eq(noPick, false, "digging without a readied pick spends no turn")
|
||||||
|
ok(message2 ~= nil, "the failure explains itself")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyDisarmRejectsAMissingDirectionOrAnUndetectedTrapWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local badDirection, message1 = Commands.apply(game, "disarm sideways")
|
||||||
|
eq(badDirection, false, "an unrecognized direction word spends no turn")
|
||||||
|
eq(message1, "disarm which direction?", "the failure names what is missing")
|
||||||
|
|
||||||
|
local undetected = { x = 6, y = 5, effect = "dart", revealed = false }
|
||||||
|
game.level.traps = { undetected }
|
||||||
|
local noTarget, message2 = Commands.apply(game, "disarm east")
|
||||||
|
eq(noTarget, false, "a trap never yet noticed spends no turn")
|
||||||
|
eq(message2, "there is nothing here you have noticed to disarm", "the failure explains itself")
|
||||||
|
eq(#game.level.traps, 1, "the untouched trap is still there")
|
||||||
|
|
||||||
|
local sprung = { x = 4, y = 5, effect = "dart", revealed = true, detected = true }
|
||||||
|
game.level.traps = { sprung }
|
||||||
|
local alreadySprung = Commands.apply(game, "disarm west")
|
||||||
|
eq(alreadySprung, false, "an already-sprung trap spends no turn either")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyDisarmAlwaysSpendsTheTurnAgainstADetectedTrapWhetherItSucceedsOrSprings()
|
||||||
|
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 consumesTurn = Commands.apply(game, "disarm east")
|
||||||
|
eq(consumesTurn, true, "a disarm attempt against a real detected trap always spends the turn")
|
||||||
|
if #game.level.traps == 0 then
|
||||||
|
sawSuccess = true
|
||||||
|
else
|
||||||
|
eq(trap.revealed, true, "a failed disarm still springs and reveals the trap")
|
||||||
|
sawFailure = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ok(sawSuccess, "disarming through the command eventually succeeds across a handful of seeds")
|
||||||
|
ok(sawFailure, "disarming through the command eventually springs across a handful of seeds")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyAppeaseBuysFactionStandingWithGoldAndSpendsTheTurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.gold = 100
|
||||||
|
local repBefore = Factions.reputationFor(game.player, Factions.MERCHANT)
|
||||||
|
local costBefore = Factions.appeaseCost(game.player, Factions.MERCHANT)
|
||||||
|
local consumesTurn = Commands.apply(game, "appease merchant")
|
||||||
|
eq(consumesTurn, true, "affording tribute to a real faction spends the turn")
|
||||||
|
eq(game.player.gold, 100 - costBefore, "the tribute's cost is charged in gold")
|
||||||
|
ok(Factions.reputationFor(game.player, Factions.MERCHANT) > repBefore, "standing actually improves")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyAppeaseRejectsAMissingOrUnknownFactionWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local missing, message1 = Commands.apply(game, "appease")
|
||||||
|
eq(missing, false, "appease with no faction name spends no turn")
|
||||||
|
ok(contains(message1, "merchant"), "the failure lists the valid faction names")
|
||||||
|
|
||||||
|
local unknown, message2 = Commands.apply(game, "appease atlanteans")
|
||||||
|
eq(unknown, false, "an unrecognized faction name spends no turn")
|
||||||
|
ok(contains(message2, "merchant"), "the failure lists the valid faction names")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyAppeaseFailsWithoutSpendingATurnWhenGoldIsShort()
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user