174 lines
5.3 KiB
Lua
174 lines
5.3 KiB
Lua
-- 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
|