-------------------------------------------------------------- -- Server side base Script for aura mar, handles the randomized spawning -- -- created by mrb... 11/5/10 -- edited by brandi.. 12/13/10 - split the single script into a base script and one script for each section -- updated by abeechler ... 8/31/11 - added proper clamped network resets when attempting to pulse the named enemy spawner -------------------------------------------------------------- require('02_server/Map/AM/L_NAMED_ENEMY_SPAWNER') -- local constants local mobDeathResetNumber = 0 -- how many mobs need to die in a section before a new load is picked local zonePrefix = "em" -- start of the spanwer name string local zoneNameConst = 2 -- Do Not Change: constant for the location of the zoneName when split(spawnerName, "_") is called local sectionIDConst = 3 -- Do Not Change: constant for the location of the sectionID when split(spawnerName, "_") is called local zoneName = "" -- zone name sent from volume script local zones = {} -- sets of enemies sent from volume script local eventsToCheck = {} -- sets of event specific spawn sets of enemies sent from volume script local sectionMultipliers = {} -- section mulitpliers sent from volume script local changeNum = 0 -- number of player in the volume to change the max spawn number sent from volume script local mobs = {} local respawnTime = 80 -- respawn timer on the enemies --============================================================ --============================================================ function setGameVariables(passedsets, passedevents, passedzoneName,passedsectionMultipliers,passedchangeNum,passedmobDeathResetNumber,passedmobs) zones = passedsets eventsToCheck = passedevents zoneName = passedzoneName sectionMultipliers = passedsectionMultipliers changeNum = passedchangeNum mobDeathResetNumber = passedmobDeathResetNumber mobs = passedmobs end -- print function that only works in an internal build function debugPrint(self, text) if self:GetVersioningInfo().bIsInternal then print(text) end end -- splits a string based on the pattern passed in function split(str, pat) local t = {} -- splits a string based on the given pattern and returns a table string.gsub(str .. pat, "(.-)" .. pat, function(result) table.insert(t, result) end) return t end function baseStartup(self, msg) -- variable to keep track of the players in the volume self:SetVar("TotalPlayers", 0) -- variable to keep track of the state of enemies spawn, min for less spawned, max for more spawned self:SetVar("SpawnState", "min") -- variable for when the spawn number changed to set a delay so it doesnt keep spawning again self:SetVar("JustChanged", false) math.randomseed( os.time() ) -- check if an event is happening and set the zones table correctly checkEvents(self) -- set and activate the initial spawnerNetworks for the map spawnMapZones(self) end ---------------------------------------------------------------- -- Custom function: checks holliday events and sets the zones table if one is valid ---------------------------------------------------------------- function checkEvents(self) -- loop through the eventsToCheck table, if the event is active than use the alternate zones table for that event. for event,eventZoneTable in pairs(eventsToCheck) do if self:GetHolidayEvent{eventToCheck = event}.isValid then -- we found a valid event so set the zones table and return zones = eventZoneTable return end end end ---------------------------------------------------------------- -- Custom function: Sets up all the sections in the map to spawn ---------------------------------------------------------------- function spawnMapZones(self) -- spawn the mobs on the spawners based on the sectionName for sectionID, iMultiplier in pairs(sectionMultipliers) do local sectionName = zonePrefix .. "_" .. zoneName .. "_" .. sectionID -- spawn section spawnSection(self, sectionName, iMultiplier) end -- the start area volume controls the Named enemy spawners if zoneName == "str" then -- spawn named enemy SpawnNamedEnemy(self) end -- we have finished initializing the map so set bInit to true self:SetVar("bInit", true) end ---------------------------------------------------------------- -- Custom function: Sets up a section in the map to spawn ---------------------------------------------------------------- function spawnSection(self, sectionName, iMultiplier) -- get a random load from the zones table based on the sectionName local spawnLoad = getRandomLoad(self, sectionName) -- if we dont find a load the return if not spawnLoad then return end -- loop through the spawn load and set and spawn each spawner network for k, spawnerData in ipairs(spawnLoad) do if spawnerData.name then -- get the number of mobs to maintain and adjust based on the multiplier, rounded down local spawnNum = math.floor(spawnerData.num * iMultiplier) -- concat the spawner network name local spawnerName = sectionName .. "_" .. spawnerData.name -- set up the spawner network setSpawnerNetwork(self, spawnerName, spawnNum, spawnerData.LOT) end end end ---------------------------------------------------------------- -- Custom function: Spawns mobs on a spawner network, Now... ---------------------------------------------------------------- function setSpawnerNetwork(self, spawnerName, spawnNum, spawnLOT) -- get the spawner object local spawner = LEVEL:GetSpawnerByName(spawnerName) -- check to see if the script is trying to spawn more than 1 gorilla, and dont let it if spawnLOT == 11217 and spawnNum > 1 then spawnNum = 1 end -- if we have a spawner object lets set it up if spawner then -- set the LOT to spawn if it's sent to the function if spawnLOT then spawner:SpawnerSetSpawnTemplateID{iObjTemplate = spawnLOT} spawner:SpawnerSetRespawnTime{ fTime = respawnTime } end -- set the number of LOT's to spawn if it's sent to the function if spawnNum then spawner:SpawnerSetNumToMaintain{uiNum = spawnNum} --print("FROM SCRIPT: the number set to spawn is "..spawnNum.." and the lot is "..spawnLOT.." and the number of nodes on the spawner is "..spawner:SpawnerGetNumNodes().uiNum.." on spawner network "..spawnerName.." the number set to maintain is "..spawner:SpawnerGetNumToMaintain().uiNum) end -- we are setting to pulse a spawner network with a clamped -- max spawn and need to reset it if spawnerName == "Named_Enemies" then spawner:SpawnerReset() end spawner:SpawnerActivate() -- if we are still initializing the map then set a Lua Notification for when a mob dies on this spawner network if not self:GetVar("bInit") then self:SendLuaNotificationRequest{requestTarget = spawner, messageName = "NotifySpawnerOfDeath"} end end end ---------------------------------------------------------------- -- Custom function: Returns a random spawn set from the zones table or false ---------------------------------------------------------------- function getRandomLoad(self, sectionName) -- get the zoneName and sectioinID from the section name string local zoneInfo = split(sectionName, "_") -- set the get the section load table from the zones table local sectionData = zones -- set the variables for the random weight system local weightTable = {} local totalWeight = 0 -- create a table based on the sectionData weights, incrementing the weights for k,load in ipairs(sectionData) do totalWeight = totalWeight + load.iChance table.insert(weightTable, totalWeight) end -- get a random number based on the totalWeight and divide it by totalWeight local randWeight = math.random(0,totalWeight) -- loop through the section load table and find the right load to use based on the randWeight for k,weight in ipairs(weightTable) do if randWeight <= weight then local randLoad = zones[k] --debugPrint(self, '** Spawning: ' .. sectionName .. ' using: ' .. k) --debugPrint(self, "randWeight = " .. randWeight .. " -> weight = ".. weight) if randLoad then return randLoad end end end return false end function notifyNotifySpawnerOfDeath(self, other, msg) -- message sent from an enemy's spawner network when it dies local spawnerName = other:GetStoredConfigData().configData.spawner_name -- if we dont have a spawner name then return if not spawnerName then return end -- if a named enemy dies, tell the named enemy script if spawnerName == "Named_Enemies" then NamedEnemyDeath(self,other,msg) return end -- strip out the section name from the full spawner name local sectionName = string.sub(spawnerName, 1, -7) -- get the mob death count for this section local mobDeathCount = self:GetVar("mobsDead_" .. sectionName) or 0 mobDeathCount = mobDeathCount + 1 --debugPrint(self, "NotifySpawnerOfDeath " .. msg.objectID:GetName().name .. " @ " .. tostring(spawnerName) .. " count = " .. mobDeathCount) -- if we have met the mobDeathResetNumber then spawn this section with a new random load if mobDeathCount >= mobDeathResetNumber then mobDeathCount = 0 -- split out the different parts of the sectionName to send to the spawnSection function local zoneInfo = split(sectionName, "_") spawnSection(self, sectionName, sectionMultipliers[zoneInfo[sectionIDConst]]) end -- set the mobDeathCount self:SetVar("mobsDead_" .. sectionName, mobDeathCount) end ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------- -- when a player enters the volume, add to the totalplayers ---------------------------------------------------------------- function baseCollisionPhantom(self,msg) -- set the player local player = msg.objectID -- make sure the player actually exists if player:Exists() and player:IsCharacter().isChar then -- get the number of players that were in the volume local TotalPlayers = table.maxn(self:GetObjectsInPhysicsBounds().objects) self:SetVar("TotalPlayers", TotalPlayers) --print("Player "..player:GetName().name.." ENTERED - TotalPlayers is "..TotalPlayers.." in volume "..self:GetName().name) -- check if players are now higher than the change number -- make sure the spawn rate wasnt just reset and that it is in the min amount spawned state if TotalPlayers >= changeNum and not self:GetVar("JustChanged") and self:GetVar("SpawnState") == "min" then -- go to the function to turn up the spawn numbers SpawnersUp(self) end end end ---------------------------------------------------------------- -- when a player leaves the volume, subtract from the total players ---------------------------------------------------------------- function baseOffCollisionPhantom(self,msg) -- set the player local player = msg.objectID -- make sure the player actually exists if player:Exists() and player:IsCharacter().isChar then -- get the number of players that were in the volume local TotalPlayers = table.maxn(self:GetObjectsInPhysicsBounds().objects) -- set the number of players self:SetVar("TotalPlayers", TotalPlayers) --print("Player "..player:GetName().name.." EXITED - TotalPlayers is "..TotalPlayers.." in volume "..self:GetName().name) -- check if players are now lower than the change number -- make sure the spawn rate wasnt just reset and that it is in the max amount spawned state if TotalPlayers < changeNum and not self:GetVar("JustChanged") and self:GetVar("SpawnState") == "max" then -- go to the function to turn down the spawn numbers SpawnersDown(self) end end end ---------------------------------------------------------------- -- custom function - turn the spawn numbers up ---------------------------------------------------------------- function SpawnersUp(self) --print("spawners ramp up") -- set the spawn state to max self:SetVar("SpawnState", "max") -- set the just changed state to true self:SetVar("JustChanged", true) -- make timer to maintain the change state GAMEOBJ:GetTimer():AddTimerWithCancel( 60, "StateChange", self ) -- loop through the sections in the area for name,num in pairs(sectionMultipliers) do -- loop through the types in the spawn sets for i = 1,#zones[1] do -- create the spawner network name local spawnerName = zonePrefix .. "_" .. zoneName .. "_" .. name.."_type"..i -- use the spawner network name to find out how many enemies are spawned on the spawner network. local spawner = LEVEL:GetSpawnerByName(spawnerName) if spawner then local oldNum = spawner:SpawnerGetNumToMaintain().uiNum -- add one to the number ccurrently spawned if oldNum == 0 then return end local newNum = tonumber(oldNum) + 1 if (newNum > spawner:SpawnerGetNumNodes().uiNum) then newNum = oldNum --print("%%%%%%%%%%%%%%% ALERT!!! SPAWN NUMBER HAD TO BE ADJUSTED %%%%%%%%%%%%%%%%%") --print(" new number is "..newNum.." and max is "..spawner:SpawnerGetNumNodes().uiNum) end setSpawnerNetwork(self, spawnerName, newNum) end end end end ---------------------------------------------------------------- -- custom function - turn the spawn numbers down ---------------------------------------------------------------- function SpawnersDown(self) --print("spawners ramp down") -- set the spawn state to max self:SetVar("SpawnState", "min") -- set the just changed state to true self:SetVar("JustChanged", true) -- make timer to maintain the change state GAMEOBJ:GetTimer():AddTimerWithCancel( 60, "StateChange", self ) -- loop through the sections in the area for name,num in pairs(sectionMultipliers) do -- loop through the types in the spawn sets for i = 1,#zones[1] do -- create the spawner network name local spawnerName = zonePrefix .. "_" .. zoneName .. "_" .. name.."_type"..i -- use the spawner network name to find out how many enemies are spawned on the spawner network. local spawner = LEVEL:GetSpawnerByName(spawnerName) if spawner then local oldNum = spawner:SpawnerGetNumToMaintain().uiNum local newNum = oldNum -- make sure the the spawn if oldNum > 1 then newNum = oldNum - 1 end setSpawnerNetwork(self, spawnerName, newNum) end end end end ---------------------------------------------------------------- -- timer to control state change ---------------------------------------------------------------- function onTimerDone(self,msg) NamedTimerDone(self,msg) if msg.name == "StateChange" then -- set the just changed state to false self:SetVar("JustChanged", false) -- get the spawn state local SpawnState = self:GetVar("SpawnState") -- get the total number of players in the volume local TotalPlayers = self:GetVar("TotalPlayers") -- check to see if the spawn state should have changed during the pause -- if the spawnstate is min and the total players is greater than the change number if SpawnState == "min" and TotalPlayers >= changeNum then -- turn the spawn numbers up SpawnersUp(self) -- if the spawnstate is max and the total players is less than the change number elseif SpawnState == "max" and TotalPlayers < changeNum then -- turn the spawn numbers down SpawnersDown(self) end end end