feat: extend game with Game:learnSkill and Game:useSkill

This commit is contained in:
dualfroz committed 2026-09-06 19:51:54 +02:00
1 parent b4e2c7a431
commit e850ef2d5e
1 file changed
+115 -8
+115 -8
View File
@@ -2295,27 +2295,134 @@ function Game:hungerTorchTick()
self.player.hp = math.min(self.player.maxHp, self.player.hp + weatherRegen) self.player.hp = math.min(self.player.maxHp, self.player.hp + weatherRegen)
end end
end end
local curseDrain = Curses.drainAmount(self.player)
if curseDrain > 0 then
self.player.hp = self.player.hp - curseDrain
self.log:add("a cursed affliction saps your strength")
end
local diseaseLine = Disease.tick(self.player)
if diseaseLine then self.log:add(diseaseLine) end
local hungerLine = Hunger.tick(self.player)
if hungerLine then self.log:add(hungerLine) end
if self.player.light.fuel > 0 then if self.player.light.fuel > 0 then
self.player.light.fuel = self.player.light.fuel - 1 self.player.light.fuel = self.player.light.fuel - 1
end end
if self.player.mana < self.player.maxMana then
self.player.mana = self.player.mana + 1
end
end end
function Game:endPlayerTurn() function Game:endPlayerTurn()
self.turnState = nil
Scheduler.spend(self.player) Scheduler.spend(self.player)
self:hungerTorchTick() self:hungerTorchTick()
Hazards.step(self.level, self.rng)
Nodes.step(self.level)
Corpses.step(self.level)
for _, trap in ipairs(Disarm.sweep(self.level, self.rng, self.player.x, self.player.y)) do
self.log:add("you notice a hidden trap nearby")
end
for _, door in ipairs(Secrets.sweep(self.level, self.rng, self.player.x, self.player.y)) do
self.log:add("you notice a hidden door in the wall")
end
local eventLine = Events.step(self.level, self.rng)
if eventLine then self.log:add(eventLine) end
Skills.tickCooldowns(self.player)
self:resolveQuest()
self.turn = self.turn + 1 self.turn = self.turn + 1
if self.turn % Mercenaries.WAGE_INTERVAL == 0 then
local wageLine = Mercenaries.payWage(self)
if wageLine then self.log:add(wageLine) end
end
self:computeVisible() self:computeVisible()
local sanityLine = Sanity.tick(self)
if sanityLine then self.log:add(sanityLine) end
if Sanity.rollScream(self.rng, self) then
self.log:add("a scream of raw terror tears from your throat")
end
if self.horde then
local hordeLine = Horde.tick(self)
if hordeLine then self.log:add(hordeLine) end
end
end
-- Spends a skill point to permanently learn `key`, gated by class, level and
-- point balance (see skills.lua). Free of any turn cost.
function Game:learnSkill(key)
local success, message = Skills.learn(self.player, key)
if message then self.log:add(message) end
return success
end
-- Attempts to use the active skill `key`, forwarding any extra arguments
-- (a target monster, or two for multishot) straight to skills.lua.
function Game:useSkill(key, ...)
local success, lines = Skills.use(self, key, ...)
self.log:addAll(lines)
return success
end
-- Shared head of any player turn, whether the autopilot or a typed command
-- is about to decide what happens next: runs every other actor up to the
-- player, ticks the status/water/hazard afflictions that land on the
-- player's own turn boundary, and rolls the stun/panic checks that can
-- consume the turn before any action is even chosen. Returns "halt" once
-- play cannot continue this call (already won, or dead at any point along
-- the way - the caller must not act or spend a turn), "skip" once the turn
-- is already spent on a stun or a panic scream, or "ready" once the caller
-- is clear to choose and perform an action of its own.
--
-- Cached on self.turnState until Game:endPlayerTurn clears it, so calling
-- this more than once before a turn is actually spent - the one new
-- situation Game:manualStep introduces, since a rejected typed command
-- spends no turn and its caller is free to just try again - never re-rolls
-- the stun/panic check or re-ticks poison, fire or hunger a second time for
-- a turn the player has not actually finished taking yet. Game:autoStep
-- never revisits an unspent turn this way, so the cache is invisible to it.
function Game:beginTurn()
if self.turnState then return self.turnState end
if self.won then self.turnState = "halt"; return "halt" end
self:runToPlayer()
if not self.player:isAlive() then self.turnState = "halt"; return "halt" end
self.log:addAll(Status.tick(self.player))
if not self.player:isAlive() then self.turnState = "halt"; return "halt" end
Conductivity.tick(self.level, self.player)
local hazardLine = Hazards.afflict(self.level, self.player)
if hazardLine then self.log:add(hazardLine) end
if not self.player:isAlive() then self.turnState = "halt"; return "halt" end
if Status.skipsTurn(self.player) then
self.log:add("you are stunned")
self.turnState = "skip"
elseif Sanity.rollPanic(self.rng, self.player) then
self.log:add("terror seizes you and the turn slips away")
self.turnState = "skip"
else
self.turnState = "ready"
end
return self.turnState
end end
function Game:autoStep() function Game:autoStep()
self:runToPlayer() local state = self:beginTurn()
if not self.player:isAlive() then return end if state == "halt" then return end
self.log:addAll(Status.tick(self.player)) if state == "ready" then self:choosePlayerAction() end
if not self.player:isAlive() then return end self:endPlayerTurn()
if Status.skipsTurn(self.player) then end
self.log:add("you are stunned")
else -- Human-driven counterpart to Game:autoStep: runs the exact same pre-turn
self:choosePlayerAction() -- checks, then hands `text` to commands.lua instead of letting
-- choosePlayerAction decide on its own. Returns (consumesTurn, message) from
-- Commands.apply so a caller (warren.lua's --play REPL, or a test driving a
-- fixed script of commands) can tell a wasted keystroke from a turn the
-- world actually answered. A stun or panic rolled during beginTurn still
-- spends the turn and ends it exactly like autoStep, without ever looking at
-- `text` - the player was never in control of that turn to begin with.
function Game:manualStep(text)
local state = self:beginTurn()
if state == "halt" then return false, "there is nothing left to do" end
if state == "skip" then
self:endPlayerTurn()
return true, nil
end end
self:endPlayerTurn() self:endPlayerTurn()
end end