more refactoring, public cells assigned a faction
This commit is contained in:
parent
444e607420
commit
6dcf8bb4a8
|
@ -22,6 +22,16 @@ this.publicHouseTypes = {
|
|||
houses = "Houses",
|
||||
cantonworks = "Cantonworks"
|
||||
}
|
||||
|
||||
-- Canton string matches
|
||||
-- move NPCs into waistworks
|
||||
this.waistworks = "[Ww]aistworks"
|
||||
-- don't lock canalworks
|
||||
this.canalworks = "[Cc]analworks"
|
||||
-- doors to underworks should be ignored
|
||||
-- but NPCs in underworks should not be disabled
|
||||
this.underworks = "[Uu]nderworks"
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Filled at runtime
|
||||
|
@ -69,13 +79,27 @@ this.vowel = function(str)
|
|||
return n
|
||||
end
|
||||
|
||||
-- picks the key of the largest value out of a key:whatever, value:number table
|
||||
this.keyOfLargestValue = function(t)
|
||||
local picked
|
||||
local largest = 0
|
||||
for key, value in pairs(t) do
|
||||
if value > largest then
|
||||
largest = value
|
||||
picked = key
|
||||
end
|
||||
end
|
||||
-- return largest == 0 and nil or largest
|
||||
return picked
|
||||
end
|
||||
|
||||
-- todo: pick this better
|
||||
this.pickPublicHouseType = function(cell)
|
||||
if cell.id:match("Guild") then
|
||||
return this.publicHouseTypes.guildhalls
|
||||
elseif cell.id:match("Temple") then
|
||||
return this.publicHouseTypes.temples
|
||||
elseif cell.id:match("[Cc]analworks") or cell.id:match("[Ww]aistworks") then
|
||||
elseif cell.id:match(this.canalworks) or cell.id:match(this.waistworks) then
|
||||
return this.publicHouseTypes.cantonworks
|
||||
-- elseif cell.id:match("House") then
|
||||
-- return publicHouseTypes.houses
|
||||
|
@ -99,6 +123,19 @@ this.checkModdedCell = function(cellId)
|
|||
|
||||
return id
|
||||
end
|
||||
|
||||
this.isCantonWorksCell = function(cell)
|
||||
-- for _, str in pairs(waistworks) do if cell.id:match(str) then return true end end
|
||||
return cell.id:match(this.waistworks) or cell.id:match(this.canalworks) or cell.id:match(this.underworks)
|
||||
end
|
||||
|
||||
this.isCantonCell = function(cell)
|
||||
if cell.isInterior and not cell.behavesAsExterior then return false end
|
||||
for door in cell:iterateReferences(tes3.objectType.door) do
|
||||
if door.destination and this.isCantonWorksCell(door.destination.cell) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
-- }}}
|
||||
|
||||
return this
|
||||
|
|
52
MWSE/mods/celediel/NPCsGoHome/functions/cellEvaluators.lua
Normal file
52
MWSE/mods/celediel/NPCsGoHome/functions/cellEvaluators.lua
Normal file
|
@ -0,0 +1,52 @@
|
|||
local common = require("celediel.NPCsGoHome.common")
|
||||
local config = require("celediel.NPCsGoHome.config").getConfig()
|
||||
local npcEvaluators = require("celediel.NPCsGoHome.functions.npcEvaluators")
|
||||
|
||||
local this = {}
|
||||
|
||||
-- todo: logging
|
||||
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
||||
|
||||
this.calculateCellWorth = function(cell, proprietor)
|
||||
-- cell worth is combined worth of all NPCs
|
||||
local worth = 0
|
||||
|
||||
for innard in cell:iterateReferences(tes3.objectType.npc) do
|
||||
worth = worth + npcEvaluators.calculateNPCWorth(innard, innard == proprietor and cell or nil).total
|
||||
end
|
||||
|
||||
return worth
|
||||
end
|
||||
|
||||
this.pickCellFaction = function(cell)
|
||||
-- iterate NPCs in the cell, if 2/3 the population is any one faction,
|
||||
-- that's the cell's faction, otherwise, cell doesn't have a faction.
|
||||
local npcs = {majorityFactions = {}, allFactions = {}, total = 0}
|
||||
for npc in cell:iterateReferences(tes3.objectType.npc) do
|
||||
local faction = npc.object.faction
|
||||
|
||||
if faction then
|
||||
if not npcs.allFactions[faction] then npcs.allFactions[faction] = {total = 0, percentage = 0} end
|
||||
|
||||
if not npcs.allFactions[faction].master or npcs.allFactions[faction].master.object.factionIndex <
|
||||
npc.object.factionIndex then npcs.allFactions[faction].master = npc end
|
||||
|
||||
npcs.allFactions[faction].total = npcs.allFactions[faction].total + 1
|
||||
end
|
||||
|
||||
npcs.total = npcs.total + 1
|
||||
end
|
||||
|
||||
for faction, info in pairs(npcs.allFactions) do
|
||||
info.percentage = (info.total / npcs.total) * 100
|
||||
if info.percentage >= config.factionIgnorePercentage then
|
||||
-- return faction.id
|
||||
npcs.majorityFactions[faction] = info.percentage
|
||||
end
|
||||
end
|
||||
|
||||
-- no faction
|
||||
return table.empty(npcs.majorityFactions) and "none" or common.keyOfLargestValue(npcs.majorityFactions)
|
||||
end
|
||||
|
||||
return this
|
|
@ -2,16 +2,9 @@
|
|||
local common = require("celediel.NPCsGoHome.common")
|
||||
local config = require("celediel.NPCsGoHome.config").getConfig()
|
||||
local dataTables = require("celediel.NPCsGoHome.functions.dataTables")
|
||||
local cellEvaluators = require("celediel.NPCsGoHome.functions.cellEvaluators")
|
||||
|
||||
-- {{{ local variables and such
|
||||
-- Canton string matches
|
||||
-- move NPCs into waistworks
|
||||
local waistworks = "[Ww]aistworks"
|
||||
-- don't lock canalworks
|
||||
local canalworks = "[Cc]analworks"
|
||||
-- doors to underworks should be ignored
|
||||
-- but NPCs in underworks should not be disabled
|
||||
local underworks = "[Uu]nderworks"
|
||||
|
||||
-- city name if cell.name is nil
|
||||
local wilderness = "Wilderness"
|
||||
|
@ -22,7 +15,7 @@ local function log(level, ...) if config.logLevel >= level then common.log(...)
|
|||
|
||||
-- patented by Merlord
|
||||
local yeet = function(reference)
|
||||
-- tes3.positionCell({reference = reference, position = {0, 0, 10000}})
|
||||
tes3.positionCell({reference = reference, position = {0, 0, 10000}})
|
||||
reference:disable()
|
||||
timer.delayOneFrame(function() mwscript.setDelete({reference = reference}) end)
|
||||
end
|
||||
|
@ -35,10 +28,10 @@ local function getFightFromSpawnedReference(id)
|
|||
|
||||
local ref = tes3.createReference({
|
||||
object = id,
|
||||
-- cell = toddTest,
|
||||
cell = tes3.getPlayerCell(),
|
||||
-- position = zeroVector,
|
||||
position = {0, 0, 10000},
|
||||
cell = toddTest,
|
||||
-- cell = tes3.getPlayerCell(),
|
||||
position = tes3vector3.new(0, 0, 0),
|
||||
-- position = {0, 0, 10000},
|
||||
orientation = tes3vector3.new(0, 0, 0)
|
||||
})
|
||||
|
||||
|
@ -97,19 +90,6 @@ this.isIgnoredCell = function(cell)
|
|||
return config.ignored[cell.id] or config.ignored[cell.sourceMod] -- or wilderness
|
||||
end
|
||||
|
||||
this.isCantonWorksCell = function(cell)
|
||||
-- for _, str in pairs(waistworks) do if cell.id:match(str) then return true end end
|
||||
return cell.id:match(waistworks) or cell.id:match(canalworks) or cell.id:match(underworks)
|
||||
end
|
||||
|
||||
this.isCantonCell = function(cell)
|
||||
if this.isInteriorCell(cell) then return false end
|
||||
for door in cell:iterateReferences(tes3.objectType.door) do
|
||||
if door.destination and this.isCantonWorksCell(door.destination.cell) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- ! this one depends on tes3 ! --
|
||||
this.fargothCheck = function()
|
||||
local fargothJournal = tes3.getJournalIndex({id = "MS_Lookout"})
|
||||
|
@ -186,6 +166,8 @@ this.isPublicHouse = function(cell)
|
|||
if not this.isInteriorCell(cell) then return false end
|
||||
|
||||
-- gather some data about the cell
|
||||
local worth = cellEvaluators.calculateCellWorth(cell)
|
||||
local faction = cellEvaluators.pickCellFaction(cell)
|
||||
local typeOfPub = common.pickPublicHouseType(cell)
|
||||
local city, publicHouseName
|
||||
|
||||
|
@ -204,8 +186,8 @@ this.isPublicHouse = function(cell)
|
|||
end
|
||||
|
||||
-- if it's a waistworks cell, it's public, with no proprietor
|
||||
if config.waistWorks == common.waist.public and cell.id:match(waistworks) then
|
||||
dataTables.createPublicHouseTableEntry(cell, nil, city, publicHouseName)
|
||||
if config.waistWorks == common.waist.public and cell.id:match(common.waistworks) then
|
||||
dataTables.createPublicHouseTableEntry(cell, nil, city, publicHouseName, worth, faction)
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -217,8 +199,7 @@ this.isPublicHouse = function(cell)
|
|||
log(common.logLevels.medium, "NPC:\'%s\' of class:\'%s\' made %s public", npc.object.name,
|
||||
npc.object.class and npc.object.class.id or "none", cell.name)
|
||||
|
||||
dataTables.createPublicHouseTableEntry(cell, npc, city, publicHouseName)
|
||||
|
||||
dataTables.createPublicHouseTableEntry(cell, npc, city, publicHouseName, worth, faction)
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -251,7 +232,7 @@ this.isPublicHouse = function(cell)
|
|||
config.factionIgnorePercentage then
|
||||
log(common.logLevels.medium, "%s is %s%% faction %s, marking public.", cell.name, info.percentage, faction)
|
||||
|
||||
dataTables.createPublicHouseTableEntry(cell, npcs.factions[faction].master, city, publicHouseName)
|
||||
dataTables.createPublicHouseTableEntry(cell, npcs.factions[faction].master, city, publicHouseName, worth, faction)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -287,7 +268,7 @@ this.isIgnoredDoor = function(door, homeCellId)
|
|||
end
|
||||
|
||||
-- don't lock doors to canton cells
|
||||
local isCantonWorks = this.isCantonWorksCell(dest)
|
||||
local isCantonWorks = common.isCantonWorksCell(dest)
|
||||
|
||||
log(common.logLevels.large, "%s is %s, (%sin a city, is %spublic, %soccupied)", --
|
||||
dest.id, this.isIgnoredCell(dest) and "ignored" or "not ignored", -- destination is ignored
|
||||
|
|
|
@ -3,7 +3,7 @@ local common = require("celediel.NPCsGoHome.common")
|
|||
local config = require("celediel.NPCsGoHome.config").getConfig()
|
||||
local interop = require("celediel.NPCsGoHome.interop")
|
||||
local positions = require("celediel.NPCsGoHome.data.positions")
|
||||
local evaluators = require("celediel.NPCsGoHome.functions.npcEvaluators")
|
||||
local npcEvaluators = require("celediel.NPCsGoHome.functions.npcEvaluators")
|
||||
|
||||
local zeroVector = tes3vector3.new(0, 0, 0)
|
||||
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
||||
|
@ -13,18 +13,20 @@ local this = {}
|
|||
this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, position, orientation)
|
||||
if npc.object and (npc.object.name == nil or npc.object.name == "") then return end
|
||||
|
||||
local pickedPosition, pickedOrientation, pos, ori
|
||||
|
||||
-- mod support for different positions in cells
|
||||
local id = common.checkModdedCell(home.id)
|
||||
|
||||
log(common.logLevels.medium, "Found %s for %s: %s... adding it to in memory table...",
|
||||
isHome and "home" or "public house", npc.object.name, id)
|
||||
|
||||
-- pick the position and orientation the NPC will be placed at
|
||||
local pickedPosition, pickedOrientation, pos, ori
|
||||
|
||||
if isHome and positions.npcs[npc.object.name] then
|
||||
pos = positions.npcs[npc.object.name].position
|
||||
ori = positions.npcs[npc.object.name].orientation
|
||||
elseif not table.empty(common.runtimeData.positions[id]) then
|
||||
-- pick a random position out of the positions in memory
|
||||
local choice, index = table.choice(common.runtimeData.positions[id])
|
||||
pos = choice.position
|
||||
ori = choice.orientation
|
||||
|
@ -57,7 +59,7 @@ this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, posit
|
|||
ogOrientation = ogOrientation, -- tes3vector3
|
||||
homePosition = pickedPosition, -- tes3vector3
|
||||
homeOrientation = pickedOrientation, -- tes3vector3
|
||||
worth = evaluators.calculateNPCWorth(npc) -- int
|
||||
worth = npcEvaluators.calculateNPCWorth(npc) -- int
|
||||
}
|
||||
|
||||
common.runtimeData.homes.byName[npc.object.name] = entry
|
||||
|
@ -68,20 +70,9 @@ this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, posit
|
|||
return entry
|
||||
end
|
||||
|
||||
this.createPublicHouseTableEntry = function(publicCell, proprietor, city, name)
|
||||
this.createPublicHouseTableEntry = function(publicCell, proprietor, city, name, cellWorth, cellFaction)
|
||||
local typeOfPub = common.pickPublicHouseType(publicCell)
|
||||
|
||||
local worth = 0
|
||||
|
||||
-- cell worth is combined worth of all NPCs
|
||||
for innard in publicCell:iterateReferences(tes3.objectType.npc) do
|
||||
if innard == proprietor then
|
||||
worth = worth + evaluators.calculateNPCWorth(innard, publicCell).total
|
||||
else
|
||||
worth = worth + evaluators.calculateNPCWorth(innard).total
|
||||
end
|
||||
end
|
||||
|
||||
local proprietorName = proprietor and proprietor.object.name or "no one"
|
||||
|
||||
if not common.runtimeData.publicHouses[city] then common.runtimeData.publicHouses[city] = {} end
|
||||
|
@ -96,7 +87,8 @@ this.createPublicHouseTableEntry = function(publicCell, proprietor, city, name)
|
|||
cell = publicCell,
|
||||
proprietor = proprietor,
|
||||
proprietorName = proprietorName,
|
||||
worth = worth
|
||||
worth = cellWorth,
|
||||
faction = cellFaction
|
||||
}
|
||||
|
||||
interop.setRuntimeData(common.runtimeData)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
-- handles finding homes or picking public spaces NPCs
|
||||
-- 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 checks = require("celediel.NPCsGoHome.functions.checks")
|
||||
local dataTables = require("celediel.NPCsGoHome.functions.dataTables")
|
||||
|
||||
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
||||
|
@ -31,8 +32,6 @@ this.pickInnForNPC = function(npc, city)
|
|||
-- 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
|
||||
-- ? pick based on barterGold and value of equipment for merchants ?
|
||||
-- ? for others, pick based on value of equipment
|
||||
|
||||
-- but for now pick one at random
|
||||
if common.runtimeData.publicHouses[city] and common.runtimeData.publicHouses[city][common.publicHouseTypes.inns] then
|
||||
|
@ -81,6 +80,8 @@ this.pickHomeForNPC = function(cell, npc)
|
|||
-- time to pick the "home"
|
||||
local name = npc.object.name
|
||||
local city = common.split(cell.name, ",")[1]
|
||||
|
||||
-- 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
|
||||
|
@ -102,10 +103,9 @@ this.pickHomeForNPC = function(cell, npc)
|
|||
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 checks.isCantonCell(cell) then
|
||||
if common.isCantonCell(cell) then
|
||||
if common.runtimeData.publicHouses[city] and
|
||||
common.runtimeData.publicHouses[city][common.publicHouseTypes.cantonworks] then
|
||||
-- todo: maybe poorer NPCs in canalworks, others in waistworks ?
|
||||
local canton = table.choice(common.runtimeData.publicHouses[city][common.publicHouseTypes.cantonworks])
|
||||
log(common.logLevels.medium, "Picking works %s, %s for %s", canton.city, canton.name, npc.object.name)
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
-- handles evalutating NPCs
|
||||
-- handles evaluating NPCs
|
||||
local this = {}
|
||||
|
||||
-- todo: logging
|
||||
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
||||
|
||||
-- NPCs barter gold + value of all inventory items
|
||||
this.calculateNPCWorth = function(npc, merchantCell)
|
||||
-- start with this
|
||||
|
@ -33,7 +36,7 @@ this.calculateNPCWorth = function(npc, merchantCell)
|
|||
end
|
||||
end
|
||||
|
||||
-- caculate the total
|
||||
-- calculate the total
|
||||
local total = 0
|
||||
for _, v in pairs(worth) do total = total + v end
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ local function log(level, ...) if config.logLevel >= level then common.log(...)
|
|||
|
||||
local this = {}
|
||||
|
||||
-- create an in memory list of positions for a cell, to ensure multiple NPCs aren't placed in the same spot
|
||||
this.updatePositions = function(cell)
|
||||
local id = cell.id
|
||||
-- update runtime positions in cell, but don't overwrite loaded positions
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
-- {{{ other files
|
||||
-- ? could probably split this file out to others as well
|
||||
-- todo: too many things require too many other things, needs fix
|
||||
local config = require("celediel.NPCsGoHome.config").getConfig()
|
||||
local common = require("celediel.NPCsGoHome.common")
|
||||
local checks = require("celediel.NPCsGoHome.functions.checks")
|
||||
|
|
Loading…
Reference in a new issue