better logging and such
This commit is contained in:
parent
79f5f394b9
commit
8a640d07f3
|
@ -1,5 +1,3 @@
|
||||||
local inspect = require("inspect")
|
|
||||||
|
|
||||||
local this = {}
|
local this = {}
|
||||||
|
|
||||||
-- {{{ Variables and such
|
-- {{{ Variables and such
|
||||||
|
@ -65,11 +63,6 @@ end
|
||||||
|
|
||||||
this.log = function(...) mwse.log("[%s] %s", this.modName, string.format(...)) end
|
this.log = function(...) mwse.log("[%s] %s", this.modName, string.format(...)) end
|
||||||
|
|
||||||
this.inspect = function(thing)
|
|
||||||
this.log("Inspecting a %s", thing)
|
|
||||||
this.log(inspect(thing))
|
|
||||||
end
|
|
||||||
|
|
||||||
this.vowel = function(str)
|
this.vowel = function(str)
|
||||||
local s = string.sub(str, 1, 1)
|
local s = string.sub(str, 1, 1)
|
||||||
local n = ""
|
local n = ""
|
||||||
|
@ -89,7 +82,6 @@ this.keyOfLargestValue = function(t)
|
||||||
picked = key
|
picked = key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- return largest == 0 and nil or largest
|
|
||||||
return picked
|
return picked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,49 +4,59 @@ local npcEvaluators = require("celediel.NPCsGoHome.functions.npcEvaluators")
|
||||||
|
|
||||||
local this = {}
|
local this = {}
|
||||||
|
|
||||||
-- todo: logging
|
|
||||||
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
local function log(level, ...) if config.logLevel >= level then common.log(...) end end
|
||||||
|
|
||||||
|
-- cell worth is combined worth of all NPCs
|
||||||
this.calculateCellWorth = function(cell, proprietor)
|
this.calculateCellWorth = function(cell, proprietor)
|
||||||
-- cell worth is combined worth of all NPCs
|
|
||||||
local worth = 0
|
local worth = 0
|
||||||
|
|
||||||
|
local msg = "breakdown:\n"
|
||||||
for innard in cell:iterateReferences(tes3.objectType.npc) do
|
for innard in cell:iterateReferences(tes3.objectType.npc) do
|
||||||
worth = worth + npcEvaluators.calculateNPCWorth(innard, innard == proprietor and cell or nil).total
|
local total = npcEvaluators.calculateNPCWorth(innard, innard == proprietor and cell or nil).total
|
||||||
|
worth = worth + total
|
||||||
|
msg = msg .. string.format("%s worth:%s, ", innard.object.name, total)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
log(common.logLevels.medium, "Calculated worth of %s for cell %s", worth, cell.id)
|
||||||
|
log(common.logLevels.large, msg:sub(1, #msg - 2)) -- strip off last ", "
|
||||||
return worth
|
return worth
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- iterate NPCs in the cell, if configured amount of the population is any one
|
||||||
|
-- faction, that's the cell's faction, otherwise, cell doesn't have a faction.
|
||||||
this.pickCellFaction = function(cell)
|
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}
|
local npcs = {majorityFactions = {}, allFactions = {}, total = 0}
|
||||||
|
|
||||||
|
-- count all the npcs with factions
|
||||||
for npc in cell:iterateReferences(tes3.objectType.npc) do
|
for npc in cell:iterateReferences(tes3.objectType.npc) do
|
||||||
local faction = npc.object.faction
|
local faction = npc.object.faction
|
||||||
|
|
||||||
if faction then
|
if faction then
|
||||||
if not npcs.allFactions[faction] then npcs.allFactions[faction] = {total = 0, percentage = 0} end
|
if not npcs.allFactions[faction.id] then npcs.allFactions[faction.id] = {total = 0, percentage = 0} end
|
||||||
|
|
||||||
if not npcs.allFactions[faction].master or npcs.allFactions[faction].master.object.factionIndex <
|
if not npcs.allFactions[faction.id].master or npcs.allFactions[faction.id].master.object.factionIndex <
|
||||||
npc.object.factionIndex then npcs.allFactions[faction].master = npc end
|
npc.object.factionIndex then npcs.allFactions[faction.id].master = npc end
|
||||||
|
|
||||||
npcs.allFactions[faction].total = npcs.allFactions[faction].total + 1
|
npcs.allFactions[faction.id].total = npcs.allFactions[faction.id].total + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
npcs.total = npcs.total + 1
|
npcs.total = npcs.total + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
for faction, info in pairs(npcs.allFactions) do
|
-- pick out all the factions that make up a percentage of the cell greater than the configured value
|
||||||
|
-- as long as the cell passes the minimum requirement check
|
||||||
|
for id, info in pairs(npcs.allFactions) do
|
||||||
info.percentage = (info.total / npcs.total) * 100
|
info.percentage = (info.total / npcs.total) * 100
|
||||||
if info.percentage >= config.factionIgnorePercentage then
|
if info.percentage >= config.factionIgnorePercentage and npcs.total >= config.minimumOccupancy then
|
||||||
-- return faction.id
|
npcs.majorityFactions[id] = info.percentage
|
||||||
npcs.majorityFactions[faction] = info.percentage
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- no faction
|
-- from the majority values, return the faction with the largest percentage, or "none"
|
||||||
return table.empty(npcs.majorityFactions) and "none" or common.keyOfLargestValue(npcs.majorityFactions)
|
local picked = common.keyOfLargestValue(npcs.majorityFactions)
|
||||||
|
log(common.logLevels.medium, "Picked faction %s for cell %s", picked, cell.id)
|
||||||
|
log(common.logLevels.large, "breakdown:\n%s", json.encode(npcs, {indent = true}))
|
||||||
|
return picked
|
||||||
end
|
end
|
||||||
|
|
||||||
return this
|
return this
|
||||||
|
|
|
@ -109,6 +109,8 @@ this.isIgnoredNPC = function(npc)
|
||||||
local isDead = false
|
local isDead = false
|
||||||
local isHostile = false
|
local isHostile = false
|
||||||
local isVampire = false
|
local isVampire = false
|
||||||
|
-- some TR "Hired Guards" aren't actually "guards", ignore them as well
|
||||||
|
local isGuard = obj.isGuard or (obj.name:lower():match("guard") and true or false)
|
||||||
|
|
||||||
if npc.mobile then
|
if npc.mobile then
|
||||||
if npc.mobile.health.current <= 0 or npc.mobile.isDead then isDead = true end
|
if npc.mobile.health.current <= 0 or npc.mobile.isDead then isDead = true end
|
||||||
|
@ -132,13 +134,13 @@ this.isIgnoredNPC = function(npc)
|
||||||
"guard:%s dead:%s vampire:%s werewolf:%s dreamer:%s follower:%s hostile:%s %s%s"), --
|
"guard:%s dead:%s vampire:%s werewolf:%s dreamer:%s follower:%s hostile:%s %s%s"), --
|
||||||
obj.name, npc.object.id, npc.object.baseObject and npc.object.baseObject.id or "nil", --
|
obj.name, npc.object.id, npc.object.baseObject and npc.object.baseObject.id or "nil", --
|
||||||
config.ignored[obj.id:lower()], obj.sourceMod, config.ignored[obj.sourceMod:lower()], --
|
config.ignored[obj.id:lower()], obj.sourceMod, config.ignored[obj.sourceMod:lower()], --
|
||||||
obj.isGuard, isDead, isVampire, isWerewolf, (obj.class and obj.class.id == "Dreamers"), --
|
isGuard, isDead, isVampire, isWerewolf, (obj.class and obj.class.id == "Dreamers"), --
|
||||||
common.runtimeData.followers[npc.object.id], isHostile, obj.id:match("fargoth") and "fargoth:" or "", --
|
common.runtimeData.followers[npc.object.id], isHostile, obj.id:match("fargoth") and "fargoth:" or "", --
|
||||||
obj.id:match("fargoth") and isFargothActive or "")
|
obj.id:match("fargoth") and isFargothActive or "")
|
||||||
|
|
||||||
return config.ignored[obj.id:lower()] or --
|
return config.ignored[obj.id:lower()] or --
|
||||||
config.ignored[obj.sourceMod:lower()] or --
|
config.ignored[obj.sourceMod:lower()] or --
|
||||||
obj.isGuard or --
|
isGuard or --
|
||||||
isFargothActive or --
|
isFargothActive or --
|
||||||
isDead or -- don't move dead NPCS
|
isDead or -- don't move dead NPCS
|
||||||
isHostile or --
|
isHostile or --
|
||||||
|
@ -166,8 +168,6 @@ this.isPublicHouse = function(cell)
|
||||||
if not this.isInteriorCell(cell) then return false end
|
if not this.isInteriorCell(cell) then return false end
|
||||||
|
|
||||||
-- gather some data about the cell
|
-- gather some data about the cell
|
||||||
local worth = cellEvaluators.calculateCellWorth(cell)
|
|
||||||
local faction = cellEvaluators.pickCellFaction(cell)
|
|
||||||
local typeOfPub = common.pickPublicHouseType(cell)
|
local typeOfPub = common.pickPublicHouseType(cell)
|
||||||
local city, publicHouseName
|
local city, publicHouseName
|
||||||
|
|
||||||
|
@ -187,7 +187,9 @@ this.isPublicHouse = function(cell)
|
||||||
|
|
||||||
-- if it's a waistworks cell, it's public, with no proprietor
|
-- if it's a waistworks cell, it's public, with no proprietor
|
||||||
if config.waistWorks == common.waist.public and cell.id:match(common.waistworks) then
|
if config.waistWorks == common.waist.public and cell.id:match(common.waistworks) then
|
||||||
dataTables.createPublicHouseTableEntry(cell, nil, city, publicHouseName, worth, faction)
|
dataTables.createPublicHouseTableEntry(cell, nil, city, publicHouseName,
|
||||||
|
cellEvaluators.calculateCellWorth(cell),
|
||||||
|
cellEvaluators.pickCellFaction(cell))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -199,7 +201,9 @@ this.isPublicHouse = function(cell)
|
||||||
log(common.logLevels.medium, "NPC:\'%s\' of class:\'%s\' made %s public", npc.object.name,
|
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)
|
npc.object.class and npc.object.class.id or "none", cell.name)
|
||||||
|
|
||||||
dataTables.createPublicHouseTableEntry(cell, npc, city, publicHouseName, worth, faction)
|
dataTables.createPublicHouseTableEntry(cell, npc, city, publicHouseName,
|
||||||
|
cellEvaluators.calculateCellWorth(cell),
|
||||||
|
cellEvaluators.pickCellFaction(cell))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -232,7 +236,9 @@ this.isPublicHouse = function(cell)
|
||||||
config.factionIgnorePercentage then
|
config.factionIgnorePercentage then
|
||||||
log(common.logLevels.medium, "%s is %s%% faction %s, marking public.", cell.name, info.percentage, faction)
|
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, worth, faction)
|
dataTables.createPublicHouseTableEntry(cell, npcs.factions[faction].master, city, publicHouseName,
|
||||||
|
cellEvaluators.calculateCellWorth(cell),
|
||||||
|
cellEvaluators.pickCellFaction(cell))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -281,17 +287,18 @@ end
|
||||||
|
|
||||||
-- AT NIGHT
|
-- AT NIGHT
|
||||||
this.checkTime = function()
|
this.checkTime = function()
|
||||||
log(common.logLevels.large, "Current time is %s, things are closed between %s and %s",
|
local night = tes3.worldController.hour.value >= config.closeTime or tes3.worldController.hour.value <= config.openTime
|
||||||
tes3.worldController.hour.value, config.closeTime, config.openTime)
|
log(common.logLevels.large, "Current time is %.2f (%snight), things are closed between %s and %s",
|
||||||
return tes3.worldController.hour.value >= config.closeTime or tes3.worldController.hour.value <= config.openTime
|
tes3.worldController.hour.value, night and "" or "not ", config.closeTime, config.openTime)
|
||||||
|
return night
|
||||||
end
|
end
|
||||||
|
|
||||||
-- inclement weather
|
-- inclement weather
|
||||||
this.checkWeather = function(cell)
|
this.checkWeather = function(cell)
|
||||||
if not cell.region then return end
|
if not cell.region then return end
|
||||||
|
|
||||||
log(common.logLevels.large, "Weather: %s >= %s == %s", cell.region.weather.index, config.worstWeather,
|
log(common.logLevels.large, "Weather: current:%s >= configured worst:%s == %s", cell.region.weather.index,
|
||||||
cell.region.weather.index >= config.worstWeather)
|
config.worstWeather, cell.region.weather.index >= config.worstWeather)
|
||||||
|
|
||||||
return cell.region.weather.index >= config.worstWeather
|
return cell.region.weather.index >= config.worstWeather
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, posit
|
||||||
if isHome and positions.npcs[npc.object.name] then
|
if isHome and positions.npcs[npc.object.name] then
|
||||||
pos = positions.npcs[npc.object.name].position
|
pos = positions.npcs[npc.object.name].position
|
||||||
ori = positions.npcs[npc.object.name].orientation
|
ori = positions.npcs[npc.object.name].orientation
|
||||||
elseif not table.empty(common.runtimeData.positions[id]) then
|
elseif common.runtimeData.positions[id] and not table.empty(common.runtimeData.positions[id]) then
|
||||||
-- pick a random position out of the positions in memory
|
-- pick a random position out of the positions in memory
|
||||||
local choice, index = table.choice(common.runtimeData.positions[id])
|
local choice, index = table.choice(common.runtimeData.positions[id])
|
||||||
pos = choice.position
|
pos = choice.position
|
||||||
|
@ -36,11 +36,11 @@ this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, posit
|
||||||
ori = {0, 0, 0}
|
ori = {0, 0, 0}
|
||||||
end
|
end
|
||||||
|
|
||||||
log(common.logLevels.large, "Settled on position:%s, orientation:%s for %s in %s", pos, ori, npc.object.name, id)
|
|
||||||
|
|
||||||
pickedPosition = tes3vector3.new(pos[1], pos[2], pos[3])
|
pickedPosition = tes3vector3.new(pos[1], pos[2], pos[3])
|
||||||
pickedOrientation = tes3vector3.new(ori[1], ori[2], ori[3])
|
pickedOrientation = tes3vector3.new(ori[1], ori[2], ori[3])
|
||||||
|
|
||||||
|
log(common.logLevels.large, "Settled on position:%s, orientation:%s for %s in %s", pickedPosition, pickedOrientation, npc.object.name, id)
|
||||||
|
|
||||||
local ogPosition = position and (tes3vector3.new(position.x, position.y, position.z)) or
|
local ogPosition = position and (tes3vector3.new(position.x, position.y, position.z)) or
|
||||||
(npc.position and npc.position:copy() or zeroVector:copy())
|
(npc.position and npc.position:copy() or zeroVector:copy())
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
-- handles evaluating NPCs
|
-- handles evaluating NPCs
|
||||||
local common = require("celediel.NPCsGoHome.common")
|
local common = require("celediel.NPCsGoHome.common")
|
||||||
|
local config = require("celediel.NPCsGoHome.config").getConfig()
|
||||||
|
|
||||||
local this = {}
|
local this = {}
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ this.calculateNPCWorth = function(npc, merchantCell)
|
||||||
-- calculate the total
|
-- calculate the total
|
||||||
local total = 0
|
local total = 0
|
||||||
for _, v in pairs(worth) do total = total + v end
|
for _, v in pairs(worth) do total = total + v end
|
||||||
|
log(common.logLevels.medium, "Calculated worth of %s for %s", total, npc.object.name)
|
||||||
|
|
||||||
-- then add it to the table
|
-- then add it to the table
|
||||||
worth.total = total
|
worth.total = total
|
||||||
|
|
|
@ -125,9 +125,6 @@ this.processNPCs = function(cell)
|
||||||
for npc in cell:iterateReferences(tes3.objectType.npc) do
|
for npc in cell:iterateReferences(tes3.objectType.npc) do
|
||||||
-- for npc, _ in pairs(cellsInMemory[cell].npcs) do
|
-- for npc, _ in pairs(cellsInMemory[cell].npcs) do
|
||||||
if not checks.isIgnoredNPC(npc) then
|
if not checks.isIgnoredNPC(npc) then
|
||||||
log(common.logLevels.large, "People change")
|
|
||||||
-- if not npc.data.NPCsGoHome then npc.data.NPCsGoHome = {} end
|
|
||||||
|
|
||||||
-- find NPC homes
|
-- find NPC homes
|
||||||
local npcHome = config.moveNPCs and housing.pickHomeForNPC(cell, npc) or nil
|
local npcHome = config.moveNPCs and housing.pickHomeForNPC(cell, npc) or nil
|
||||||
|
|
||||||
|
@ -163,8 +160,7 @@ this.processNPCs = function(cell)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now put NPCs back
|
-- now put NPCs back
|
||||||
-- if not (checks.checkTime() or checks.checkWeather(cell)) and #movedNPCs > 0 then putNPCsBack() end
|
if not (checks.checkTime() or checks.checkWeather(cell)) and #common.runtimeData.movedNPCs > 0 then this.putNPCsBack() end
|
||||||
if not (checks.checkTime() or checks.checkWeather(cell)) then this.putNPCsBack() end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
this.processSiltStriders = function(cell)
|
this.processSiltStriders = function(cell)
|
||||||
|
|
|
@ -16,7 +16,8 @@ local category = page:createCategory(common.modName)
|
||||||
|
|
||||||
category:createDropdown({
|
category:createDropdown({
|
||||||
label = "Debug log level",
|
label = "Debug log level",
|
||||||
description = [[Enable this if you want to flood mwse.log with nonsense. Even small is huge.]],
|
description = "Enable this if you want to flood mwse.log with nonsense. Even small is huge." ..
|
||||||
|
"Large in Old Ebonheart spits out 16k lines each update. Don't pick that option.",
|
||||||
options = {
|
options = {
|
||||||
{label = "None", value = common.logLevels.none},
|
{label = "None", value = common.logLevels.none},
|
||||||
{label = "Small", value = common.logLevels.small},
|
{label = "Small", value = common.logLevels.small},
|
||||||
|
|
Loading…
Reference in a new issue