From ec2a570b3077955278e3237c0c8d5cd3ab3ef044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lilian=20J=C3=B3nsd=C3=B3ttir?= Date: Sun, 23 Aug 2020 23:54:58 -0700 Subject: [PATCH] don't move multiple NPCs into the same spot --- MWSE/mods/celediel/NPCsGoHome/common.lua | 18 +++++++++ .../NPCsGoHome/functions/dataTables.lua | 39 ++++++------------- .../celediel/NPCsGoHome/functions/housing.lua | 23 ++++++----- .../NPCsGoHome/functions/processors.lua | 29 ++++++++++++++ MWSE/mods/celediel/NPCsGoHome/main.lua | 1 + readme.md | 8 +++- 6 files changed, 77 insertions(+), 41 deletions(-) diff --git a/MWSE/mods/celediel/NPCsGoHome/common.lua b/MWSE/mods/celediel/NPCsGoHome/common.lua index d6cc12c..c091b04 100644 --- a/MWSE/mods/celediel/NPCsGoHome/common.lua +++ b/MWSE/mods/celediel/NPCsGoHome/common.lua @@ -29,6 +29,8 @@ this.runtimeData = { }, -- NPCs who have been moved movedNPCs = {}, + -- positions that haven't been used + positions = {}, -- player companions followers = {} } @@ -73,6 +75,22 @@ this.pickPublicHouseType = function(cell) return this.publicHouseTypes.inns end end + +this.checkModdedCell = function(cellId) + local id + + if cellId == "Balmora, South Wall Cornerclub" and tes3.isModActive("South Wall.ESP") then + id = "Balmora, South Wall Den Of Iniquity" + elseif cellId == "Balmora, Eight Plates" and tes3.isModActive("Eight Plates.esp") then + id = "Balmora, Seedy Eight Plates" + elseif cellId == "Hla Oad, Fatleg's Drop Off" and tes3.isModActive("Clean DR115_TheDropoff_HlaOadDocks.ESP") then + id = "Hla Oad, The Drop Off" + else + id = cellId + end + + return id +end -- }}} return this diff --git a/MWSE/mods/celediel/NPCsGoHome/functions/dataTables.lua b/MWSE/mods/celediel/NPCsGoHome/functions/dataTables.lua index e0f7bce..ea6afcb 100644 --- a/MWSE/mods/celediel/NPCsGoHome/functions/dataTables.lua +++ b/MWSE/mods/celediel/NPCsGoHome/functions/dataTables.lua @@ -37,29 +37,13 @@ end -- }}} -this.checkModdedCell = function(cellId) - local id - - if cellId == "Balmora, South Wall Cornerclub" and tes3.isModActive("South Wall.ESP") then - id = "Balmora, South Wall Den Of Iniquity" - elseif cellId == "Balmora, Eight Plates" and tes3.isModActive("Eight Plates.esp") then - id = "Balmora, Seedy Eight Plates" - elseif cellId == "Hla Oad, Fatleg's Drop Off" and tes3.isModActive("Clean DR115_TheDropoff_HlaOadDocks.ESP") then - id = "Hla Oad, The Drop Off" - else - id = cellId - end - - return id -end - 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 = this.checkModdedCell(home.id) + 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) @@ -67,22 +51,21 @@ this.createHomedNPCTableEntry = function(npc, home, startingPlace, isHome, posit if isHome and positions.npcs[npc.object.name] then pos = positions.npcs[npc.object.name].position ori = positions.npcs[npc.object.name].orientation - -- pickedPosition = positions.npcs[npc.object.name] and tes3vector3.new(p[1], p[2], p[3]) or zeroVector:copy() - -- pickedOrientation = positions.npcs[npc.object.name] and tes3vector3.new(o[1], o[2], o[3]) or zeroVector:copy() - elseif positions.cells[id] then - pos = table.choice(positions.cells[id]).position - ori = table.choice(positions.cells[id]).orientation - -- pickedPosition = positions.cells[id] and tes3vector3.new(p[1], p[2], p[3]) or zeroVector:copy() - -- pickedOrientation = positions.cells[id] and tes3vector3.new(o[1], o[2], o[3]) or zeroVector:copy() - -- pickedPosition = tes3vector3.new(p[1], p[2], p[3]) - -- pickedOrientation = tes3vector3.new(o[1], o[2], o[3]) + -- elseif positions.cells[id] then + elseif common.runtimeData.positions[id] then + -- pos = table.choice(positions.cells[id]).position + -- ori = table.choice(positions.cells[id]).orientation + local choice, index = table.choice(common.runtimeData.positions[id]) + pos = choice.position + ori = choice.orientation + table.remove(common.runtimeData.positions[id], index) else pos = {0,0,0} ori = {0,0,0} - -- pickedPosition = zeroVector:copy() - -- pickedOrientation = zeroVector:copy() 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]) pickedOrientation = tes3vector3.new(ori[1], ori[2], ori[3]) diff --git a/MWSE/mods/celediel/NPCsGoHome/functions/housing.lua b/MWSE/mods/celediel/NPCsGoHome/functions/housing.lua index 8db26d0..2ec62f8 100644 --- a/MWSE/mods/celediel/NPCsGoHome/functions/housing.lua +++ b/MWSE/mods/celediel/NPCsGoHome/functions/housing.lua @@ -45,7 +45,8 @@ end this.pickPublicHouseForNPC = function(npc, city) -- look for wandering guild members - if common.runtimeData.publicHouses[city] and common.runtimeData.publicHouses[city][common.publicHouseTypes.guildhalls] then + if common.runtimeData.publicHouses[city] and + common.runtimeData.publicHouses[city][common.publicHouseTypes.guildhalls] then for _, data in pairs(common.runtimeData.publicHouses[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 @@ -78,8 +79,6 @@ this.pickHomeForNPC = function(cell, npc) for _, str in pairs(contextualNPCs) do if npc.object.id:match(str) then return end end -- time to pick the "home" - local picked = nil - local name = npc.object.name local city = common.split(cell.name, ",")[1] for door in cell:iterateReferences(tes3.objectType.door) do @@ -88,11 +87,9 @@ this.pickHomeForNPC = function(cell, npc) -- essentially, if npc full name, or surname matches the cell name if dest.id:match(name) or this.livesInManor(dest.name, name) then - if common.runtimeData.homes.byName[name] then -- already have a home, don't create the table dataTables again - picked = common.runtimeData.homes.byName[name] - else - picked = dataTables.createHomedNPCTableEntry(npc, dest, cell, true) - end + -- already have a home, don't create the table dataTables again + return common.runtimeData.homes.byName[name] and common.runtimeData.homes.byName[name] or + dataTables.createHomedNPCTableEntry(npc, dest, cell, true) end end end @@ -102,21 +99,23 @@ this.pickHomeForNPC = function(cell, npc) log(common.logLevels.medium, "Didn't find a home for %s, trying inns", npc.object.name) local dest = this.pickPublicHouseForNPC(npc, city) - if dest then picked = dataTables.createHomedNPCTableEntry(npc, dest, cell, false) end + 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.runtimeData.publicHouses[city] and common.runtimeData.publicHouses[city][common.publicHouseTypes.cantonworks] 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) - if canton then picked = dataTables.createHomedNPCTableEntry(npc, canton.cell, cell, false) end + if canton then return dataTables.createHomedNPCTableEntry(npc, canton.cell, cell, false) end end end end - return picked + -- didn't find anything + return nil end return this diff --git a/MWSE/mods/celediel/NPCsGoHome/functions/processors.lua b/MWSE/mods/celediel/NPCsGoHome/functions/processors.lua index 788c9dc..379dddb 100644 --- a/MWSE/mods/celediel/NPCsGoHome/functions/processors.lua +++ b/MWSE/mods/celediel/NPCsGoHome/functions/processors.lua @@ -5,11 +5,40 @@ local checks = require("celediel.NPCsGoHome.functions.checks") local interop = require("celediel.NPCsGoHome.interop") local housing = require("celediel.NPCsGoHome.functions.housing") local dataTables = require("celediel.NPCsGoHome.functions.dataTables") +local positions = require("celediel.NPCsGoHome.data.positions") local function log(level, ...) if config.logLevel >= level then common.log(...) end end local this = {} +this.updatePositions = function(cell) + local id = cell.id + -- update runtime positions in cell, but don't overwrite loaded positions + if not common.runtimeData.positions[id] and positions.cells[id] then + common.runtimeData.positions[id] = {} + for _, data in pairs(positions.cells[id]) do + table.insert(common.runtimeData.positions[id], data) + end + end +end + +this.searchCellsForPositions = function() + for _, cell in pairs(tes3.getActiveCells()) do + -- check active cells + this.updatePositions(cell) + for door in cell:iterateReferences(tes3.objectType.door) do + if door.destination then + -- then check cells attached to active cells + this.updatePositions(door.destination.cell) + -- one more time + for internalDoor in door.destination.cell:iterateReferences(tes3.objectType.door) do + if internalDoor.destination then this.updatePositions(internalDoor.destination.cell) end + end + end + end + end +end + -- search in a specific cell for moved NPCs this.checkForMovedNPCs = function(cell) -- NPCs don't get moved to exterior cells, so no need to check them for moved NPCs diff --git a/MWSE/mods/celediel/NPCsGoHome/main.lua b/MWSE/mods/celediel/NPCsGoHome/main.lua index e46bedc..4ff78c0 100644 --- a/MWSE/mods/celediel/NPCsGoHome/main.lua +++ b/MWSE/mods/celediel/NPCsGoHome/main.lua @@ -91,6 +91,7 @@ local function updateCells() log(common.logLevels.medium, "Updating active cells!") followers = buildFollowerList() + processors.searchCellsForPositions() for _, cell in pairs(tes3.getActiveCells()) do log(common.logLevels.large, "Applying changes to cell %s", cell.id) diff --git a/readme.md b/readme.md index 9502ec2..5a8a444 100644 --- a/readme.md +++ b/readme.md @@ -16,6 +16,7 @@ ignored class or faction will not be locked, or have its NPCS disabled. * NPC "homes" * Outside NPCs who have homes are currently paired with the inside cell of their home * Other NPCs are configurably paired with local public houses (Inns, temples, and guildhalls of their faction) +* Moved NPCs persist on save/load ## WIP ## @@ -28,4 +29,9 @@ ignored class or faction will not be locked, or have its NPCS disabled. ## TODO ## * move non-faction NPCs who don't have homes to temples or inns based on their "worth" -* pick temple for the poorest NPCs, or classed inns based on NPC/inn "worth" \ No newline at end of file +* pick temple for the poorest NPCs, or classed inns based on NPC/inn "worth" + +## Known issues ## + +* If NPCs in a town are moved, and the player moves far away from that town before they're moved back, then +saves and reloads, those NPCs will probably stay moved. \ No newline at end of file