rewrite with coroutines

This commit is contained in:
Lilian Jónsdóttir 2020-10-14 00:36:12 -07:00
parent 61deb36132
commit 1e4ccd6327

View file

@ -10,10 +10,51 @@ local function log(level, ...) if config.logLevel >= level then common.log(...)
local this = {} local this = {}
-- iterators
local function iterateNPCs(cell)
local function iterator()
for npc in cell:iterateReferences(tes3.objectType.npc) do
if not checks.isIgnoredNPC(npc) then
local keep = checks.isBadWeatherNPC(npc)
coroutine.yield(npc, keep)
end
end
end
return coroutine.wrap(iterator)
end
local function iterateSilts(cell)
local function iterator()
for activator in cell:iterateReferences(tes3.objectType.activator) do
if checks.isSiltStrider(activator) then coroutine.yield(activator) end
end
end
return coroutine.wrap(iterator)
end
local function iterateDoors(cell)
local function iterator()
for door in cell:iterateReferences(tes3.objectType.door) do
if not checks.isIgnoredDoor(door, cell.id) then coroutine.yield(door) end
end
end
return coroutine.wrap(iterator)
end
local function iteratePets(cell)
local function iterator()
for creature in cell:iterateReferences(tes3.objectType.creature) do
local isPet, linkedToTravel = checks.isNPCPet(creature)
if isPet then coroutine.yield(creature, linkedToTravel) end
end
end
return coroutine.wrap(iterator)
end
local function moveNPC(homeData) local function moveNPC(homeData)
-- do some logging -- do some logging
log(common.logLevels.medium, "[PROC] Moving %s to home %s (%s, %s, %s)", homeData.npc.object.name, homeData.home.id, log(common.logLevels.medium, "[PROC:NPCS] Moving %s to home %s (%s, %s, %s)", homeData.npc.object.name,
homeData.homePosition.x, homeData.homePosition.y, homeData.homePosition.z) homeData.home.id, homeData.homePosition.x, homeData.homePosition.y, homeData.homePosition.z)
local npc = homeData.npc local npc = homeData.npc
@ -46,7 +87,7 @@ end
local function disableNPC(npc, cell) local function disableNPC(npc, cell)
-- do some logging -- do some logging
log(common.logLevels.medium, "[PROC] Disabling un-homed %s", npc.name and npc.name or npc.id) log(common.logLevels.medium, "[PROC:NPCS] Disabling un-homed %s", npc.name and npc.name or npc.id)
-- add to runtimeData -- add to runtimeData
if checks.isBadWeatherNPC(npc) then if checks.isBadWeatherNPC(npc) then
common.runtimeData.NPCs.disabledBadWeather[cell.id] = common.runtimeData.NPCs.disabledBadWeather[cell.id] or {} common.runtimeData.NPCs.disabledBadWeather[cell.id] = common.runtimeData.NPCs.disabledBadWeather[cell.id] or {}
@ -64,12 +105,12 @@ local function disableNPC(npc, cell)
end end
local function putNPCsBack(npcData) local function putNPCsBack(npcData)
log(common.logLevels.large, "[PROC] Moving back NPCs:\n%s", common.inspect(npcData)) log(common.logLevels.medium, "[PROC:NPCS] Moving back NPCs:\n%s", common.inspect(npcData))
-- for i = #npcData, 1, -1 do -- for i = #npcData, 1, -1 do
for id, data in pairs(npcData) do for id, data in pairs(npcData) do
if data.npc.object then if data.npc.object then
-- local data = table.remove(npcData, i) -- local data = table.remove(npcData, i)
log(common.logLevels.medium, "[PROC] Moving %s back outside to %s (%s, %s, %s)", data.npc.object.name, log(common.logLevels.medium, "[PROC:NPCS] Moving %s back outside to %s (%s, %s, %s)", data.npc.object.name,
data.ogPlace.id, data.ogPosition.x, data.ogPosition.y, data.ogPosition.z) data.ogPlace.id, data.ogPosition.x, data.ogPosition.y, data.ogPosition.z)
-- unset NPC data so we don't try to move them on load -- unset NPC data so we don't try to move them on load
@ -92,9 +133,9 @@ local function putNPCsBack(npcData)
end end
local function reEnableNPCs(npcs) local function reEnableNPCs(npcs)
log(common.logLevels.large, "[PROC] Re-enabling NPCs:\n%s", common.inspect(npcs)) log(common.logLevels.medium, "[PROC:NPCS] Re-enabling NPCs:\n%s", common.inspect(npcs))
for id, ref in pairs(npcs) do for id, ref in pairs(npcs) do
log(common.logLevels.medium, "[PROC] Making attempt at re-enabling %s", id) log(common.logLevels.medium, "[PROC:NPCS] Making attempt at re-enabling %s", id)
if ref.object and ref.disabled then if ref.object and ref.disabled then
-- ref:enable() -- ref:enable()
@ -127,10 +168,10 @@ end
-- search in a specific cell for moved or disabled NPCs -- search in a specific cell for moved or disabled NPCs
local function checkForMovedOrDisabledNPCs(cell) local function checkForMovedOrDisabledNPCs(cell)
log(common.logLevels.medium, "[PROC] Looking for moved NPCs in cell %s", cell.id) log(common.logLevels.medium, "[PROC:NPCS] Looking for moved NPCs in cell %s", cell.id)
for npc in cell:iterateReferences(tes3.objectType.npc) do for npc in cell:iterateReferences(tes3.objectType.npc) do
if npc.data and npc.data.NPCsGoHome then if npc.data and npc.data.NPCsGoHome then
log(common.logLevels.large, "[PROC] %s has NPCsGoHome data, deciding if disabled or moved...%s", npc, log(common.logLevels.large, "[PROC:NPCS] %s has NPCsGoHome data, deciding if disabled or moved...%s", npc,
common.inspect(npc.data.NPCsGoHome)) common.inspect(npc.data.NPCsGoHome))
local badWeather = checks.isBadWeatherNPC(npc) local badWeather = checks.isBadWeatherNPC(npc)
if npc.data.NPCsGoHome.disabled then if npc.data.NPCsGoHome.disabled then
@ -199,27 +240,24 @@ this.searchCellsForPositions = function()
end end
this.processNPCs = function(cell) this.processNPCs = function(cell)
log(common.logLevels.small, "[PROC:NPCS] Looking for NPCs to process in cell:%s", cell.id)
local night = checks.isNight() local night = checks.isNight()
local badWeather = checks.isInclementWeather() local badWeather = checks.isInclementWeather()
log(common.logLevels.small, "[PROC] Looking for NPCs to process in cell:%s", cell.id)
if not cell.name and not config.disableNPCsInWilderness then if not cell.name and not config.disableNPCsInWilderness then
-- shitty way of implementing this config option and re-enabling NPCs when it gets turned off -- shitty way of implementing this config option and re-enabling NPCs when it gets turned off
-- but at least it's better than trying to keep track of NPCs that have been disabled in the wilderness -- but at least it's better than trying to keep track of NPCs that have been disabled in the wilderness
log(common.logLevels.medium, "[PROC] Shitty hack ACTIVATE! It's now not night, and the weather is great.") log(common.logLevels.medium, "[PROC:NPCS] Shitty hack ACTIVATE! It's now not night, and the weather is great.")
night = false night = false
badWeather = false badWeather = false
end end
if config.disableNPCs and badWeather and not night then if config.disableNPCs and badWeather and not night then
log(common.logLevels.large, "[PROC] !!Bad weather and not night!!") log(common.logLevels.large, "[PROC:NPCS] !!Bad weather and not night!!")
-- bad weather during the day, so disable some NPCs -- bad weather during the day, so disable some NPCs
for npc in cell:iterateReferences(tes3.objectType.npc) do for npc, keep in iterateNPCs(cell) do
if not checks.isIgnoredNPC(npc) then if not keep or not config.keepBadWeatherNPCs then disableOrMove(npc, cell) end
local keep = checks.isBadWeatherNPC(npc)
if not keep or not config.keepBadWeatherNPCs then disableOrMove(npc, cell) end
end
end end
-- LuaFormatter off -- LuaFormatter off
@ -229,13 +267,11 @@ this.processNPCs = function(cell)
if not common.isEmptyTable(common.runtimeData.NPCs.disabledBadWeather[cell.id]) then reEnableNPCs(common.runtimeData.NPCs.disabledBadWeather[cell.id]) end if not common.isEmptyTable(common.runtimeData.NPCs.disabledBadWeather[cell.id]) then reEnableNPCs(common.runtimeData.NPCs.disabledBadWeather[cell.id]) end
end end
elseif config.disableNPCs and night then elseif config.disableNPCs and night then
log(common.logLevels.large, "[PROC] !!Good or bad weather and night!!") log(common.logLevels.large, "[PROC:NPCS] !!Good or bad weather and night!!")
-- at night, weather doesn't matter, disable everyone -- at night, weather doesn't matter, disable everyone
for npc in cell:iterateReferences(tes3.objectType.npc) do for npc in iterateNPCs(cell) do if not npc.disabled then disableOrMove(npc, cell) end end
if not checks.isIgnoredNPC(npc) then disableOrMove(npc, cell) end
end
else else
log(common.logLevels.large, "[PROC] !!Good weather and not night!!") log(common.logLevels.large, "[PROC:NPCS] !!Good weather and not night!!")
-- put everyone back -- put everyone back
if not common.isEmptyTable(common.runtimeData.NPCs.moved[cell.id]) then putNPCsBack(common.runtimeData.NPCs.moved[cell.id]) end if not common.isEmptyTable(common.runtimeData.NPCs.moved[cell.id]) then putNPCsBack(common.runtimeData.NPCs.moved[cell.id]) end
if not common.isEmptyTable(common.runtimeData.NPCs.movedBadWeather[cell.id]) then putNPCsBack(common.runtimeData.NPCs.movedBadWeather[cell.id]) end if not common.isEmptyTable(common.runtimeData.NPCs.movedBadWeather[cell.id]) then putNPCsBack(common.runtimeData.NPCs.movedBadWeather[cell.id]) end
@ -245,100 +281,107 @@ this.processNPCs = function(cell)
end end
end end
-- todo: maybe deal with these like NPCs, adding to runtime data
-- todo: and setting ref.data.NPCsGoHome = {disabled = true}
-- todo: would have to check for them on load/cell change as well
-- todo: doors is already half done
this.processSiltStriders = function(cell) this.processSiltStriders = function(cell)
log(common.logLevels.small, "[PROC] Looking for silt striders to process in cell:%s", cell.id) log(common.logLevels.small, "[PROC:SILT] Looking for silt striders to process in cell:%s", cell.id)
for activator in cell:iterateReferences(tes3.objectType.activator) do
if checks.isSiltStrider(activator) then local night = checks.isNight()
if config.disableNPCs and (checks.isNight() or (checks.isInclementWeather() and not config.keepBadWeatherNPCs)) then local badWeather = checks.isInclementWeather()
if not activator.disabled then
log(common.logLevels.medium, "[PROC] Disabling silt strider %s!", activator.object.name) -- I don't think there are any silt striders in Region cells so not bothering with config.disableNPCsInWilderness
mwscript.disable({reference = activator})
-- activator:disable() if config.disableNPCs and (night or (badWeather and not config.keepBadWeatherNPCs)) then
-- tes3.setEnabled({reference = activator, enabled = false}) -- disable
end for silt in iterateSilts(cell) do
else log(common.logLevels.medium, "[PROC:SILT] Disabling silt strider %s!", silt.object.name)
if activator.disabled then mwscript.disable({reference = silt})
log(common.logLevels.medium, "[PROC] Enabling silt strider %s!", activator.object.name) end
mwscript.enable({reference = activator}) else
-- activator:enable() -- re-enable
-- tes3.setEnabled({reference = activator, enabled = true}) for silt in iterateSilts(cell) do
end log(common.logLevels.medium, "[PROC:SILT] Enabling silt strider %s!", silt.object.name)
end mwscript.enable({reference = silt})
end end
end end
log(common.logLevels.large, "[PROC] Done with silt striders") log(common.logLevels.large, "[PROC:SILT] Done with silt striders")
end end
-- todo: maybe rewrite this one like processNPCs() too
-- deal with trader's guars, and other npc linked creatures/whatever -- deal with trader's guars, and other npc linked creatures/whatever
this.processPets = function(cell) this.processPets = function(cell)
local night = checks.isNight() local night = checks.isNight()
local badWeather = checks.isInclementWeather() local badWeather = checks.isInclementWeather()
log(common.logLevels.small, "[PROC] Looking for NPC pets to process in cell:%s", cell.id) log(common.logLevels.small, "[PROC:PETS] Looking for NPC pets to process in cell:%s", cell.id)
for creature in cell:iterateReferences(tes3.objectType.creature) do -- for creature in cell:iterateReferences(tes3.objectType.creature) do
local isPet, linkedToTravel = checks.isNPCPet(creature) for pet, linkedToTravel in iteratePets(cell) do
if isPet then -- this is becoming too much lol
-- this is becoming too much lol if config.disableNPCs and
if config.disableNPCs and (night or (badWeather and (not linkedToTravel or (linkedToTravel and not config.keepBadWeatherNPCs)))) then (night or (badWeather and (not linkedToTravel or (linkedToTravel and not config.keepBadWeatherNPCs)))) then
-- disable -- disable
if not creature.disabled then if not pet.disabled then
log(common.logLevels.medium, "[PROC] Disabling NPC Pet %s!", creature.object.id) log(common.logLevels.medium, "[PROC:PETS] Disabling NPC Pet %s!", pet.object.id)
mwscript.disable({reference = creature}) mwscript.disable({reference = pet})
end end
else else
-- enable -- enable
if creature.disabled then if pet.disabled then
log(common.logLevels.medium, "[PROC] Enabling NPC Pet %s!", creature.object.id) log(common.logLevels.medium, "[PROC:PETS] Enabling NPC Pet %s!", pet.object.id)
mwscript.enable({reference = creature}) mwscript.enable({reference = pet})
end
end end
end end
end end
end end
this.processDoors = function(cell) this.processDoors = function(cell)
log(common.logLevels.small, "[PROC:DOOR] Looking for doors to process in cell:%s", cell.id)
local night = checks.isNight() local night = checks.isNight()
log(common.logLevels.small, "[PROC] Looking for doors to process in cell:%s", cell.id) if config.lockDoors and night then
-- lock
for door in cell:iterateReferences(tes3.objectType.door) do for door in iterateDoors(cell) do
if not door.data.NPCsGoHome then door.data.NPCsGoHome = {} end if not door.data.NPCsGoHome then door.data.NPCsGoHome = {} end
if not checks.isIgnoredDoor(door, cell.id) then
-- don't mess around with doors that are already locked -- don't mess around with doors that are already locked
if door.data.NPCsGoHome.alreadyLocked == nil then if door.data.NPCsGoHome.alreadyLocked == nil then -- the one time I specifically don't want to use [ if not thing ]
door.data.NPCsGoHome.alreadyLocked = tes3.getLocked({reference = door}) door.data.NPCsGoHome.alreadyLocked = tes3.getLocked({reference = door})
end end
log(common.logLevels.large, "[PROC] Found %slocked %s with destination %s", log(common.logLevels.large, "[PROC:DOOR] Found %slocked %s with destination %s",
door.data.NPCsGoHome.alreadyLocked and "" or "un", door.id, door.destination.cell.id) door.data.NPCsGoHome.alreadyLocked and "" or "un", door.id, door.destination.cell.id)
if config.lockDoors and night then -- it's not a door that's already locked or one we've already touched, so lock it
if not door.data.NPCsGoHome.alreadyLocked then if not door.data.NPCsGoHome.alreadyLocked and not door.data.NPCsGoHome.modified then
log(common.logLevels.medium, "[PROC] Locking: %s to %s", door.object.name, door.destination.cell.id) log(common.logLevels.medium, "[PROC:DOOR] Locking: %s to %s", door.object.name, door.destination.cell.id)
local lockLevel = math.random(25, 100) -- todo: pick this better
tes3.lock({reference = door, level = lockLevel}) local lockLevel = math.random(25, 100)
door.data.NPCsGoHome.modified = true tes3.lock({reference = door, level = lockLevel})
end door.data.NPCsGoHome.modified = true
else
-- only unlock doors that we locked before
if door.data.NPCsGoHome.modified then
door.data.NPCsGoHome.modified = false
tes3.setLockLevel({reference = door, level = 0})
tes3.unlock({reference = door})
log(common.logLevels.medium, "[PROC] Unlocking: %s to %s", door.object.name,
door.destination.cell.id)
end
end end
log(common.logLevels.large, "[PROC] Now locked Status: %s", tes3.getLocked({reference = door})) log(common.logLevels.large, "[PROC:DOOR] Now locked Status: %s", tes3.getLocked({reference = door}))
end
else
-- unlock
for door in cell:iterateReferences(tes3.objectType.door) do
-- only unlock doors that we locked before
if door.data.NPCsGoHome and door.data.NPCsGoHome.modified then
door.data.NPCsGoHome.modified = false
tes3.setLockLevel({reference = door, level = 0})
tes3.unlock({reference = door})
log(common.logLevels.medium, "[PROC:DOOR] Unlocking: %s to %s", door.object.name,
door.destination.cell.id)
end
end end
end end
log(common.logLevels.large, "[PROC] Done with doors") log(common.logLevels.large, "[PROC:DOOR] Done with doors")
end end
return this return this