Merge pull request #1370 from AverageConsumer/codex/mod-field-action-busy

This commit is contained in:
bryanthaboi
2026-08-15 20:20:12 -04:00
committed by GitHub
4 changed files with 24 additions and 5 deletions
+2
View File
@@ -226,6 +226,8 @@ exposes `headbutt`, `whirlpool`, `waterfall`, `sweet_scent`, and the
contextual `squirtbottle` key item. Fishing rows include the owned rods that contextual `squirtbottle` key item. Fishing rows include the owned rods that
are valid choices. The list is empty while the world is busy, and omits an are valid choices. The list is empty while the world is busy, and omits an
action whenever its item, move, badge, terrain, or engine state forbids it. action whenever its item, move, badge, terrain, or engine state forbids it.
The optional second return is `"world is busy"` during transient input locks
or `"no overworld"` before a playable world exists.
Call `mod.world:useFieldAction(id, opts)` to perform a listed action through Call `mod.world:useFieldAction(id, opts)` to perform a listed action through
the active game's own field-item path. Fishing accepts `{ rod = "OLD_ROD" }` the active game's own field-item path. Fishing accepts `{ rod = "OLD_ROD" }`
+4 -2
View File
@@ -95,8 +95,10 @@ end
-- are listed; callers receive copied labels and never inspect world internals. -- are listed; callers receive copied labels and never inspect world internals.
function WorldAPI:availableFieldActions() function WorldAPI:availableFieldActions()
local game, ow, out = self.game, self:overworld(), {} local game, ow, out = self.game, self:overworld(), {}
if not (game and game.save and ow and ow.map and ow.player) if not (game and game.save and ow and ow.map and ow.player) then
or not acceptsMenuInput(game, ow) then return out end return out, NO_OVERWORLD
end
if not acceptsMenuInput(game, ow) then return out, "world is busy" end
local save, inventory = game.save, game.save.inventory or {} local save, inventory = game.save, game.save.inventory or {}
local items = game.data and game.data.items or {} local items = game.data and game.data.items or {}
+4 -2
View File
@@ -78,8 +78,10 @@ end
-- collision and fishing rules. -- collision and fishing rules.
function WorldAPI:availableFieldActions() function WorldAPI:availableFieldActions()
local world, game, out = self:overworld(), self.game, {} local world, game, out = self:overworld(), self.game, {}
if not (world and game and game.save and world.map and world.player) if not (world and game and game.save and world.map and world.player) then
or not world:acceptsMenuInput() then return out end return out, NO_OVERWORLD
end
if not world:acceptsMenuInput() then return out, "world is busy" end
local inventory = game.save.inventory or {} local inventory = game.save.inventory or {}
if (inventory.BICYCLE or 0) > 0 then if (inventory.BICYCLE or 0) > 0 then
+14 -1
View File
@@ -34,6 +34,9 @@ function redGame.stack:top() return self.states[#self.states] end
local RedAPI = require("src.world.WorldAPI") local RedAPI = require("src.world.WorldAPI")
local red = RedAPI.new(redGame, "fixture") local red = RedAPI.new(redGame, "fixture")
local unavailable, reason = RedAPI.new({}, "fixture"):availableFieldActions()
T.eq(#unavailable, 0, "Red lists no actions without an overworld")
T.eq(reason, "no overworld", "Red reports a missing overworld")
local RedWorld = require("src.world.OverworldController") local RedWorld = require("src.world.OverworldController")
T.check(type(RedWorld.useBicycle) == "function" T.check(type(RedWorld.useBicycle) == "function"
and type(RedWorld.useFishingRod) == "function" and type(RedWorld.useFishingRod) == "function"
@@ -59,7 +62,9 @@ T.check(not ok and err == "fishing rod unavailable",
T.eq(redWorld.rodUsed, used, "a rejected Red rod changes nothing") T.eq(redWorld.rodUsed, used, "a rejected Red rod changes nothing")
redWorld.player.moving = true redWorld.player.moving = true
T.eq(#red:availableFieldActions(), 0, "Red hides actions while moving") actions, err = red:availableFieldActions()
T.eq(#actions, 0, "Red hides actions while moving")
T.eq(err, "world is busy", "Red distinguishes a busy world from no actions")
ok, err = red:useFieldAction("bicycle") ok, err = red:useFieldAction("bicycle")
T.check(not ok and err == "world is busy", T.check(not ok and err == "world is busy",
"Red refuses a stale action while busy") "Red refuses a stale action while busy")
@@ -142,6 +147,9 @@ goldWorld.fieldContext = function(_, mon) return {
local GoldAPI = require("src.world.gen2.WorldAPI") local GoldAPI = require("src.world.gen2.WorldAPI")
local gold = GoldAPI.new(goldGame, "fixture") local gold = GoldAPI.new(goldGame, "fixture")
unavailable, reason = GoldAPI.new({}, "fixture"):availableFieldActions()
T.eq(#unavailable, 0, "Gold lists no actions without an overworld")
T.eq(reason, "no overworld", "Gold reports a missing overworld")
actions = gold:availableFieldActions() actions = gold:availableFieldActions()
byId = {} byId = {}
for _, action in ipairs(actions) do byId[action.id] = action end for _, action in ipairs(actions) do byId[action.id] = action end
@@ -170,4 +178,9 @@ T.check(gold:useFieldAction("squirtbottle"),
T.eq(goldWorld.itemUsed, "SQUIRTBOTTLE", T.eq(goldWorld.itemUsed, "SQUIRTBOTTLE",
"Gold delegates the SquirtBottle to its field-item path") "Gold delegates the SquirtBottle to its field-item path")
goldWorld.acceptsMenuInput = function() return false end
actions, err = gold:availableFieldActions()
T.eq(#actions, 0, "Gold hides actions while busy")
T.eq(err, "world is busy", "Gold distinguishes a busy world from no actions")
T.finish() T.finish()