feat: add targetArg to commands

This commit is contained in:
dualfroz committed 2026-09-02 21:29:54 +02:00
1 parent 1d5768acd1
commit 4e4d22cf2e
1 file changed
+155
+155
View File
@@ -322,3 +322,158 @@ local function hereHandler(methodName, nothingMessage)
end end
end end
Handlers.open = hereHandler("openChest", "there is nothing here to open")
Handlers.butcher = hereHandler("butcherCorpse", "there is nothing here to butcher")
Handlers.raise = hereHandler("raiseCorpse", "there is nothing here to raise")
Handlers.scavenge = hereHandler("scavengeCorpse", "there is nothing here to scavenge")
Handlers.harvest = hereHandler("harvestNode", "there is nothing here to harvest")
Handlers.ransom = hereHandler("ransomCaptive", "there is nothing here to ransom")
Handlers.sellcaptive = hereHandler("sellCaptive", "there is nothing here to sell")
Handlers.interrogate = hereHandler("interrogateCaptive", "there is nothing here to interrogate")
Handlers.descend = hereHandler("descend", "there are no stairs down here")
Handlers[">"] = Handlers.descend
Handlers.ascend = hereHandler("ascend", "there are no stairs up here")
Handlers["<"] = Handlers.ascend
Handlers.enterrift = hereHandler("enterRift", "there is no rift here to cross")
Handlers.exitrift = hereHandler("exitRift", "you are not standing across a rift")
-- Game:startHorde is a deliberate, one-way trial (see its own header: the
-- dungeon floor left behind is simply abandoned, there is no exit back) that
-- always succeeds and, unlike every hereHandler above, carries no location
-- requirement of its own - so this guards against the one real footgun a
-- typed command adds that the method itself does not: retyping "horde"
-- mid-run would otherwise silently discard the current wave and its
-- progress by building a brand new arena on top of it.
Handlers.horde = function(game)
if game.horde then return false, "you are already fighting in the arena" end
game:startHorde()
return true, nil
end
Handlers.pray = function(game)
local shrine = game.level:shrineAt(game.player.x, game.player.y)
if not shrine then return false, "there is no shrine here" end
if game:prayAt(shrine) then return true, nil end
return false, "your prayer goes unanswered"
end
Handlers.quest = function(game)
local board = game.level:questBoardAt(game.player.x, game.player.y)
if not board then return false, "there is no quest board here" end
if game:tryAcceptQuest(board) then return true, nil end
return false, "you cannot take up that bounty"
end
-- Every faction key factions.lua defines, spelled out here (rather than
-- discovered from the module at runtime) purely so a bad argument's error
-- message can list them by name; the set itself is built from the same
-- constants Game:appeaseFaction already trusts, so a typo can never buy
-- standing with a faction that does not exist.
local FACTION_NAMES = {
Factions.MERCHANT, Factions.GOBLINOID, Factions.VERMIN, Factions.ORCISH,
Factions.UNDEAD, Factions.BEAST, Factions.CULT, Factions.DRAKE, Factions.BANDIT,
}
local FACTION_SET = {}
for _, name in ipairs(FACTION_NAMES) do FACTION_SET[name] = true end
Handlers.appease = function(game, args)
local faction = args[1]
if not faction or not FACTION_SET[faction] then
return false, "appease which faction? " .. table.concat(FACTION_NAMES, ", ")
end
if game:appeaseFaction(faction) then return true, nil end
return false, nil
end
Handlers.dig = function(game, args)
local dir = DIRS[args[1]]
if not dir then return false, "dig which direction?" end
if game:dig(dir[1], dir[2]) then return true, nil end
return false, "you cannot dig there"
end
-- Disarms a detected-but-unsprung trap one step away in `dir` - the same
-- Chebyshev-1 reach Disarm.sweep already uses to notice it in the first
-- place (see Game:endPlayerTurn's "you notice a hidden trap nearby"). The
-- validity check below duplicates Game:disarmTrap's own guard on purpose:
-- unlike every other handler here, a disarm attempt against a real trap
-- must still spend the turn even when Disarm.attempt fails and springs it,
-- but Game:disarmTrap's own boolean return conflates that spring with "no
-- trap here" into the same false - so this handler tells the two apart
-- itself instead of trusting the method's return value for turn cost.
Handlers.disarm = function(game, args)
local dir = DIRS[args[1]]
if not dir then return false, "disarm which direction?" end
local trap = game.level:trapAt(game.player.x + dir[1], game.player.y + dir[2])
if not trap or not trap.detected or trap.revealed then
return false, "there is nothing here you have noticed to disarm"
end
game:disarmTrap(trap)
return true, nil
end
-- Crafting/economy verbs (game.lua's forgeGem/mergeGemsAt/socketItem/
-- socketRune/temperItem/enchantItem/disenchantItem/repairEquipped/
-- stealFromShop/dismissHireling/learnSkill/brewAt), the other half of the
-- API choosePlayerAction can already reach that a typed session could not
-- until now. Every one of these Game methods already logs its own success
-- or failure reason, so a handler only needs its own message for an
-- argument so malformed the underlying method can never even be called.
-- Shared by socket/socketrune/temper/enchant/disenchant: their `target`
-- resolves through Game:resolveGear exactly like this, either the literal
-- word for currently equipped gear or an inventory slot number for
-- anything else (a spare ring, an unequipped bow).
local function targetArg(token)
if token == "weapon" or token == "armor" then return token end
return tonumber(token)
end
Handlers.forge = function(game, args)
local element = args[1]
if not element then return false, "forge which element? fire, frost, shock or venom" end
if game:forgeGem(element) then return true, nil end
return false, nil
end
Handlers.merge = function(game, args)
local a, b = tonumber(args[1]), tonumber(args[2])
if not a or not b then return false, "merge which two gems? give two inventory numbers" end
if game:mergeGemsAt(a, b) then return true, nil end
return false, "those cannot be merged"
end
Handlers.socket = function(game, args)
local target, gemIndex = targetArg(args[1]), tonumber(args[2])
if not target or not gemIndex then
return false, "socket what into what? give a target (weapon/armor/item number) and a gem number"
end
if game:socketItem(target, gemIndex) then return true, nil end
return false, "that cannot be socketed"
end
Handlers.socketrune = function(game, args)
local target, runeIndex = targetArg(args[1]), tonumber(args[2])
if not target or not runeIndex then
return false, "socket which rune into what? give a target (weapon/armor/item number) and a rune number"
end
if game:socketRune(target, runeIndex) then return true, nil end
return false, "that cannot be socketed"
end
Handlers.temper = function(game, args)
local target = targetArg(args[1])
if not target then return false, "temper what? weapon, armor or an item number" end
if game:temperItem(target) then return true, nil end
return false, "that cannot be tempered"
end
Handlers.enchant = function(game, args)
local target, affixKey = targetArg(args[1]), args[2]
if not target or not affixKey then
return false, "enchant what with what? give a target (weapon/armor/item number) and an affix name"
end
if game:enchantItem(target, affixKey) then return true, nil end
return false, "that cannot be enchanted"
end