-- 13925 Castle Corner Inner 2 9499 3 4210 -- 13926 Castle Gate 2 9503 3 4214 -- 13927 Castle Tower 2 9507 3 4218 -- 13928 Castle Wall Bridge 2 9508 3 4219 -- 13929 Castle Wall Straight 2 9514 3 4225 -- 13930 Castle Wall T 2 9517 3 4228 -- 13931 Castle Wall Tower With Top -- 13932 Castle Wall Widening 2 9520 3 4231 -- 14202 Castle Wall Tower With Top QB -- 14206 Castle Corner Inner QB -- 14207 Castle Gate QB -- 14208 Castle Tower QB -- 14209 Castle Wall Bridge QB -- 14210 Castle Wall Straight QB -- 14211 Castle Wall T QB -- 14213 Castle Wall Widening QB -- 16131 Center Object -------------------------------------------------------------- -- Includes -------------------------------------------------------------- require('ai/ACT/L_ACT_GENERIC_ACTIVITY_MGR') -- Center piece lot number local gCenterLOT = 16131 local gCenterSpawned = 0 local gGameOver = false -- Center piece object IDs local gCenterIDs = { center1 = 0, center2 = 0 } local HealthCBLOT = 16206 local ShieldCBLOT = 16207 local DragonCBLOT = 16208 local AttackCBLOT = 16209 local ShieldCBCount = 0 local DragonCBCount = 0 local AttackCBCount = 0 local HealthCBCount = 0 --////////////////////////////////////////////////////////////////////////////////// -- User Config local variables local gConstants = { acceptedDelay = 2, -- how long to wait after all the players have accepted before starting the game. startDelay = 2, -- how long to wait after all the players have accepted before starting the game. returnZone = 89, -- map number the player will return to on exit returnLoc = { x = 0, y = 0, z = 0 } -- {x,y,z} location that the player will be teleported to in the returnZone on exit } --============================================================ -- Script only local variables local gGamestate = { tPlayers = {}, -- players who have entered the game tWaitingPlayers = {}, -- players who haven't accepted yet iNumberOfPlayers = 0 -- number of players given from ZoneLoadedInfo } ---------------------------------------------------------------- -- Received when the script is loaded ---------------------------------------------------------------- function onStartup(self) -- Initialize the pseudo random number generator and return math.randomseed(os.time()) self:SetVar('playersAccepted', 0) self:SetVar('playersReady', false) --self:MiniGameSetParameters{numTeams = 1, playersPerTeam = 4} -- Load first center piece RESMGR:LoadObject { objectTemplate = gCenterLOT, x=-4.0, y=200.00, z= 103.0, owner = self } end function onChildLoaded(self, msg) print("Child Loaded") if msg.templateID == gCenterLOT then -- childID if gCenterSpawned == 0 then gCenterSpawned = 1 gCenterIDs.center1 = msg.childID RESMGR:LoadObject { objectTemplate = gCenterLOT , x=-12.0, y=200.00, z=-111.0 , owner = self } elseif gCenterSpawned == 1 then gCenterSpawned = 2 gCenterIDs.center2 = msg.childID end end end function onChildRemoved(self, msg) local child = msg.childID local message_string = "test" local bDisplayMessage = false if(gGameOver == true) then return end if(child:GetLOT().objtemplate == gCenterLOT) then if child:GetID() == gCenterIDs.center1:GetID() then print("team 2 wins") message_string = "TEAM 2 WINS!!" bDisplayMessage = true elseif child:GetID() == gCenterIDs.center2:GetID() then print("team 1 wins") message_string = "TEAM 1 WINS!!" bDisplayMessage = true end end if(bDisplayMessage == true) then gGameOver = true for i = 1, table.maxn(gGamestate.tPlayers) do local playerID = GAMEOBJ:GetObjectByID(gGamestate.tPlayers[i]) playerID:DisplayMessageBox{bShow = true, imageID = 1, text = message_string, callbackClient = self, identifier = "score thing"} end end end ---------------------------------------------------------------- -- Player is fully loaded and has completed the load handshake process. ---------------------------------------------------------------- function onPlayerReady(self, msg) if not self:GetVar('SurvivalStartupComplete') then self:SetVar('SurvivalStartupComplete', true) end end ---------------------------------------------------------------- -- Player has loaded into the map ---------------------------------------------------------------- function onPlayerLoaded(self, msg) -- adding the players to the gGamestate tables table.insert(gGamestate.tPlayers, msg.playerID:GetID()) table.insert(gGamestate.tWaitingPlayers, msg.playerID:GetID()) -- adding player to mini game team --self:MiniGameAddPlayer{playerID = msg.playerID} --self:MiniGameSetTeam{playerID = msg.playerID, teamID = 1} -- setting up player ui self:SetNetworkVar('Define_Player_To_UI', msg.playerID:GetID()) -- freeze the player movement/controls if not self:GetNetworkVar('wavesStarted') then -- updating the scoreboard for the new players self:SetNetworkVar('Update_ScoreBoard_Players', gGamestate.tPlayers) self:SetNetworkVar('Show_ScoreBoard', true) end -- TODO set this up to work with teams -- move players to correct spawn locations SetPlayerSpawnPoints(self) msg.playerID:PlayerSetCameraCyclingMode{ cyclingMode = ALLOW_CYCLE_TEAMMATES, bAllowCyclingWhileDeadOnly = true } if not self:GetNetworkVar('wavesStarted') then playerConfirmed(self) else local playerID = msg.playerID if not playerID then return end table.insert(gGamestate.tWaitingPlayers, v) UpdatePlayer(self, playerID) --playerID:SetUserCtrlCompPause{bPaused = false} GetLeaderboardData(self, playerID, self:GetActivityID().activityID, 50) --set player stats to max playerID:SetHealth{health = playerID:GetMaxHealth{}.health} --print('max health = ' .. playerID:GetMaxHealth{}.health) playerID:SetArmor{armor = playerID:GetMaxArmor{}.armor} playerID:SetImagination{imagination = playerID:GetMaxImagination{}.imagination} end end ---------------------------------------------------------------- -- Player has exited the map ---------------------------------------------------------------- function onPlayerExit(self, msg) local playerNum = 0 --print('player ' .. msg.playerID:GetName().name .. ' has exited') for i = 1, table.maxn(gGamestate.tPlayers) do if gGamestate.tPlayers[i] == msg.playerID:GetID() then playerNum = i end end if playerNum ~= 0 then table.remove(gGamestate.tPlayers, playerNum) -- set player to not auto-respawn msg.playerID:SetPlayerAllowedRespawn{dontPromptForRespawn=false} end playerNum = 0 for k,v in ipairs(gGamestate.tWaitingPlayers) do if msg.playerID:GetID() == v then playerNum = k end end if playerNum ~= 0 then table.remove(gGamestate.tWaitingPlayers, playerNum) end if not self:GetNetworkVar('wavesStarted') then playerConfirmed(self) --print('num of players left waiting: ' .. #gGamestate.tWaitingPlayers) if #gGamestate.tPlayers == 0 then return end if table.maxn(gGamestate.tWaitingPlayers) == 0 then --print('All players have accepted') ActivityTimerStopAllTimers(self) ActivityTimerStart(self, 'AllAcceptedDelay', 1, gConstants.startDelay) --(timerName, updateTime, stopTime) elseif #gGamestate.tPlayers > #gGamestate.tWaitingPlayers then if not self:GetVar('AcceptedDelayStarted') then self:SetVar('AcceptedDelayStarted', true) ActivityTimerStart(self, 'AcceptedDelay', 1, gConstants.acceptedDelay ) --(timerName, updateTime, stopTime) end end else UpdatePlayer(self, msg.playerID, true) if checkAllPlayersDead() then GameOver(self, msg.playerID) end end SetActivityValue(self, msg.playerID, 1, 0) local numPlayers = self:GetNetworkVar('NumberOfPlayers') self:SetNetworkVar('NumberOfPlayers', numPlayers - 1) end function onZoneLoadedInfo(self, msg) self:SetNetworkVar('NumberOfPlayers', msg.maxPlayersSoft) end function playerConfirmed(self) local playersConfirmed = {} for k,v in ipairs(gGamestate.tPlayers) do local bPass = false for key,value in ipairs(gGamestate.tWaitingPlayers) do if value == v then bPass = true end end if not bPass then table.insert(playersConfirmed, v) end end self:SetNetworkVar('PlayerConfirm_ScoreBoard', playersConfirmed) end ---------------------------------------------------------------- -- This is called when players hit the UI to exit or stop the game. ---------------------------------------------------------------- function baseMessageBoxRespond(self, msg, newMsg) if (msg.identifier == "RePlay" ) then PlayerAccepted(self, msg.sender) playerConfirmed(self) elseif (msg.identifier == "Exit_Question" ) and msg.iButton == 1 then ResetStats(msg.sender) self:SetNetworkVar('Exit_Waves', msg.sender:GetID()) -- send player to a specific location msg.sender:TransferToLastNonInstance{ playerID = msg.sender, bUseLastPosition = false, pos_x = 131.83, pos_y = 376, pos_z = -180.31, rot_x = 0, rot_y = -0.268720, rot_z = 0, rot_w = 0.963218} end end ---------------------------------------------------------------- -- Custom function: Checks to see if all players have accepted, -- if they have then the game is started. ---------------------------------------------------------------- function PlayerAccepted(self, playerID) local playerNum = 0 print("PLAYER ACCEPTED") -- Figure out what player num this guy is. for k,v in ipairs(gGamestate.tWaitingPlayers) do if playerID:GetID() == v then playerNum = k end end if playerNum == 0 then return end -- TODO make sure this value is correct table.remove(gGamestate.tWaitingPlayers, playerNum) if table.maxn(gGamestate.tWaitingPlayers) == 0 and #gGamestate.tPlayers >= self:GetNetworkVar('NumberOfPlayers') then print("accepted option 1") ActivityTimerStopAllTimers(self) ActivityTimerStart(self, 'AllAcceptedDelay', 1, gConstants.startDelay) --(timerName, updateTime, stopTime) else if not self:GetVar('AcceptedDelayStarted') then print("accepted option 2") self:SetVar('AcceptedDelayStarted', true) --ActivityTimerStart(self, 'AcceptedDelay', 1, gConstants.acceptedDelay) --(timerName, updateTime, stopTime) ActivityTimerStart(self, 'AcceptedDelay', 1, 2) --(timerName, updateTime, stopTime) end end end function ResetStats(playerID) -- set the player's imag, health and armor to full if playerID:Exists() then --set player stats to max playerID:SetHealth{health = playerID:GetMaxHealth{}.health} playerID:SetArmor{armor = playerID:GetMaxArmor{}.armor} playerID:SetImagination{imagination = playerID:GetMaxImagination{}.imagination} end end ---------------------------------------------------------------- -- Custom function: Starts the game. ---------------------------------------------------------------- function StartWaves(self) SetupActivity(self, 4) self:ActivityStart() self:SetVar('playersReady', true) self:SetVar('AcceptedDelayStarted', false) gGamestate.tWaitingPlayers = {} for k,v in ipairs(gGamestate.tPlayers) do local playerID = GAMEOBJ:GetObjectByID(v) if not playerID then return end table.insert(gGamestate.tWaitingPlayers, v) UpdatePlayer(self, playerID) GetLeaderboardData(self, playerID, self:GetActivityID().activityID, 50) ResetStats(playerID) if not self:GetVar('firstTimeDone') then --remove the activity cost from the player as they load into the map local takeCost = self:ChargeActivityCost{user = playerID}.bSucceeded end end self:SetVar('firstTimeDone', true) -- needed to get rewards -- taskType = DB name for series of achievments, target = activityID, value1 = what it will evaluate local sTaskType = 'survival_time_team' if #gGamestate.tPlayers == 1 then sTaskType = 'survival_time_solo' end self:SetVar('missionType', sTaskType) --print('start smashables') self:SetNetworkVar('wavesStarted', true) self:SetNetworkVar('Start_Wave_Message', "Start!") end ---------------------------------------------------------------- -- Custom function: Checks to see if all the players are dead, -- then stops the game. ---------------------------------------------------------------- function checkAllPlayersDead() local deadPlayers = 0 for k,v in ipairs(gGamestate.tPlayers) do local playerID = GAMEOBJ:GetObjectByID(v) if not playerID then return end if playerID:IsDead().bDead then deadPlayers = deadPlayers + 1 end end if deadPlayers == table.maxn(gGamestate.tPlayers) then return true end return false end -- Create a SetPlayerSpawnPoints per team function SetPlayerSpawnPoints(self) for k,v in ipairs(gGamestate.tPlayers) do local playerID = GAMEOBJ:GetObjectByID(v) if not playerID then return end local spawnObj = self:GetObjectsInGroup{ group = 'P' .. k .. '_Spawn', ignoreSpawners = true }.objects[1] if spawnObj then local pos = spawnObj:GetPosition().pos local rot = spawnObj:GetRotation() print("SPAWN POINT FOUND") playerID:Teleport{pos = pos, x = rot.x, y = rot.y, z = rot.z, w = rot.w, bSetRotation = true} end end end ---------------------------------------------------------------- -- Custom function: Happens when all players have died, this -- stops all running processes and resets gGamestate variables ---------------------------------------------------------------- function GameOver(self, player) if not checkAllPlayersDead() then return end local finalTime = ActivityTimerGetCurrentTime(self, 'ClockTick') ActivityTimerStopAllTimers(self) for k,v in ipairs(gGamestate.tPlayers) do local playerID = GAMEOBJ:GetObjectByID(v) if not playerID then return end local timeVar = GetActivityValue(self, playerID, 1) local scoreVar = GetActivityValue(self, playerID, 0) self:NotifyClientZoneObject{name = 'Update_ScoreBoard', paramObj = playerID, paramStr = tostring(scoreVar), param1 = timeVar} playerID:Resurrect() -- this is to have everyone get their own time at the end of the match StopActivity(self, playerID, scoreVar, timeVar) end self:SetNetworkVar('wavesStarted', false) SetPlayerSpawnPoints(self) end function basePlayerResurrected(self, msg, newMsg) self:SetNetworkVar('Show_ScoreBoard', true) end ---------------------------------------------------------------- -- Custom function: splits a string based on patern and returns a table ---------------------------------------------------------------- function split(str, pat) local t = {} -- NOTE: use {n = 0} in Lua-5.0 local fpat = "(.-)" .. pat local last_end = 1 local s, e, cap = str:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(t,cap) end last_end = e+1 s, e, cap = str:find(fpat, last_end) end if last_end <= #str then cap = str:sub(last_end) table.insert(t, cap) end return t end ---------------------------------------------------------------- -- When activity is stopped this is needed to update the leaderboard. ---------------------------------------------------------------- function onDoCalculateActivityRating(self, msg) -- get the time for the player --print('Score = ' .. msg.fValue1) --print('Time = ' .. msg.fValue2) msg.outActivityRating = msg.fValue2 return msg end -- activity timers ---------------------------------------------------------------- -- When ActivityTimerUpdate is sent, basically when a timer hits it updateInterval. ---------------------------------------------------------------- function onActivityTimerUpdate(self, msg) if msg.name == "AcceptedDelay" then --print('update delay timer to ' .. math.ceil(msg.timeRemaining)) self:SetNetworkVar('Update_Default_Start_Timer', math.ceil(msg.timeRemaining)) elseif msg.name == "ClockTick" then self:SetNetworkVar('Update_Timer', msg.timeElapsed) elseif msg.name == "SpawnTick" and not self:GetVar('isCoolDown') then --spawnMobs(self) end end ---------------------------------------------------------------- -- When ActivityTimerDone is sent, basically when the activity timer has reached it's duration. ---------------------------------------------------------------- function onActivityTimerDone(self, msg) if msg.name == "AcceptedDelay" then --or msg.name == "AllAcceptedDelay" --print('update delay timer to 0') self:SetNetworkVar('Update_Default_Start_Timer', 0) ActivityTimerStart(self, 'AllAcceptedDelay', 1, 1) elseif msg.name == "AllAcceptedDelay" then --or msg.name == "AllAcceptedDelay" --print('accepted delay *******************************') self:SetNetworkVar('Clear_Scoreboard', true) ActivityTimerStart(self, 'StartDelay', 3, 3) --(timerName, updateTime, stopTime) StartWaves(self) elseif msg.name == "StartDelay" then --print('adding in timers *******************************') ActivityTimerStart(self, 'ClockTick', 1) --(timerName, updateTime, stopTime) -- spawnMobs(self) ActivityTimerStart(self, 'PlaySpawnSound', 3, 3) --(timerName, updateTime, stopTime) elseif msg.name == "CoolDownStart" then --print('cool down start timer *******************************') self:SetVar('isCoolDown', true) ActivityTimerStop(self, 'SpawnTick') --print('stopping clock tick') elseif msg.name == "CoolDownStop" then --print('cool down stop timer *******************************') self:SetVar('isCoolDown', false) -- spawnMobs(self) ActivityTimerStart(self, 'PlaySpawnSound', 3, 3) --(timerName, updateTime, stopTime) elseif msg.name == "PlaySpawnSound" then -- play war horn sound for k,v in ipairs(gGamestate.tPlayers) do GAMEOBJ:GetObjectByID(v):PlayNDAudioEmitter{m_NDAudioEventGUID = '{ca36045d-89df-4e96-a317-1e152d226b69}'} end end end --============================================================ --============================================================ -- Game messages sent to the BASE_SURVIVAL_SERVER.lua file, these -- must be in this script. Only change to add custom functionality, -- but leav e the base*message*(self, msg, newMsg) in the function. --============================================================ ---------------------------------------------------------------- -- Received a fire event messaged from the client ---------------------------------------------------------------- function onFireEventServerSide(self, msg) baseFireEventServerSide(self, msg, newMsg) end ---------------------------------------------------------------- -- A player has respawned ---------------------------------------------------------------- function onPlayerResurrected(self, msg) basePlayerResurrected(self, msg, newMsg) end ---------------------------------------------------------------- -- Received a notify object message ---------------------------------------------------------------- function onNotifyObject(self, msg) -- add to this CBs ref count. If it is 4 then do whatever if(msg.name == "cb_added") then if(msg.param1 == HealthCBLOT) then HealthCBCount = HealthCBCount + 1 if(HealthCBCount == 4) then print("ALL 4") -- do something end elseif(msg.param1 == DragonCBLOT) then DragonCBCount = DragonCBCount + 1 if(DragonCBCount == 4) then print("ALL 4") -- do something end elseif(msg.param1 == AttackCBLOT) then AttackCBCount = AttackCBCount + 1 if(AttackCBCount == 4) then print("ALL 4") -- do something end elseif(msg.param1 == ShieldCBLOT) then ShieldCBCount = ShieldCBCount + 1 if(ShieldCBCount == 4) then print("ALL 4") -- do something end end print("CB ADDED: " .. msg.param1) return end -- remove from this CBs ref count. If it is 3 then undo whatever if(msg.name == "cb_removed") then print("CB REMOVED: " .. msg.param1) if(msg.param1 == HealthCBLOT) then HealthCBCount = HealthCBCount - 1 if(HealthCBCount == 3) then print("WAS 4") -- do something end elseif(msg.param1 == DragonCBLOT) then DragonCBCount = DragonCBCount - 1 if(DragonCBCount == 3) then print("WAS 4") -- do something end elseif(msg.param1 == AttackCBLOT) then AttackCBCount = AttackCBCount - 1 if(AttackCBCount == 3) then print("WAS 4") -- do something end elseif(msg.param1 == ShieldCBLOT) then ShieldCBCount = ShieldCBCount - 1 if(ShieldCBCount == 3) then print("WAS 4") -- do something end end return end local player = msg.ObjIDSender -- check to make sure the player is in the activity if not IsPlayerInActivity(self, player) then return end -- update kill score UpdateActivityValue(self, player, 0, msg.param1) end ---------------------------------------------------------------- -- This is called when players hit the UI to exit or stop the game. ---------------------------------------------------------------- function onMessageBoxRespond(self,msg) baseMessageBoxRespond(self, msg, newMsg) end ---------------------------------------------------------------- -- Notification that a ui element used. ---------------------------------------------------------------- function onActivityStateChangeRequest(self,msg) baseActivityStateChangeRequest(self, msg, newMsg) end