test: cover tests.commandsApplyStealFailsWithNothingWardedUnderfootWi...
This commit is contained in:
1 parent
69dd449825
commit
808016f925
1 file changed
+173
+173
@@ -13623,6 +13623,179 @@ end
|
|||||||
function tests.commandsApplyStealTakesTheWardedWareUnderfootAndSpendsTheTurn()
|
function tests.commandsApplyStealTakesTheWardedWareUnderfootAndSpendsTheTurn()
|
||||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
||||||
|
game.level.entities = { keeper }
|
||||||
|
game.level.floorItems = { { x = 5, y = 5, item = Items.scroll("identify"), price = 18, shopId = keeper.id } }
|
||||||
|
local invBefore = #game.player.inventory
|
||||||
|
local consumesTurn = Commands.apply(game, "steal")
|
||||||
|
eq(consumesTurn, true, "stealing a warded ware underfoot spends the turn")
|
||||||
|
eq(#game.player.inventory, invBefore + 1, "the stolen item joins the inventory")
|
||||||
|
eq(keeper.hostile, true, "the keeper turns hostile after the theft")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyStealFailsWithNothingWardedUnderfootWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local consumesTurn, message = Commands.apply(game, "steal")
|
||||||
|
eq(consumesTurn, false, "stealing with nothing underfoot spends no turn")
|
||||||
|
eq(message, "there is nothing here worth stealing", "the failure explains itself")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyDismissReleasesTheHirelingAndSpendsTheTurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
Mercenaries.hire(game, "sellsword")
|
||||||
|
ok(game:hasHireling(), "the hire itself succeeded")
|
||||||
|
local consumesTurn = Commands.apply(game, "dismiss")
|
||||||
|
eq(consumesTurn, true, "dismissing an under-contract hireling spends the turn")
|
||||||
|
eq(game:hasHireling(), false, "the hireling is gone")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyDismissFailsWithNoHirelingWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local consumesTurn = Commands.apply(game, "dismiss")
|
||||||
|
eq(consumesTurn, false, "dismissing with nobody under contract spends no turn")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyLearnSpendsAPointNeverATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "fighter"
|
||||||
|
game.player.skillPoints = 1
|
||||||
|
local turnBefore = game.turn
|
||||||
|
local success = Commands.apply(game, "learn cleave")
|
||||||
|
eq(success, false, "learning a skill never spends a turn")
|
||||||
|
eq(game.turn, turnBefore, "the turn counter is untouched by learning")
|
||||||
|
eq(Skills.has(game.player, "cleave"), true, "the skill is actually learned")
|
||||||
|
eq(game.player.skillPoints, 0, "the skill point is spent")
|
||||||
|
ok(contains(game.log:last(), "learn"), "learning is logged")
|
||||||
|
|
||||||
|
local missing, message = Commands.apply(game, "learn")
|
||||||
|
eq(missing, false, "learn with no skill name spends no turn")
|
||||||
|
ok(message ~= nil, "the failure names what is missing")
|
||||||
|
|
||||||
|
local alreadyKnown = Commands.apply(game, "learn cleave")
|
||||||
|
eq(alreadyKnown, false, "re-learning an already-known skill spends no turn")
|
||||||
|
ok(contains(game.log:last(), "already"), "the failure to re-learn is logged")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skills.active/Skills.passive keys are camelCase (secondWind, poisonBlade,
|
||||||
|
-- manaShield), but Commands.parse lowercases every token including a typed
|
||||||
|
-- skill name before any handler sees it - a player typing the skill's own
|
||||||
|
-- printed name would otherwise never match it. Typed exactly as a human
|
||||||
|
-- would type it (mixed case), routed through the real Commands.apply/parse
|
||||||
|
-- pipeline, not a pre-lowercased literal.
|
||||||
|
function tests.commandsApplyLearnAcceptsTheSkillsOwnCamelCaseSpellingDespiteTheParserLowercasingIt()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "fighter"
|
||||||
|
game.player.level = 5
|
||||||
|
game.player.skillPoints = 2
|
||||||
|
local success = Commands.apply(game, "learn secondWind")
|
||||||
|
eq(success, false, "learning a skill never spends a turn")
|
||||||
|
eq(Skills.has(game.player, "secondWind"), true, "the camelCase skill is actually learned under its real key")
|
||||||
|
ok(contains(game.log:last(), "second wind"), "learning is logged under the skill's real name")
|
||||||
|
|
||||||
|
local rogue = stagedGame(2, arena(21, 11), 5, 5)
|
||||||
|
rogue.player.class = "rogue"
|
||||||
|
rogue.player.level = 5
|
||||||
|
rogue.player.skillPoints = 2
|
||||||
|
Commands.apply(rogue, "learn poisonBlade")
|
||||||
|
eq(Skills.has(rogue.player, "poisonBlade"), true, "a differently-classed camelCase skill also resolves correctly")
|
||||||
|
|
||||||
|
local mage = stagedGame(3, arena(21, 11), 5, 5)
|
||||||
|
mage.player.class = "mage"
|
||||||
|
mage.player.level = 5
|
||||||
|
mage.player.skillPoints = 2
|
||||||
|
Commands.apply(mage, "learn manaShield")
|
||||||
|
eq(Skills.has(mage.player, "manaShield"), true, "a camelCase PASSIVE skill resolves too, not only active ones")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyUseskillAcceptsACamelCaseSkillNameDespiteTheParserLowercasingIt()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
game.player.class = "fighter"
|
||||||
|
game.player.level = 5
|
||||||
|
Skills.learn(game.player, "secondWind")
|
||||||
|
game.player.hp = 1
|
||||||
|
local consumesTurn = Commands.apply(game, "useskill secondWind")
|
||||||
|
eq(consumesTurn, true, "using a camelCase-named skill by its real spelling spends the turn")
|
||||||
|
ok(game.player.hp > 1, "second wind actually healed the player, proving the real skill ran")
|
||||||
|
eq(game.player.skillCooldowns.secondWind, Skills.active.secondWind.cooldown,
|
||||||
|
"the cooldown lands on the real camelCase key, not a lowercased one")
|
||||||
|
|
||||||
|
local rogue = stagedGame(5, arena(21, 11), 5, 5)
|
||||||
|
rogue.player.class = "rogue"
|
||||||
|
rogue.player.level = 5
|
||||||
|
Skills.learn(rogue.player, "poisonBlade")
|
||||||
|
local consumesTurn2 = Commands.apply(rogue, "useskill poisonBlade")
|
||||||
|
eq(consumesTurn2, true, "using poisonBlade by its real camelCase spelling spends the turn")
|
||||||
|
eq(rogue.player.pendingPoisonBlade, true, "the venom is actually readied, proving the real skill ran")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyBrewCombinesTwoHerbsAtACauldronAndSpendsTheTurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||||
|
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.BLOODROOT) }
|
||||||
|
local consumesTurn = Commands.apply(game, "brew 1 2")
|
||||||
|
eq(consumesTurn, true, "brewing two herbs at a cauldron underfoot spends the turn")
|
||||||
|
eq(game.player.inventory[1].kind, Items.POTION, "the brewed potion replaces the spent herbs")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyBrewFailsAwayFromACauldronWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.BLOODROOT) }
|
||||||
|
local consumesTurn = Commands.apply(game, "brew 1 2")
|
||||||
|
eq(consumesTurn, false, "brewing away from any cauldron spends no turn")
|
||||||
|
eq(#game.player.inventory, 2, "a failed brew for lack of a cauldron spends nothing")
|
||||||
|
local missing, message = Commands.apply(game, "brew")
|
||||||
|
eq(missing, false, "brew with no indices spends no turn")
|
||||||
|
ok(message ~= nil, "the failure names what is missing")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Real bug found while manually verifying the new moonbell/sunpetal curdle
|
||||||
|
-- pairing through the full command pipeline: Game:brewAt returns false both
|
||||||
|
-- when nothing was ever attempted (no cauldron, bad indices) and when a real
|
||||||
|
-- attempt curdled (both herbs already spent, gas already vented) - the old
|
||||||
|
-- handler read either shape of false as "give the turn back", so a player
|
||||||
|
-- who curdled a pairing got a free retry exactly like a typo would. Fixed by
|
||||||
|
-- duplicating the preconditions in the handler (same shape as disarm's own
|
||||||
|
-- fix earlier today) so anything that reaches Game:brewAt always spends the
|
||||||
|
-- turn regardless of which of its two outcomes it lands on.
|
||||||
|
function tests.commandsApplyBrewSpendsTheTurnEvenWhenThePairingCurdles()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||||
|
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.NIGHTCAP) }
|
||||||
|
local consumesTurn, message = Commands.apply(game, "brew 1 2")
|
||||||
|
eq(consumesTurn, true, "a curdled brew still consumed a real attempt and must spend the turn")
|
||||||
|
eq(message, nil, "the curdle's own log line speaks for it, like a successful brew's message does")
|
||||||
|
eq(#game.player.inventory, 0, "the curdle already spent both herbs before the handler ever saw the outcome")
|
||||||
|
ok(contains(game.log:recent(1)[1] or "", "curdle"), "the curdle is still logged through the command pipeline")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyBrewRejectsTheSameIndexTwiceOrANonHerbItemWithoutSpendingATurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||||
|
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Items.potion(10) }
|
||||||
|
local sameIndex = Commands.apply(game, "brew 1 1")
|
||||||
|
eq(sameIndex, false, "naming the same inventory slot twice spends no turn")
|
||||||
|
local nonHerb = Commands.apply(game, "brew 1 2")
|
||||||
|
eq(nonHerb, false, "pairing a herb with a non-herb item spends no turn")
|
||||||
|
eq(#game.player.inventory, 2, "neither rejected attempt spends any item")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyHelpMentionsTheCraftingAndEconomyVerbs()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local _, message = Commands.apply(game, "help")
|
||||||
|
for _, word in ipairs({ "steal", "dismiss", "learn", "forge", "merge", "brew", "socket", "temper", "enchant", "repair" }) do
|
||||||
|
ok(contains(message, word), "help mentions " .. word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.commandsApplyHelpMentionsAppeaseDisarmAndHorde()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local _, message = Commands.apply(game, "help")
|
||||||
|
for _, word in ipairs({ "appease", "disarm", "horde" }) do
|
||||||
|
ok(contains(message, word), "help mentions " .. word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Game:manualStep - the turn-cycle integration around commands.lua.
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user