diff --git a/src/commands.lua b/src/commands.lua index 6975164..a5b21d0 100644 --- a/src/commands.lua +++ b/src/commands.lua @@ -477,3 +477,149 @@ Handlers.enchant = function(game, args) return false, "that cannot be enchanted" end +Handlers.disenchant = function(game, args) + local target = targetArg(args[1]) + if not target then return false, "disenchant what? weapon, armor or an item number" end + if game:disenchantItem(target) then return true, nil end + return false, "that cannot be disenchanted" +end + +Handlers.repair = function(game, args) + local slot = args[1] + if slot ~= "weapon" and slot ~= "armor" and slot ~= "bow" then + return false, "repair what? weapon, armor or bow" + end + if game:repairEquipped(slot) then return true, nil end + return false, nil +end + +-- Steals whichever warded ware sits underfoot, the same tile Game:pickupHere +-- already resolves against - unlike Game:stealFromShop's own raw floorItems +-- index, a typed command can only ever mean "the ware I am standing on". +local function groundIndexHere(game) + for i, ground in ipairs(game.level.floorItems) do + if ground.x == game.player.x and ground.y == game.player.y then return i, ground end + end + return nil +end + +Handlers.steal = function(game) + local index = groundIndexHere(game) + if index and game:stealFromShop(index) then return true, nil end + return false, "there is nothing here worth stealing" +end + +Handlers.dismiss = function(game) + if game:dismissHireling() then return true, nil end + return false, nil +end + +Handlers.learn = function(game, args) + local key = resolveSkillKey(args[1]) + if not key then return false, "learn which skill?" end + game:learnSkill(key) + return false, nil +end + +-- Duplicates Game:brewAt's own precondition checks (cauldron underfoot, two +-- distinct herb items) before ever calling it, the same shape as disarm +-- above and for the same reason: past those preconditions, brewing always +-- spends both herbs, whether the pairing brews a potion or curdles into gas +-- (see Alchemy.brew), so this handler must not read a curdle's own `false` +-- as "nothing happened" and hand the player a free turn back. +Handlers.brew = function(game, args) + local a, b = tonumber(args[1]), tonumber(args[2]) + if not a or not b then return false, "brew which two herbs? give two inventory numbers" end + if not game.level:cauldronAt(game.player.x, game.player.y) then + return false, "there is no cauldron here" + end + if a == b then return false, "brew two different herbs, not the same one twice" end + local herbA, herbB = game.player.inventory[a], game.player.inventory[b] + if not herbA or not herbB or herbA.kind ~= "herb" or herbB.kind ~= "herb" then + return false, "you need two herbs to brew" + end + game:brewAt(a, b) + return true, nil +end + +-- Purely informational commands. Every one of these returns false (spends no +-- turn) and carries its whole answer in the message, which is the one place +-- a caller should print something the game log itself would never contain. +Handlers.inventory = function(game) + if #game.player.inventory == 0 then return false, "you are carrying nothing" end + local lines = {} + for i, item in ipairs(game.player.inventory) do + lines[#lines + 1] = string.format(" %d) %s", i, Identify.label(game.identify, item)) + end + return false, table.concat(lines, "\n") +end +Handlers.i = Handlers.inventory + +Handlers.status = function(game) + local p = game.player + return false, string.format( + "hp %d/%d mana %d/%d gold %d essence %d level %d xp %d/%d depth %d turn %d", + p.hp, p.maxHp, p.mana or 0, p.maxMana or 0, p.gold, p.essence, + p.level, p.xp, p.xpNext, game.depth, game.turn) +end + +Handlers.look = function(game) + local targets = visibleHostilesInOrder(game) + if #targets == 0 then return false, "you see no threats nearby" end + local names = {} + for i, entity in ipairs(targets) do + names[#names + 1] = string.format("%d) %s", i, entity.name) + end + return false, "in sight: " .. table.concat(names, ", ") +end +Handlers.l = Handlers.look + +-- Detail views (examine.lua): `examine ` inspects inventory item n, the +-- same index use/drop/sell already key off; `examine monster ` inspects +-- the nth entry of the very list Handlers.look just numbered. Both branches +-- are free, like every other informational command here. +Handlers.examine = function(game, args) + if args[1] == "monster" then + local index = tonumber(args[2]) + if not index then return false, "examine which monster? give the number look showed you" end + local target = visibleHostilesInOrder(game)[index] + if not target then return false, "no monster in sight at that number" end + return false, Examine.monster(game.player, target) + end + local index = indexArg(args) + if not index then return false, "examine what? give an inventory number, or 'monster '" end + local item = game.player.inventory[index] + if not item then return false, "you are not carrying anything at that number" end + return false, Examine.item(game.identify, item) +end +Handlers.x = Handlers.examine + +Handlers.help = function() + return false, "commands: north/south/east/west/ne/nw/se/sw (or n/s/e/w/...), attack , " .. + "wait, pickup, explore, rest, travel down/up, inventory, use , drop , sell , throw [target], " .. + "fire [target], capture [target], cast [target], useskill [target], " .. + "open, pray, quest, appease , butcher, raise, " .. + "scavenge, harvest, ransom, sellcaptive, interrogate, dig , disarm , " .. + "descend, ascend, enterrift, exitrift, horde, " .. + "steal, dismiss, learn , forge , merge , brew , " .. + "socket , socketrune , temper , " .. + "enchant , disenchant , repair , " .. + "examine , examine monster , look, status, help " .. + "([target] is the number look/examine gives a monster; omit it to auto-target the nearest one)" +end + +-- Parses `text` and dispatches it against `game`. Returns (consumesTurn, +-- message): Game:manualStep spends the player's turn iff the first value is +-- true, and either surfaces `message` itself (a failure reason, or an +-- informational answer) or leaves the game log to speak for a successful +-- action, exactly the way every Game: method already logs its own +-- outcome. +function Commands.apply(game, text) + local parsed = Commands.parse(text) + if not parsed then return false, "say something" end + local handler = Handlers[parsed.verb] + if not handler then return false, "unknown command: " .. parsed.verb end + return handler(game, parsed.args) +end + +return Commands