-------------------------------------------------------------- -- Includes -------------------------------------------------------------- require('o_mis') require('o_ShootingGallery') -- @TODO: deal with players logging out in middle of race -------------------------------------------------------------- -- Constants -------------------------------------------------------------- -- Start Location for the Zone CONSTANTS = {} CONSTANTS["PLAYER_ZONEIN_POS"] = {x = 122.854, y = 278.0, z = -343.110} CONSTANTS["PLAYER_ZONEIN_ROT"] = {w = 0.722735, x = 0, y = 0.691124, z = 0} --CONSTANTS["PLAYER_ZONEIN_POS"] = {x = -688.0, y = 201.0, z = -147.0} --CONSTANTS["PLAYER_ZONEIN_ROT"] = {w = 0.722735, x = 0, y = 0.691124, z = 0} -- --CONSTANTS["PLAYER_START_POS1"] = {x = -604.0, y = 186.0, z = -154.0} --CONSTANTS["PLAYER_START_ROT1"] = {w = 0.287, x = 0, y = 0.957, z = 0} -- --CONSTANTS["PLAYER_START_POS2"] = {x = -601.0, y = 186.0, z = -150.0} --CONSTANTS["PLAYER_START_ROT2"] = {w = 0.287, x = 0, y = 0.957, z = 0} -- CONSTANTS["PLAYER_START_POS1"] = { x = -258.739, y = 210.0, z = -457.921 } CONSTANTS["PLAYER_START_POS2"] = { x = -254.554, y = 210.0, z = -462.901 } CONSTANTS["PLAYER_START_POS3"] = { x = -250.512, y = 210.0, z = -467.708 } CONSTANTS["PLAYER_START_POS4"] = { x = -245.919, y = 210.0, z = -473.172 } CONSTANTS["PLAYER_START_POS5"] = { x = -241.867, y = 210.0, z = -477.991 } CONSTANTS["PLAYER_START_POS6"] = { x = -237.412, y = 210.0, z = -483.290 } CONSTANTS["PLAYER_START_POS7"] = { x = -233.087, y = 210.0, z = -488.434 } CONSTANTS["PLAYER_START_POS8"] = { x = -228.770, y = 210.0, z = -493.569 } CONSTANTS["PLAYER_START_POS9"] = { x = -224.724, y = 210.0, z = -498.382 } CONSTANTS["PLAYER_START_POS10"]= { x = -220.404, y = 210.0, z = -503.520 } CONSTANTS["PLAYER_START_ROT"] = {w = -0.45988774, x = 0, y = 0.88797706, z = 0} CONSTANTS["CANNON_TEMPLATEID"] = 1864 CONSTANTS["CANNON_PLAYER_OFFSET"] = {x = 6.652, y = 0, z = -5.716} --@todo port back CONSTANTS["CANNON_VELOCITY"] = 160.0 CONSTANTS["CANNON_MIN_DISTANCE"] = 30.0 CONSTANTS["CANNON_REFIRE_RATE"] = 1000.0 CONSTANTS["CANNON_BARREL_OFFSET"] = {x = 0, y = 4.3, z = 9} CONSTANTS["CANNON_TIMEOUT"] = -1 CONSTANTS["CANNON_IMPACT_SKILL"] = 73 CONSTANTS["GOAL_LINE_LOT"] = 2717 CONSTANTS["CHECKPOINT_LOT"] = 2718 CONSTANTS["BOARD_LOT"] = 2250 CONSTANTS["RACE_MISSION_ID"] = 31 CONSTANTS["CANNON_MISSION_ID"] = 57 CONSTANTS["TURN_SPEED_MULT"] = 0.4 -- turn speed multiplier for track CONSTANTS["MAX_PLAYERS"] = 10 -- number of players max CONSTANTS["MIN_PLAYERS"] = 1 -- number of players min CONSTANTS["MAX_LAPS"] = 3 -- number of laps for race CONSTANTS["NUM_CHECKPOINTS"] = 0 -- this should Auto Update CONSTANTS["NUM_CANNONS"] = 0 -- this should Auto Update CONSTANTS["COUNTDOWN_TIME"] = 3.0 CONSTANTS["RACE_TIMEOUT"] = 20.0 --60.0 -- time until race auto quits with less then min players CONSTANTS["RACE_START_TIME"] = 25.0--30.0 --30.0 -- time until race starts after min player reached CONSTANTS["RACE_FINISH_TIME"] = 40.0 --60.0 -- time until race finishes BOARDS = {2851, 2852, 2853, 2854} CONSTANTS["NUM_BOARDS"] = #BOARDS PLAYERS = {} CHECKPOINTS = {} CANNONS = {} -- stores player in cannon and the cannon itself PLAYERS_TO_REMOVE = {} -- stores players that need to be removed from the cannon -- local vars LOCALS = {} LOCALS["bWaitingForPlayers"] = false -------------------------------------------------------------- -- Helper Functions -------------------------------------------------------------- -------------------------------------------------------------- -- Pads a number with zeros on the left, to fill a field of the specified -- length. -------------------------------------------------------------- function ZeroPad(number, length) return string.rep("0", length - #tostring(number)) .. tostring(number) end -------------------------------------------------------------- -- parses time to a string -------------------------------------------------------------- function ParseTime(numTime) local newTime = tonumber(numTime) local min = math.floor(newTime / 1000 / 60) newTime = newTime - (min * 1000 * 60) local sec = math.floor(newTime / 1000) newTime = newTime - (sec * 1000) local msec = math.floor(newTime) local strTime = "" if (min > 0) then strTime = ZeroPad(min,2) .. ":" .. ZeroPad(sec,2) .. "." .. ZeroPad(msec,3) else strTime = ZeroPad(sec,2) .. "." .. ZeroPad(msec,3) end return strTime end -------------------------------------------------------------- -- checks to see if the checkPoint ID is valid, -- returns > 0 if valid -------------------------------------------------------------- function IsValidCheckpoint(self, checkPoint) for chkp = 1, CONSTANTS["NUM_CHECKPOINTS"] do if (checkPoint == CHECKPOINTS[chkp]) then return chkp end end return 0 end -------------------------------------------------------------- -- checks to see if the cannon ID is valid and empty, -- returns cannonid if valid, 0 otherwise -------------------------------------------------------------- function GetValidCannon(self) for chkp = 1, CONSTANTS["NUM_CANNONS"] do if (CANNONS[chkp]["Player"] == 0) then return CANNONS[chkp]["Cannon"] end end return 0 end -------------------------------------------------------------- -- returns true if game is going -------------------------------------------------------------- function IsGameStarted(self) return (LOCALS["GameStarted"] == true) end -------------------------------------------------------------- -- returns player num -- returns > 0 if valid -------------------------------------------------------------- function GetPlayerNum(self, player) for pnum = 1, #PLAYERS do if (player:GetID() == PLAYERS[pnum]) then return pnum end end return 0 end -------------------------------------------------------------- -- checks to see if a player has hit all checkpoints -------------------------------------------------------------- function HasPlayerHitAllCheckpoints(self, player) local playerData = self:GetVar(player:GetID()) if (playerData) then for chkp = 1, CONSTANTS["NUM_CHECKPOINTS"] do if (playerData["chkpStatus" .. chkp] == false) then return false end end else return false end -- all checkpoints good, no failures return true end -------------------------------------------------------------- -- sends a message to display the current lap to the player -------------------------------------------------------------- function DisplayLapNumberToPlayer(self, lapNum, player, strLastLapTime) if (player) then player:DisplayFloatyText{strText = "Lap " .. lapNum .. ", Last: " .. ParseTime(strLastLapTime) .. "s"} end end -------------------------------------------------------------- -- sends a message to display checkpoint info to the player -------------------------------------------------------------- function DisplayCheckpointTimeToPlayer(self, player) if ( (player) and (IsGameStarted(self)) ) then -- get player data local playerData = self:GetVar(player:GetID()) if (playerData) then -- get current time local theTime = GAMEOBJ:GetSystemTime() local strTime = tonumber(theTime) - tonumber(playerData["curLapTime"]) player:DisplayFloatyText{strText = "Checkpoint;" .. ParseTime(strTime) .. "s"} end end end -------------------------------------------------------------- -- sets the place data member for a player -------------------------------------------------------------- function SetPlayerPlace(self, player, place) if (player) then local playerData = self:GetVar(player:GetID()) if (playerData) then playerData["place"] = place self:SetVar(player:GetID(), playerData) end end end -------------------------------------------------------------- -- flags a lap for a player and displays any information -------------------------------------------------------------- function FlagLap(self, player) -- try to get player data local playerData = self:GetVar(player:GetID()) -- has the player hit all the checkpoints? if ( (IsGameStarted(self)) and (playerData) and ( HasPlayerHitAllCheckpoints(self,player) == true ) ) then print("Goal Hit!") local theTime = GAMEOBJ:GetSystemTime() local strTime = tonumber(theTime) - tonumber(playerData["curLapTime"]) -- set this player's lap time playerData["lapTime" .. playerData["curLap"]] = strTime -- reset current lapTime playerData["curLapTime"] = theTime -- move the player to the next lap playerData["curLap"] = tonumber(playerData["curLap"]) + 1 -- reset checkpoint flags for chkp = 1, CONSTANTS["NUM_CHECKPOINTS"] do playerData["chkpStatus" .. chkp] = false end -- store the data self:SetVar(player:GetID(), playerData) -- show player the lap number or end game if (tonumber(playerData["curLap"]) <= CONSTANTS["MAX_LAPS"]) then DisplayLapNumberToPlayer(self, playerData["curLap"], player, strTime) player:PlaySound{ strSoundName = "lap_complete" } else -- done with race (someone finished) local numFinishedPlayers = IncrementVarAndReturn("NumPlayersFinished") -- set to first place SetPlayerPlace(self, player, numFinishedPlayers) -- -- stun player because he is done with race -- player:SetStunned -- { -- StateChangeType = PUSH, -- bCantMove = true, -- bCantTurn = true, -- bCantAttack = true, -- bCantEquip = true, -- bCantInteract = true -- } -- -- stop the race when we are totally done if (numFinishedPlayers >= #PLAYERS) then StopGame(self) -- first player across the line starts the timeout timer elseif (numFinishedPlayers == 1) then DoFinishRaceTimer(self,player) end end end end -------------------------------------------------------------- -- being end race timer -------------------------------------------------------------- function DoFinishRaceTimer(self,winner) -- cancel all timers GAMEOBJ:GetTimer():CancelAllTimers( self ) local winnerName = winner:GetName().name -- display tooltip to all players in race for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) local playerData = self:GetVar(PLAYERS[pnum]) if ((winner:GetID() == PLAYERS[pnum])) then -- show tooltip to winner player:DisplayTooltip{ bShow = true, strText = "You Win!\n Waiting for other players." } player:PlayFXEffect{effectType = "fireworks"} elseif (player and playerData) then -- show tooltip to others player:DisplayTooltip{ bShow = true, strText = "Winner: " .. winnerName .. "\nRace ends in " .. CONSTANTS["RACE_FINISH_TIME"] .. " seconds.", iTime = 5000 } end end -- start timer for game start GAMEOBJ:GetTimer():AddTimerWithCancel( CONSTANTS["RACE_FINISH_TIME"], "EndGame", self ) end -------------------------------------------------------------- -- flags a checkpoint for a player and displays any information -------------------------------------------------------------- function FlagCheckpoint(self, player, checkPoint) -- try to get player data and checkpoint data local playerData = self:GetVar(player:GetID()) local chkp = tonumber(IsValidCheckpoint(self,checkPoint)) -- are the vars valid? if ( (IsGameStarted(self)) and (playerData) and ( chkp > 0) and tonumber(playerData["curLap"]) <= CONSTANTS["MAX_LAPS"]) then print("Checkpoint " .. chkp .. " Hit!") -- show the checkpoint time to player if (playerData["chkpStatus" .. chkp] == false) then player:PlaySound{ strSoundName = "checkpoint" } DisplayCheckpointTimeToPlayer(self, player) end -- set this checkpoint to true for player playerData["chkpStatus" .. chkp] = true -- store the data self:SetVar(player:GetID(), playerData) end end -------------------------------------------------------------- -- get place string -------------------------------------------------------------- function GetPlaceString(place) if (tonumber(place) == 1) then return "1st" elseif (tonumber(place) == 2) then return "2nd" elseif (tonumber(place) == 3) then return "3rd" else return (place.."th") end end -------------------------------------------------------------- -- show the summary dialog -------------------------------------------------------------- function showSummaryDialog(self, player) if (player) then local playerData = self:GetVar(player:GetID()) -- close any tooltip player:DisplayTooltip{ bShow = false, strText = "..." } -- setup summary text local strText = "" strText = strText .. "Race Over!\n\n" -- show place local place = GetPlaceString(playerData["place"]) if (playerData["place"] == 0) then strText = strText .. "Not Finished!\n\n" else strText = strText .. "" .. place .. " Place!\n\n" end -- lap times local totalTime = 0 local bNotFinished = false for lap = 1, CONSTANTS["MAX_LAPS"] do -- if no lap time, exit early if (tonumber(playerData["lapTime" .. lap]) <= 0) then bNotFinished = true break else strText = strText .. "Lap " .. lap .. ": " .. ParseTime(playerData["lapTime" .. lap]) .. "\n" totalTime = totalTime + tonumber(playerData["lapTime" .. lap]) end end -- show total time if finished if (bNotFinished == false) then strText = strText .. "Total: " .. ParseTime(totalTime) .. "\n" end -- ask for retry strText = strText .. "\nRetry?" -- show the summary message box player:DisplayMessageBox{bShow = true, imageID = 2, callbackClient = GAMEOBJ:GetZoneControlID(), text = strText, identifier = "Racing_Summary"} end end -------------------------------------------------------------- -- remove boards from a player -------------------------------------------------------------- function RemoveBoardsFromPlayer(self, player) if (player) then for board = 1, CONSTANTS["NUM_BOARDS"] do -- unequip and remove the item player:RemoveItemFromInventory{ iObjTemplate = BOARDS[board] } end end end -------------------------------------------------------------- -- adds a random board to the player -------------------------------------------------------------- function AddRandomBoardToPlayer(self, player) if (player) then -- remove all current boards RemoveBoardsFromPlayer(self, player) local board = math.random(1,CONSTANTS["NUM_BOARDS"]) -- add item local item = player:AddNewItemToInventory{ iObjTemplate = BOARDS[board] } -- equip item player:EquipInventory{ itemtoequip = item.newObjID } end end -------------------------------------------------------------- -- remove player from game -------------------------------------------------------------- function RemovePlayerFromGame(self, player) if (player) then local playerNum = GetPlayerNum(self, player) -- reset data PLAYERS[playerNum] = -1 local NoData = {} self:SetVar(player:GetID(), NoData) -- remove all boards RemoveBoardsFromPlayer(self, player) player:Teleport{pos = CONSTANTS["PLAYER_ZONEIN_POS"], bSetRotation = false} end end -------------------------------------------------------------- -- add new player for the race -------------------------------------------------------------- function AddNewPlayerToGame(self, player) if (player) then local playerNum = IncrementVarAndReturn("PlayerNum") ----------------------------------------------------- -- store player data local PlayerData = {} PlayerData["startTime"] = 0 PlayerData["curLapTime"] = 0 PlayerData["curLap"] = 1 PlayerData["place"] = 0 for lap = 1, CONSTANTS["MAX_LAPS"] do PlayerData["lapTime" .. lap] = -1 end for chkp = 1, CONSTANTS["NUM_CHECKPOINTS"] do PlayerData["chkpStatus" .. chkp] = false end self:SetVar(player:GetID(), PlayerData) ----------------------------------------------------- -- store id in local array PLAYERS[playerNum] = player:GetID() -- put player in right spot player:Teleport{pos = CONSTANTS["PLAYER_START_POS" .. playerNum], x = CONSTANTS["PLAYER_START_ROT"].x, y = CONSTANTS["PLAYER_START_ROT"].y, z = CONSTANTS["PLAYER_START_ROT"].z, w = CONSTANTS["PLAYER_START_ROT"].w, bSetRotation = true} -- paused wait for game start player:ServerSetUserCtrlCompPause{bPaused = true} -- add board to player AddRandomBoardToPlayer(self, player) -- Try to start the game (next frame) local curplayers = LOCALS["PlayerNum"] if (tonumber(curplayers) == CONSTANTS["MAX_PLAYERS"]) then LOCALS["bWaitingForPlayers"] = false GAMEOBJ:GetTimer():CancelAllTimers( self ) GAMEOBJ:GetTimer():AddTimerWithCancel( 0.1, "StartGame", self ) else -- begin timer for game start if we have the min players if (tonumber(curplayers) == CONSTANTS["MIN_PLAYERS"]) then print("minplayers") BeginRaceStartJoinTimer(self) player:DisplayTooltip{ bShow = true, strText = "Waiting for players...", iTime = 0 } elseif (tonumber(curplayers) < CONSTANTS["MIN_PLAYERS"]) then -- start timeout timer if (LOCALS["bWaitingForPlayers"] == false) then GAMEOBJ:GetTimer():AddTimerWithCancel( CONSTANTS["RACE_TIMEOUT"], "TimeOut", self ) LOCALS["bWaitingForPlayers"] = true end -- inform player about wait with tooltip player:DisplayTooltip{ bShow = true, strText = "Waiting for players...", iTime = 0 } end end end end -------------------------------------------------------------- -- being the race join timer -------------------------------------------------------------- function BeginRaceStartJoinTimer(self) -- cancel all timers GAMEOBJ:GetTimer():CancelAllTimers( self ) -- display tooltip to all players in race for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) local playerData = self:GetVar(PLAYERS[pnum]) if (player and playerData) then -- show tooltip player:DisplayTooltip{ bShow = true, strText = "Race begins in " .. CONSTANTS["RACE_START_TIME"] .. " seconds. \nWaiting for more players." } end end -- start timer for game start GAMEOBJ:GetTimer():AddTimerWithCancel( CONSTANTS["RACE_START_TIME"], "StartGame", self ) end -------------------------------------------------------------- -- try to start the game -------------------------------------------------------------- function StartGame(self) print("Game Started") LOCALS["bWaitingForPlayers"] = false LOCALS["GameStarted"] = true -- iterate through players for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) local playerData = self:GetVar(PLAYERS[pnum]) if (player and playerData) then -- close any tooltip player:DisplayTooltip{ bShow = false, strText = "..." } -- trigger the Countdown on all clients player:ShowActivityCountdown { bPlayCountdownSound = false, bPlayAdditionalSound = true, sndName = "metallica - fuel", stateToPlaySoundOn = 1 } end end -- set a timer to Unpause and Go GAMEOBJ:GetTimer():AddTimerWithCancel( CONSTANTS["COUNTDOWN_TIME"], "Go", self ) end -------------------------------------------------------------- -- try to stop the game -------------------------------------------------------------- function StopGame(self) print("Game Stopped") LOCALS["bWaitingForPlayers"] = false GAMEOBJ:GetTimer():CancelAllTimers( self ) LOCALS["GameStarted"] = false -- iterate through players for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) if (player) then showSummaryDialog(self,player) RemovePlayerFromGame(self, player) -- -- unstun player because he is done with race -- player:RemoveStun -- { -- bCantMove = false, -- bCantTurn = false, -- bCantAttack = false, -- bCantEquip = false, -- bCantInteract = false -- } -- end end LOCALS["PlayerNum"] = 0 LOCALS["NumPlayersFinished"] = 0 end -------------------------------------------------------------- -- try to stop the game that hasn't started yet -------------------------------------------------------------- function AbortGame(self) print("Game Aborted") LOCALS["bWaitingForPlayers"] = false GAMEOBJ:GetTimer():CancelAllTimers( self ) LOCALS["GameStarted"] = false -- iterate through players for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) if (player) then RemovePlayerFromGame(self, player) player:ServerSetUserCtrlCompPause{bPaused = false} player:DisplayTooltip{ bShow = true, strText = "Game stopped, not enough players found.", iTime = 5000 } end end LOCALS["PlayerNum"] = 0 LOCALS["NumPlayersFinished"] = 0 end -------------------------------------------------------------- -- Get cannon number from player id -------------------------------------------------------------- function GetCannonNumFromPlayer(self, player) if (player) then local playerID = player:GetID() -- loop through cannons and find it for cnum = 1, #CANNONS do if (CANNONS[cnum]["Player"] == playerID) then return cnum end end end return 0 end -------------------------------------------------------------- -- Get cannon number from cannon id -------------------------------------------------------------- function GetCannonNumFromCannon(self, cannon) if (cannon) then local cannonID = cannon:GetID() -- loop through cannons and find it for cnum = 1, #CANNONS do if (CANNONS[cnum]["Cannon"] == cannonID) then return cnum end end end return 0 end -------------------------------------------------------------- -- Remove player from cannon -------------------------------------------------------------- function RemovePlayerFromCannon(self, player) if (player) then local cannonNum = GetCannonNumFromPlayer(self,player) if (cannonNum > 0) then CANNONS[cannonNum]["Player"] = 0 self:PlayerLoaded{ playerID = player } player:SetFaction{ faction = 1 } --player:ServerSetUserCtrlCompPause{bPaused = false} end end end -------------------------------------------------------------- -- Game Message Handlers -------------------------------------------------------------- -------------------------------------------------------------- -- Startup -------------------------------------------------------------- function onStartup(self) -- set game state LOCALS["PlayerNum"] = 0 LOCALS["NumPlayersFinished"] = 0 LOCALS["CheckpointNum"] = 0 LOCALS["CannonNum"] = 0 LOCALS["GameStarted"] = false end -------------------------------------------------------------- -- Timers -------------------------------------------------------------- onTimerDone = function(self, msg) if (msg.name == "StartGame") then StartGame(self) end if (msg.name == "TimeOut") then AbortGame(self) end if (msg.name == "EndGame") then StopGame(self) end if (string.starts(msg.name,"RemovePlayerFromCannon")) then local numPlayers = #PLAYERS_TO_REMOVE if (numPlayers > 0) then local player = GAMEOBJ:GetObjectByID(PLAYERS_TO_REMOVE[numPlayers]) if (player) then PLAYERS_TO_REMOVE[numPlayers] = nil -- remove the player from the cannon RemovePlayerFromCannon(self,player) end end end if (msg.name == "Go") then -- iterate through players for pnum = 1, #PLAYERS do local player = GAMEOBJ:GetObjectByID(PLAYERS[pnum]) local playerData = self:GetVar(PLAYERS[pnum]) if (player and playerData) then -- get start time local theTime = GAMEOBJ:GetSystemTime() -- set times in data playerData["startTime"] = theTime playerData["curLapTime"] = theTime self:SetVar(PLAYERS[pnum], playerData) -- unpause player:ServerSetUserCtrlCompPause{bPaused = false} end end end end -------------------------------------------------------------- -- Called when Player Loads into Zone -------------------------------------------------------------- function onPlayerLoaded(self, msg) print ("Player Entered: " .. msg.playerID:GetName().name) local player = msg.playerID -- move player to level start location -- @TODO: Sometimes this teleport works and sometimes it does not..... player:Teleport{pos = CONSTANTS["PLAYER_ZONEIN_POS"], bSetRotation = false} player:SetRacingParameters{ fTurnSpeedMult = CONSTANTS["TURN_SPEED_MULT"] } -- unpause player player:ServerSetUserCtrlCompPause{bPaused = false} -- remove all current boards RemoveBoardsFromPlayer(self, player) end -------------------------------------------------------------- -- Sent from an object after loading into zone -------------------------------------------------------------- function onObjectLoaded(self, msg) -- checkpoint Loaded if (msg.templateID == CONSTANTS["CHECKPOINT_LOT"]) then -- store it local chkpNum = IncrementVarAndReturn("CheckpointNum") CHECKPOINTS[chkpNum] = msg.objectID:GetID() -- update constant CONSTANTS["NUM_CHECKPOINTS"] = #CHECKPOINTS end if (msg.templateID == CONSTANTS["CANNON_TEMPLATEID"]) then print ("cannon added") -- Override the cannon shooting parameters msg.objectID:SetVar("ImpactSkillID",CONSTANTS["CANNON_IMPACT_SKILL"]) msg.objectID:SetShootingGalleryParams{playerPosOffset = CONSTANTS["CANNON_PLAYER_OFFSET"], projectileVelocity = CONSTANTS["CANNON_VELOCITY"], cooldown = CONSTANTS["CANNON_REFIRE_RATE"], muzzlePosOffset = CONSTANTS["CANNON_BARREL_OFFSET"], minDistance = CONSTANTS["CANNON_MIN_DISTANCE"], timeLimit = CONSTANTS["CANNON_TIMEOUT"]} -- store it local chkpNum = IncrementVarAndReturn("CannonNum") local CannonData = {} CannonData["Cannon"] = msg.objectID:GetID() CannonData["Player"] = 0 CANNONS[chkpNum] = CannonData -- update constant CONSTANTS["NUM_CANNONS"] = #CANNONS end end -------------------------------------------------------------- -- Sent from a player when responding from a messagebox -------------------------------------------------------------- function onMessageBoxRespond(self, msg) -- get player local player = msg.sender -- cancel the missions on the player for now player:CancelMission{ missionID = CONSTANTS["RACE_MISSION_ID"] } player:CancelMission{ missionID = CONSTANTS["CANNON_MISSION_ID"] } -- User wants to retry or start new race if ((msg.iButton == 1 and msg.identifier == "Racing_Summary") or (msg.iButton == 1 and msg.identifier == "Race_Mission")) then print("trigger restart") if (IsGameStarted(self)) then print("ERROR: game is not over yet!") player:DisplayTooltip{ bShow = true, strText = "The race is still running, try again after the race is over.", iTime = 5000 } player:ServerSetUserCtrlCompPause{bPaused = false} return end -- get current players local curplayers = LOCALS["PlayerNum"] if (tonumber(curplayers) < CONSTANTS["MAX_PLAYERS"]) then -- get the player Data local playerData = self:GetVar(player:GetID()) -- store the *new* player data for later use if (not playerData) then AddNewPlayerToGame(self, player) -- we used to be a player so we have player data but -- it should contain nothing elseif (not playerData["ShouldBeEmpty"]) then AddNewPlayerToGame(self, player) else print("ERROR: Player already exists in game!") end else player:DisplayTooltip{ bShow = true, strText = "The race is full, try again after the race is over.", iTime = 5000 } end -- User wants to quit Racing elseif (msg.iButton == 0 and msg.identifier == "Racing_Summary") then print("trigger leave") -- unpause player player:ServerSetUserCtrlCompPause{bPaused = false} -- User wants to shoot cannons elseif (msg.iButton == 1 and msg.identifier == "Race_Cannon_Mission") then print("cannon trigger") -- find an unused cannon local cannonID = GetValidCannon(self) -- no cannons available if (tonumber(cannonID) <= 0) then player:DisplayTooltip{ bShow = true, strText = "All cannons are full, try again later.", iTime= 5000 } print ("no cannons found") return end -- pause player player:ServerSetUserCtrlCompPause{bPaused = true} -- setup cannon vars local cannon = GAMEOBJ:GetObjectByID(cannonID) local cannonNum = GetCannonNumFromCannon(self, cannon) CANNONS[cannonNum]["Player"] = player:GetID() player:SetFaction{ faction = 2 } -- put the player in the cannon cannon:RequestActivityEnter{bStart = true, userID = player} end end -------------------------------------------------------------- -- Sent from checkpoints when a player passes them -------------------------------------------------------------- function onCollision(self, msg) FlagCheckpoint(self, msg.objectID, msg.senderID:GetID()) end -------------------------------------------------------------- -- Sent from goals when a player passes them -------------------------------------------------------------- function onOffCollision(self, msg) FlagLap(self, msg.objectID) end -------------------------------------------------------------- -- Sent from the cannon when a player starts or stops the cannon -------------------------------------------------------------- function onRequestActivityExit(self, msg) -- if the user quit, port him back -- store the player for transport at the end of the timer local numPlayers = #PLAYERS_TO_REMOVE + 1 PLAYERS_TO_REMOVE[numPlayers] = msg.userID:GetID() -- start timer for game start GAMEOBJ:GetTimer():AddTimerWithCancel( 2.0, "RemovePlayerFromCannon" .. msg.userID:GetID(), self ) end