Files
alchemist-accessibility/accessibility/categories.lua
T

174 lines
5.3 KiB
Lua
Raw Normal View History

2026-08-01 21:34:13 +02:00
-- categories.lua — classifies map contents into tracker categories.
--
-- The game's own `templatesByTag` defines exactly one tag ("exit"), so the
-- tracker needs its own scheme. Per docs/05-decisions.md D4 this is deliberately
-- FLAG-FIRST rather than a hand-listed set of template IDs:
--
-- * flags are authoritative -- modules/tile.lua:234 defines
-- `tile.tryInteract = (loot or tryInteractFunction) and ...`, which is
-- exactly "the player can do something here" versus scenery;
-- * new content in a future game version falls through to a sensible category
-- instead of vanishing from the tracker.
--
-- The only hand-maintained parts are the exclusion list and the exit tag reuse.
local categories = {}
--------------------------------------------------------------------------------
-- Exclusions
--------------------------------------------------------------------------------
-- The six templates with no name, no description and no parent: invisible
-- mechanics that must never be tracked. (See docs/05-decisions.md D4.)
local excludedTemplates = {
blank = true,
throw_blocker = true,
movement_blocker = true,
fire_detector = true,
wall_features_position_dummy = true,
ladder_down_hidden = true,
}
--------------------------------------------------------------------------------
-- Category list (order is the Ctrl+PageUp/PageDown cycle order)
--------------------------------------------------------------------------------
categories.list = {
{key = "creatures", name = "Creatures"},
{key = "items", name = "Items"},
{key = "alchemy", name = "Alchemy"},
{key = "interactables", name = "Interactables"},
{key = "exits", name = "Exits"},
{key = "terrain", name = "Terrain features"},
}
--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local exitTemplates
local function getExitTemplates()
if exitTemplates then
return exitTemplates
end
local ok, templatesByTag = pcall(require, "modules.tile.templatesByTag")
exitTemplates = (ok and templatesByTag and templatesByTag.exit) or {}
return exitTemplates
end
local itemTemplates
local function getItemTemplates()
if itemTemplates then
return itemTemplates
end
local ok, templates = pcall(require, "modules.item.templates")
itemTemplates = (ok and templates) or {}
return itemTemplates
end
-- Item category 3 is "Ingredients" (modules/item/categories.lua).
local INGREDIENT_CATEGORY = 3
local function lootContainsIngredient(loot)
if type(loot) ~= "table" then
return false
end
local templates = getItemTemplates()
for _, entry in ipairs(loot) do
local templateId = type(entry) == "table" and entry.templateId
local template = templateId and templates[templateId]
if template and template.category == INGREDIENT_CATEGORY then
return true
end
end
return false
end
local function isLootable(tile)
return tile.loot and tile.loot[1] and not tile.unlootable
end
--------------------------------------------------------------------------------
-- Classification
--------------------------------------------------------------------------------
-- Returns a category key, or nil if the tile should not be tracked.
function categories.classifyTile(tile)
if not tile or tile.isHidden or not tile.templateId then
return nil
end
if excludedTemplates[tile.templateId] then
return nil
end
if getExitTemplates()[tile.templateId] then
return "exits"
end
if isLootable(tile) then
return lootContainsIngredient(tile.loot) and "alchemy" or "items"
end
-- Structural tiles are never tracked, even though many of them report
-- tryInteract.
--
-- `wall` carries a flavour-only tryInteractFunction ("You touch the wall.
-- It's cold and rough."), so the flag-first rule promoted every wall segment
-- into Interactables -- 13 of them in the starting house alone, burying the
-- chest and the cauldron. tryInteract means "something happens if you press
-- interact", NOT "this is worth walking to".
--
-- blocksMovement AND blocksVision identifies the structural shell (walls,
-- solid rock). Containers and furniture block movement but not sight, so they
-- survive this filter. Walls are covered by the wall tones and the
-- surroundings scan anyway.
if tile.blocksMovement and tile.blocksVision then
return nil
end
if tile.tryInteract then
return "interactables"
end
-- Terrain is intentionally narrow: hazards and water only. Including every
-- wall would bury the useful entries under hundreds of identical ones -- and
-- walls are already covered by the wall tones and the surroundings scan.
if tile.isThreatening then
return "terrain"
end
return nil
end
-- Water is a property of the level's water map rather than of a tile, so it is
-- classified separately during the scan.
categories.WATER_CATEGORY = "terrain"
function categories.tileName(tile)
return tile.name or tile.templateId or "something"
end
function categories.actorName(actor)
return actor.nameObserved or actor.name or actor.templateId or "someone"
end
-- Kind key: groups instances of the same thing together. Template id is stabler
-- than the display name (two templates can share a name).
function categories.tileKind(tile)
return tile.templateId
end
function categories.actorKind(actor)
return actor.templateIdOnExamination or actor.templateId
end
return categories