morrowind-npcs-go-home/MWSE/mods/celediel/NPCsGoHome/functions/housing.lua

118 lines
5.3 KiB
Lua

-- handles finding homes or picking public spaces for NPCs
-- * home cell is chosen according to the following order:
-- * NPC's actual home, i.e.: home cell name contains NPC name
local common = require("celediel.NPCsGoHome.common")
local config = require("celediel.NPCsGoHome.config").getConfig()
local dataTables = require("celediel.NPCsGoHome.functions.dataTables")
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
-- don't move NPCs whose ids match these, just disable them
local contextualNPCs = {"^AM_", "^SF_"}
local this = {}
this.livesInManor = function(cellName, npcName)
if not cellName or (cellName and not string.find(cellName, "Manor")) then return end
local splitName = common.split(npcName)
local given = splitName[1]
local sur = splitName[2]
-- surnameless peasants don't live in manors
if not sur then return end
log(common.logLevels.large, "[HOUSING] Checking if %s %s lives in %s", given, sur, cellName)
return string.match(cellName, sur)
end
this.pickInnForNPC = function(npc, city)
-- todo: pick in Inn intelligently ?
-- high class inns for nobles and rich merchants and such
-- lower class inns for middle class npcs and merchants
-- temple for commoners and the poorest people
-- but for now pick one at random
if common.runtimeData.publicHouses.byType[city] and common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.inns] then
local choice = table.choice(common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.inns])
if not choice then return nil end
log(common.logLevels.medium, "[HOUSING] Picking inn %s, %s for %s", choice.city, choice.name, npc.object.name)
return choice.cell
end
end
this.pickPublicHouseForNPC = function(npc, city)
-- look for wandering guild members
if common.runtimeData.publicHouses.byType[city] and
common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.guildhalls] then
for _, data in pairs(common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.guildhalls]) do
-- if npc's faction and proprietor's faction match, pick that one
if npc.object.faction == data.proprietor.object.faction then
log(common.logLevels.medium, "[HOUSING] Picking %s for %s based on faction", data.cell.id, npc.object.name)
return data.cell
end
end
end
-- temple members go to the temple
if common.runtimeData.publicHouses.byType[city] and common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.temples] then
for _, data in pairs(common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.temples]) do
if npc.object.faction == data.proprietor.object.faction then
log(common.logLevels.medium, "[HOUSING] Picking temple %s for %s based on faction", data.cell.id, npc.object.name)
return data.cell
end
end
end
-- found nothing so pick an inn
return this.pickInnForNPC(npc, city)
end
-- looks through doors to find a cell that matches a wandering NPCs name
this.pickHomeForNPC = function(cell, npc)
-- don't move contextual, such as Animated Morrowind, NPCs at all
for _, str in pairs(contextualNPCs) do if npc.object.id:match(str) then return end end
-- time to pick the "home"
local name = npc.object.name:gsub(" the .*$", "") -- remove "the whatever" from NPCs name
local city = cell.name and common.split(cell.name, ",")[1] or "wilderness"
-- don't need to pick a home if we already have one
if common.runtimeData.homes.byName[name] then return common.runtimeData.homes.byName[name] end
-- check if the NPC already has a house
for door in cell:iterateReferences(tes3.objectType.door) do
if door.destination then
local dest = door.destination.cell
-- essentially, if npc full name, or surname matches the cell name
if dest.id:match(name) or this.livesInManor(dest.name, name) then
return dataTables.createHomedNPCTableEntry(npc, dest, cell, true)
end
end
end
-- haven't found a home, so put them in an inn or guildhall, or inside a canton
if config.homelessWanderersToPublicHouses then
log(common.logLevels.medium, "[HOUSING] Didn't find a home for %s, trying inns", npc.object.name)
local dest = this.pickPublicHouseForNPC(npc, city)
if dest then return dataTables.createHomedNPCTableEntry(npc, dest, cell, false) end
-- if nothing was found, then we'll settle on Canton works cell, if the cell is a Canton
if common.isCantonCell(cell) then
if common.runtimeData.publicHouses.byType[city] and
common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.cantonworks] then
local canton = table.choice(common.runtimeData.publicHouses.byType[city][common.publicHouseTypes.cantonworks])
log(common.logLevels.medium, "[HOUSING] Picking works %s, %s for %s", canton.city, canton.name, npc.object.name)
if canton then return dataTables.createHomedNPCTableEntry(npc, canton.cell, cell, false) end
end
end
end
-- didn't find anything
return nil
end
return this