-------------------------------------------------------------- -- L_KILL_COUNTER_UTIL.lua -- Intermediary utility script for objects -- Maintains an internal counter limited either by user definition, or associated network -- max spawns. -- Processes counter events sent through external sources, or received via -- personal notification subscriptions. -- Initiates event firing to user defined target group/functions based on counter state. -- Created abeechler... 9/20/11 ------------------------------------------------------------- ------------------------------------------------------------- --- config data variables for HF; defaults listed. ** if nothing is set the counter defaults to counting from 0 to x --- where 'x' is the max number of objects spawned throughout all associated networks ** -- max --> 1:x -- the upper clamped limit the counter will increment to -- min --> 1:0 -- the initial point for the counter to increment from --- associated spawn networks --- NOTE: you can include as many networks as you wish, HOWEVER the references MUST be numbered SEQUENTIALLY --- (i.e. - spawnNw1, spawnNw2, spawnNw3, etc.) to be counted properly -- spawnNw1 --> 0:networkName -- string reference to a spawner network name -- spawnNw2 --> 0:networkName -- another network -- ... -- ... -- spawnNwX --> 0:networkName -- the last in a sequential reference list of desired spawner networks --- notification subsciption management -- bManageNotifies --> 7:true/false -- whether or not the counter should manage spawn network notifies automatically -- -- (set to true by default) -- bAutoStop --> 7:true/false -- should we auto stop (unsubscribe) notification upon reching the max? -- --- fire events -- maxHit_event --> 0:event1 -- event name to fire when the couter reaches the upper limit -- maxHit_group --> 0:group1 -- desired object group maxHit_event is fired on -- minHit_event --> 0:event2 -- event name to fire when the counter reaches the lower limit -- minHit_group --> 0:group2 -- desired object group minHit_event is fired on --- types of events: this is set on the object configData in HF for the receiving the event. ---- -- FORMAT: this is for the name_activated_event sent to the group_activated_event from above -- event1 --> 0:activate ---- -- increment -- use this variable name to increment the count -- decrement -- use this variable name to decrement the count ------------------------------------------------------------- local defaultCounterMin = 0 -- Signifies where the counter should start incrementing from ---------------------------------------------------------------- -- Object functionality initialization ---------------------------------------------------------------- function onStartup(self) -- Init the counter at either a default base value, -- or a value read in from the object config data local cntMin = self:GetVar('min') or defaultCounterMin self:SetVar("min", cntMin) self:SetVar("counter", cntMin) -- Build a table containing reference to all config data -- associated spawn networks local spawnNetworkTable = {} local cnt = 1 local networkBuf = self:GetVar("spawnNw" .. cnt) while(networkBuf ~= nil) do -- Append the current found spawner network table.insert(spawnNetworkTable, networkBuf) -- Increment our count cnt = cnt + 1 -- Obtain the next sequential network networkBuf = self:GetVar("spawnNw" .. cnt) end -- Save the results self:SetVar("spawnNetworkTable", spawnNetworkTable) -- Establish the counter upper limit, either through read in -- object config data, or in its absence through associated -- spawner network max spawns local cntMax = self:GetVar('max') if(cntMax == nil) then -- We do not have an explicit user defined limit, -- obtain one based on associated spawn networks if(table.maxn(spawnNetworkTable) > 0)then local cntTally = 0 -- Iterate through the networks and accumulate their spawn limits for i, spawnerNom in ipairs(spawnNetworkTable) do -- Get a ref to the network by name local spawner = LEVEL:GetSpawnerByName(spawnerNom) if((spawner) and (spawner:Exists())) then local spawnLimit = spawner:SpawnerGetMaxToSpawn().iNum -- Confirm it is not an unlimited spawner, and add to accumulation if(spawnLimit ~= -1) then cntTally = cntTally + spawnLimit end end end -- If we have a count tally that remains zero at this point, the user has supplied -- solely infinite spawning networks - alert them to possibility. if(cntTally == 0) then cntMax = 1 errorReport(self, 3) else -- Set our accumulated network max limit cntMax = cntTally end self:SetVar("max", cntMax) else -- We were not given an explicit limit, and the -- user does not have associated spawn networks - -- set a simple default limit, and alert to the potential error cntMax = 1 self:SetVar("max", cntMax) errorReport(self, 1) end else -- The user has defined a config data max limit self:SetVar("max", cntMax) end -- If bManageNotifies is set to true - iterate through the -- associated networks, grab hooks to each network, -- and subscribe for event notification on each local bManageNotifies = self:GetVar("bManageNotifies") if((bManageNotifies ~= nil) and (bManageNotifies == false)) then return end if(table.maxn(spawnNetworkTable) > 0)then spawnerNotifies(self, true) else -- We were not provided any associated networks for -- object notification, alert the user to the potential error errorReport(self, 2) end end ---------------------------------------------------------------- -- Handle spawner notification subscription and cancellation ---------------------------------------------------------------- function spawnerNotifies(self, bSubscribe) local spawnNetworkTable = self:GetVar("spawnNetworkTable") -- Iterate through the networks and subscribe for notifies on their elements for i, spawnerNom in ipairs(spawnNetworkTable) do -- Get a ref to the network by name local spawner = LEVEL:GetSpawnerByName(spawnerNom) if((spawner) and (spawner:Exists())) then if(bSubscribe) then -- Receive notification of death self:SendLuaNotificationRequest{requestTarget = spawner, messageName = "NotifySpawnerOfDeath"} else -- Cancel death notifies self:SendLuaNotificationCancel{requestTarget = spawner, messageName = "NotifySpawnerOfDeath"} end end end end ---------------------------------------------------------------- -- Process event calls to this counter object ---------------------------------------------------------------- function onFireEvent(self, msg) --- types of events: this is set on the object configData in HF for the receiving the event. ---- -- FORMAT: this is for the name_activated_event sent to the group_activated_event from above -- event1 --> 0:activate ---- -- increment -- use this variable name to increment the count -- decrement -- use this variable name to decrement the count -- stopNotifies -- unsubscribe from current spawn network notifies -- startNotifies -- subscribe to notifications for config data referenced spawner networks -- reset -- forces the kill counter back to 0 local eventType = self:GetVar(msg.args) if not eventType then return end if((eventType == "increment") or (eventType == "decrement")) then modifyCounter(self, eventType) elseif(eventType == "stopNotifies") then spawnerNotifies(self, false) elseif(eventType == "startNotifies") then spawnerNotifies(self, true) elseif(eventType == "reset") then resetCounter(self) end end ---------------------------------------------------------------- -- Reset the kill counter to an entry state ---------------------------------------------------------------- function resetCounter(self) -- Obtain the minimum counter value and reset out counter to it local cntMin = self:GetVar('min') self:SetVar("counter", cntMin) -- If we were set to manage notifies, ensure we are doing it again local spawnNetworkTable = self:GetVar("spawnNetworkTable") local bManageNotifies = self:GetVar("bManageNotifies") if((bManageNotifies ~= nil) and (bManageNotifies == false)) then spawnerNotifies(self, false) return end if(table.maxn(spawnNetworkTable) > 0)then spawnerNotifies(self, true) else -- We were not provided any associated networks for -- object notification, alert the user to the potential error errorReport(self, 2) end end ---------------------------------------------------------------- -- Actual parsing of counter modification events ---------------------------------------------------------------- function modifyCounter(self, modType) local counter = self:GetVar("counter") local cntMax = self:GetVar("max") if modType == "increment" then -- Increment the counter and limit check. counter = counter + 1 if counter == cntMax then sendEvent(self, true) processEvent(self, true) -- If bAutoShutoff is set to FALSE, keep operations local bAutoShutoff = self:GetVar("bAutoShutoff") if((bAutoShutoff ~= nil) and (bAutoShutoff == false)) then return end spawnerNotifies(self, false) elseif counter > cntMax then return end -- Set the counter self:SetVar("counter", counter) elseif modType == "decrement" then -- Decrement the counter counter = counter - 1 local cntMin = self:GetVar("min") if counter == cntMin then sendEvent(self, false) processEvent(self, false) elseif counter < cntMin then return end -- Set the counter self:SetVar("counter", counter) end end ---------------------------------------------------------------- -- Catch subscribed spawner loads ---------------------------------------------------------------- function notifyNotifySpawnerOfDeath(self, spawnerID, msg) -- Increment our kill counter modifyCounter(self, "increment") end ---------------------------------------------------------------- -- Initiate a call to user defined objects ---------------------------------------------------------------- function sendEvent(self, bUpperLimitReached) local eventName = false local eventGroup = false if bUpperLimitReached then eventName = self:GetVar("maxHit_event") or false eventGroup = self:GetVar("maxHit_group") or false else eventName = self:GetVar("minHit_event") or false eventGroup = self:GetVar("minHit_group") or false end if not eventName or not eventGroup then return end debugPrint(self, 'name = ' .. eventName .. " group = " .. eventGroup) local groupObjs = self:GetObjectsInGroup{group = eventGroup, ignoreSpawners = true}.objects for k,obj in ipairs(groupObjs) do if obj:Exists() then obj:FireEvent{args = eventName, senderID = self} end end end ---------------------------------------------------------------- -- Enable an object extending kill counter functionality to -- process limit events ---------------------------------------------------------------- function processEvent(self, bUpperLimitReached) -- Generic counters don't process events: -- This is a template objects inheriting counter functionality -- can uniquely define in order ro accomplish specific tasks end ---------------------------------------------------------------- -- User error reporting utility function ---------------------------------------------------------------- function errorReport(self, iErrState) -- Our location local loc = self:GetPosition().pos -- Process iErrState for specific notification string local errString = "possible error found at loc: (" if(iErrState == 1) then -- We were not given an explicit limit, and the -- user does not have associated spawn networks errString = "there is a counter without a defined max limit AND without spawner network refs at loc: (" elseif(iErrState == 2) then -- We were not provided any associated networks for object notification errString = "there is a counter without spawn network refs with bManageNotifies set to TRUE at loc: (" elseif(iErrState == 3) then -- We are relying on the spawn network limits to set our max, and were only -- provided infinite networks. errString = "there is a counter trying to process a max value based only on infinite spawn networks at loc: (" end debugPrint(self, "***** L_KILL_COUNTER WARNING: " .. errString .. tostring(loc.x) .. ", " .. tostring(loc.y) .. ", " .. tostring(loc.z) .. ")") end ---------------------------------------------------------------- -- Print function that only works in an internal build ---------------------------------------------------------------- function debugPrint(self, text) if self:GetVersioningInfo().bIsInternal then print(text) end end