more refactoring, public cells assigned a faction

This commit is contained in:
Lilian Jónsdóttir 2020-08-26 21:44:56 -07:00
parent 444e607420
commit 6dcf8bb4a8
8 changed files with 125 additions and 59 deletions

View file

@ -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

View 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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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")