Guest User

Untitled

a guest
Sep 7th, 2013
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 46.55 KB | None | 0 0
  1. g_Root = getRootElement()
  2. g_ResRoot = getResourceRootElement(getThisResource())
  3. g_Me = getLocalPlayer()
  4. g_ArmedVehicleIDs = table.create({ 425, 447, 520, 430, 464, 432 }, true)
  5. g_WaterCraftIDs = table.create({ 539, 460, 417, 447, 472, 473, 493, 595, 484, 430, 453, 452, 446, 454 }, true)
  6. g_ModelForPickupType = { nitro = 2221, repair = 2222, vehiclechange = 2223 }
  7. g_HunterID = 425
  8.  
  9. g_Checkpoints = {}
  10. g_Pickups = {}
  11. g_VisiblePickups = {}
  12. g_Objects = {}
  13.  
  14. addEventHandler('onClientResourceStart', g_ResRoot,
  15.     function()
  16.         g_Players = getElementsByType('player')
  17.        
  18.         fadeCamera(false,0.0)
  19.         -- create GUI
  20.         local screenWidth, screenHeight = guiGetScreenSize()
  21.         g_dxGUI = {
  22.             --ranknum = dxText:create('1', screenWidth - 60, screenHeight - 95, false, 'bankgothic', 2, 'right'),
  23.             --ranksuffix = dxText:create('st', screenWidth - 40, screenHeight - 86, false, 'bankgothic', 1),
  24.             checkpoint = dxText:create('0/0', screenWidth - 15, screenHeight - 54, false, 'bankgothic', 0.8, 'right'),
  25.             --timepassed = dxText:create('0:00:00', screenWidth - 10, screenHeight - 25, false, 'bankgothic', 0.7, 'right'),
  26.             mapdisplay = dxText:create('Map: none', 2, screenHeight - dxGetFontHeight(0.7, 'bankgothic')/2, false, 'bankgothic', 0.7, 'left')
  27.         }
  28.         --g_dxGUI.ranknum:type('stroke', 2, 0, 0, 0, 255)
  29.         g_dxGUI.ranksuffix:type('stroke', 2, 0, 0, 0, 255)
  30.         g_dxGUI.checkpoint:type('stroke', 1, 0, 0, 0, 255)
  31.         --g_dxGUI.timepassed:type('stroke', 1, 0, 0, 0, 255)
  32.         g_GUI = {
  33.             timeleftbg = guiCreateStaticImage(screenWidth/2-108/2, 15, 108, 24, 'img/timeleft.png', false, nil),
  34.             timeleft = guiCreateLabel(screenWidth/2-108/2, 19, 108, 30, '', false),
  35.             --healthbar = FancyProgress.create(250, 1000, 'img/progress_health_bg.png', -65, 60, 123, 30, 'img/progress_health.png', 8, 8, 108, 15),
  36.             --speedbar = FancyProgress.create(0, 1.5, 'img/progress_speed_bg.png', -65, 90, 123, 30, 'img/progress_speed.png', 8, 8, 108, 15),
  37.         }
  38.         guiSetFont(g_GUI.timeleft, 'default-bold-small')
  39.         guiLabelSetHorizontalAlign(g_GUI.timeleft, 'center')
  40.         --g_GUI.speedbar:setProgress(0)
  41.        
  42.         hideGUIComponents('timeleftbg', 'timeleft', 'checkpoint')
  43.         RankingBoard.precreateLabels(10)
  44.        
  45.         -- set update handlers
  46.         g_PickupStartTick = getTickCount()
  47.         --addEventHandler('onClientRender', g_Root, updateBars)
  48.         g_WaterCheckTimer = setTimer(checkWater, 1000, 0)
  49.        
  50.         -- load pickup models and textures
  51.         for name,id in pairs(g_ModelForPickupType) do
  52.             engineImportTXD(engineLoadTXD('model/' .. name .. '.txd'), id)
  53.             engineReplaceModel(engineLoadDFF('model/' .. name .. '.dff', id), id)
  54.             -- Double draw distance for pickups
  55.             engineSetModelLODDistance( id, 60 )
  56.         end
  57.  
  58.         if isVersion101Compatible() then
  59.             -- Dont clip vehicles (1.0.1 function)
  60.             setCameraClip ( true, false )
  61.         end
  62.  
  63.         -- Init presentation screens
  64.         TravelScreen.init()
  65.         TitleScreen.init()
  66.  
  67.         -- Show title screen now
  68.         TitleScreen.show()
  69.  
  70.         setPedCanBeKnockedOffBike(g_Me, false)
  71.     end
  72. )
  73.  
  74.  
  75. -------------------------------------------------------
  76. -- Title screen - Shown when player first joins the game
  77. -------------------------------------------------------
  78. TitleScreen = {}
  79. TitleScreen.startTime = 0
  80.  
  81. function TitleScreen.init()
  82.     local screenWidth, screenHeight = guiGetScreenSize()
  83.     local adjustY = math.clamp( -30, -15 + (-30- -15) * (screenHeight - 480)/(900 - 480), -15 );
  84.     g_GUI['titleImage'] = guiCreateStaticImage(screenWidth/2-256, screenHeight/2-256+adjustY, 512, 512, 'img/title.png', false)
  85.     g_dxGUI['titleText1'] = dxText:create('', 30, screenHeight-67, false, 'bankgothic', 0.70, 'left' )
  86.     g_dxGUI['titleText2'] = dxText:create('', 120, screenHeight-67, false, 'bankgothic', 0.70, 'left' )
  87.     g_dxGUI['titleText1']:text( 'KEYS: \n' ..
  88.                                 'F4 \n' ..
  89.                                 'F5 \n' ..
  90.                                 'ENTER' )
  91.     g_dxGUI['titleText2']:text( '\n' ..
  92.                                 '- TRAFFIC ARROWS \n' ..
  93.                                 '- TOP TIMES \n' ..
  94.                                 '- RETRY' )
  95.     hideGUIComponents('titleImage','titleText1','titleText2')
  96. end
  97.  
  98. function TitleScreen.show()
  99.     showGUIComponents('titleImage','titleText1','titleText2')
  100.     guiMoveToBack(g_GUI['titleImage'])
  101.     TitleScreen.startTime = getTickCount()
  102.     TitleScreen.bringForward = 0
  103.     addEventHandler('onClientRender', g_Root, TitleScreen.update)
  104. end
  105.  
  106. function TitleScreen.update()
  107.     local secondsLeft = TitleScreen.getTicksRemaining() / 1000
  108.     local alpha = math.min(1,math.max( secondsLeft ,0))
  109.     guiSetAlpha(g_GUI['titleImage'], alpha)
  110.     g_dxGUI['titleText1']:color(220,220,220,255*alpha)
  111.     g_dxGUI['titleText2']:color(220,220,220,255*alpha)
  112.     if alpha == 0 then
  113.         hideGUIComponents('titleImage','titleText1','titleText2')
  114.         removeEventHandler('onClientRender', g_Root, TitleScreen.update)
  115.     end
  116. end
  117.  
  118. function TitleScreen.getTicksRemaining()
  119.     return math.max( 0, TitleScreen.startTime - TitleScreen.bringForward + 10000 - getTickCount() )
  120. end
  121.  
  122. -- Start the fadeout as soon as possible
  123. function TitleScreen.bringForwardFadeout(maxSkip)
  124.     local ticksLeft = TitleScreen.getTicksRemaining()
  125.     local bringForward = ticksLeft - 1000
  126.     outputDebug( 'MISC', 'bringForward ' .. bringForward )
  127.     if bringForward > 0 then
  128.         TitleScreen.bringForward = math.min(TitleScreen.bringForward + bringForward,maxSkip)
  129.         outputDebug( 'MISC', 'TitleScreen.bringForward ' .. TitleScreen.bringForward )
  130.     end
  131. end
  132. -------------------------------------------------------
  133.  
  134.  
  135. -------------------------------------------------------
  136. -- Travel screen - Message for client feedback when loading maps
  137. -------------------------------------------------------
  138. TravelScreen = {}
  139. TravelScreen.startTime = 0
  140.  
  141. function TravelScreen.init()
  142.     local screenWidth, screenHeight = guiGetScreenSize()
  143.     g_GUI['travelImage']   = guiCreateStaticImage(screenWidth/2-256, screenHeight/2-90, 512, 256, 'img/travelling.png', false, nil)
  144.     g_dxGUI['travelText1'] = dxText:create('Travelling to', screenWidth/2, screenHeight/2-130, false, 'bankgothic', 0.60, 'center' )
  145.     g_dxGUI['travelText2'] = dxText:create('', screenWidth/2, screenHeight/2-100, false, 'bankgothic', 0.70, 'center' )
  146.     g_dxGUI['travelText3'] = dxText:create('', screenWidth/2, screenHeight/2-70, false, 'bankgothic', 0.70, 'center' )
  147.     g_dxGUI['travelText1']:color(240,240,240)
  148.     hideGUIComponents('travelImage', 'travelText1', 'travelText2', 'travelText3')
  149. end
  150.  
  151. function TravelScreen.show( mapName, authorName )
  152.     TravelScreen.startTime = getTickCount()
  153.     g_dxGUI['travelText2']:text(mapName)
  154.     g_dxGUI['travelText3']:text(authorName and "Author: " .. authorName or "")
  155.     showGUIComponents('travelImage', 'travelText1', 'travelText2', 'travelText3')
  156.     guiMoveToBack(g_GUI['travelImage'])
  157. end
  158.  
  159. function TravelScreen.hide()
  160.     hideGUIComponents('travelImage', 'travelText1', 'travelText2', 'travelText3')
  161. end
  162.  
  163. function TravelScreen.getTicksRemaining()
  164.     return math.max( 0, TravelScreen.startTime + 3000 - getTickCount() )
  165. end
  166. -------------------------------------------------------
  167.  
  168.  
  169. -- Called from server
  170. function notifyLoadingMap( mapName, authorName )
  171.     fadeCamera( false, 0.0, 0,0,0 ) -- fadeout, instant, black
  172.     TravelScreen.show( mapName, authorName )
  173. end
  174.  
  175.  
  176. -- Called from server
  177. function initRace(vehicle, checkpoints, objects, pickups, mapoptions, ranked, duration, gameoptions, mapinfo, playerInfo)
  178.     outputDebug( 'MISC', 'initRace start' )
  179.     unloadAll()
  180.    
  181.     g_Players = getElementsByType('player')
  182.     g_MapOptions = mapoptions
  183.     g_GameOptions = gameoptions
  184.     g_MapInfo = mapinfo
  185.     g_PlayerInfo = playerInfo
  186.     triggerEvent('onClientMapStarting', g_Me, mapinfo )
  187.    
  188.     g_dxGUI.mapdisplay:text("Map: "..g_MapInfo.name)
  189.    
  190.     fadeCamera(true)
  191.     showHUD(false)
  192.    
  193.     g_Vehicle = vehicle
  194.     setVehicleDamageProof(g_Vehicle, true)
  195.     OverrideClient.updateVars(g_Vehicle)
  196.    
  197.     --local x, y, z = getElementPosition(g_Vehicle)
  198.     setCameraBehindVehicle(vehicle)
  199.     --alignVehicleToGround(vehicle)
  200.     updateVehicleWeapons()
  201.     setCloudsEnabled(g_GameOptions.cloudsenable)
  202.     setBlurLevel(g_GameOptions.blurlevel)
  203.     g_dxGUI.mapdisplay:visible(g_GameOptions.showmapname)
  204.     if engineSetAsynchronousLoading then
  205.         engineSetAsynchronousLoading( g_GameOptions.asyncloading )
  206.     end
  207.  
  208.     -- checkpoints
  209.     g_Checkpoints = checkpoints
  210.    
  211.     -- pickups
  212.     local object
  213.     local pos
  214.     local colshape
  215.     for i,pickup in pairs(pickups) do
  216.         pos = pickup.position
  217.         object = createObject(g_ModelForPickupType[pickup.type], pos[1], pos[2], pos[3])
  218.         setElementCollisionsEnabled(object, false)
  219.         colshape = createColSphere(pos[1], pos[2], pos[3], 3.5)
  220.         g_Pickups[colshape] = { object = object }
  221.         for k,v in pairs(pickup) do
  222.             g_Pickups[colshape][k] = v
  223.         end
  224.         g_Pickups[colshape].load = true
  225.         if g_Pickups[colshape].type == 'vehiclechange' then
  226.             g_Pickups[colshape].label = dxText:create(getVehicleNameFromModel(g_Pickups[colshape].vehicle), 0.5, 0.5)
  227.             g_Pickups[colshape].label:color(255, 255, 255, 0)
  228.             g_Pickups[colshape].label:type("shadow",2)
  229.         end
  230.     end
  231.    
  232.     -- objects
  233.     g_Objects = {}
  234.     local pos, rot
  235.     for i,object in ipairs(objects) do
  236.         pos = object.position
  237.         rot = object.rotation
  238.         g_Objects[i] = createObject(object.model, pos[1], pos[2], pos[3], rot[1], rot[2], rot[3])
  239.     end
  240.  
  241.     if #g_Checkpoints > 0 then
  242.         g_CurrentCheckpoint = 0
  243.         showNextCheckpoint()
  244.     end
  245.    
  246.     -- GUI
  247.     --g_dxGUI.timepassed:text('0:00:00')
  248.     --showGUIComponents('timepassed')
  249.     hideGUIComponents('timeleftbg', 'timeleft')
  250.     if ranked then
  251.         --showGUIComponents('ranknum', 'ranksuffix')
  252.     else
  253.         --hideGUIComponents('ranknum', 'ranksuffix')
  254.     end
  255.     if #g_Checkpoints > 0 then
  256.         showGUIComponents('checkpoint')
  257.     else
  258.         hideGUIComponents('checkpoint')
  259.     end
  260.    
  261.     g_HurryDuration = g_GameOptions.hurrytime
  262.     if duration then
  263.         launchRace(duration)
  264.     end
  265.  
  266.     fadeCamera( false, 0.0 )
  267.  
  268.     -- Editor start
  269.     if isEditor() then
  270.         editorInitRace()
  271.         return
  272.     end
  273.  
  274.     -- Min 3 seconds on travel message
  275.     local delay = TravelScreen.getTicksRemaining()
  276.     delay = math.max(50,delay)
  277.     setTimer(TravelScreen.hide,delay,1)
  278.  
  279.     -- Delay readyness until after title
  280.     TitleScreen.bringForwardFadeout(3000)
  281.     delay = delay + math.max( 0, TitleScreen.getTicksRemaining() - 1500 )
  282.  
  283.     -- Do fadeup and then tell server client is ready
  284.     setTimer(fadeCamera, delay + 750, 1, true, 10.0)
  285.     setTimer(fadeCamera, delay + 1500, 1, true, 2.0)
  286.  
  287.     setTimer( function() triggerServerEvent('onNotifyPlayerReady', g_Me) end, delay + 3500, 1 )
  288.     outputDebug( 'MISC', 'initRace end' )
  289.     setTimer( function() setCameraBehindVehicle( g_Vehicle ) end, delay + 300, 1 )
  290. end
  291.  
  292. -- Called from the server when settings are changed
  293. function updateOptions ( gameoptions, mapoptions )
  294.     -- Update
  295.     g_GameOptions = gameoptions
  296.     g_MapOptions = mapoptions
  297.  
  298.     -- Apply
  299.     updateVehicleWeapons()
  300.     setCloudsEnabled(g_GameOptions.cloudsenable)
  301.     setBlurLevel(g_GameOptions.blurlevel)
  302.     g_dxGUI.mapdisplay:visible(g_GameOptions.showmapname)
  303.     if engineSetAsynchronousLoading then
  304.         engineSetAsynchronousLoading( g_GameOptions.asyncloading )
  305.     end
  306. end
  307.  
  308. function launchRace(duration)
  309.     g_Players = getElementsByType('player')
  310.    
  311.     if type(duration) == 'number' then
  312.         showGUIComponents('timeleftbg', 'timeleft')
  313.         guiLabelSetColor(g_GUI.timeleft, 255, 255, 255)
  314.         g_Duration = duration
  315.         addEventHandler('onClientRender', g_Root, updateTime)
  316.     end
  317.    
  318.     setVehicleDamageProof(g_Vehicle, false)
  319.    
  320.     g_StartTick = getTickCount()
  321. end
  322.  
  323.  
  324. addEventHandler('onClientElementStreamIn', g_Root,
  325.     function()
  326.         local colshape = table.find(g_Pickups, 'object', source)
  327.         if colshape then
  328.             local pickup = g_Pickups[colshape]
  329.             if pickup.label then
  330.                 pickup.label:color(255, 255, 255, 0)
  331.                 pickup.label:visible(false)
  332.                 pickup.labelInRange = false
  333.             end
  334.             g_VisiblePickups[colshape] = source
  335.         end
  336.     end
  337. )
  338.  
  339. addEventHandler('onClientElementStreamOut', g_Root,
  340.     function()
  341.         local colshape = table.find(g_VisiblePickups, source)
  342.         if colshape then
  343.             local pickup = g_Pickups[colshape]
  344.             if pickup.label then
  345.                 pickup.label:color(255, 255, 255, 0)
  346.                 pickup.label:visible(false)
  347.                 pickup.labelInRange = nil
  348.             end
  349.             g_VisiblePickups[colshape] = nil
  350.         end
  351.     end
  352. )
  353.  
  354. function updatePickups()
  355.     local angle = math.fmod((getTickCount() - g_PickupStartTick) * 360 / 2000, 360)
  356.     local g_Pickups = g_Pickups
  357.     local pickup, x, y, cX, cY, cZ, pickX, pickY, pickZ
  358.     for colshape,elem in pairs(g_VisiblePickups) do
  359.         pickup = g_Pickups[colshape]
  360.         if pickup.load then
  361.             setElementRotation(elem, 0, 0, angle)
  362.             if pickup.label then
  363.                 cX, cY, cZ = getCameraMatrix()
  364.                 pickX, pickY, pickZ = unpack(pickup.position)
  365.                 x, y = getScreenFromWorldPosition(pickX, pickY, pickZ + 2.85, 0.08 )
  366.                 local distanceToPickup = getDistanceBetweenPoints3D(cX, cY, cZ, pickX, pickY, pickZ)
  367.                 if distanceToPickup > 80 then
  368.                     pickup.labelInRange = false
  369.                     pickup.label:visible(false)
  370.                 elseif x then
  371.                     if distanceToPickup < 60 then
  372.                         if isLineOfSightClear(cX, cY, cZ, pickX, pickY, pickZ, true, false, false, true, false) then
  373.                             if not pickup.labelInRange then
  374.                                 if pickup.anim then
  375.                                     pickup.anim:remove()
  376.                                 end
  377.                                 pickup.anim = Animation.createAndPlay(
  378.                                     pickup.label,
  379.                                     Animation.presets.dxTextFadeIn(500)
  380.                                 )
  381.                                 pickup.labelInRange = true
  382.                                 pickup.labelVisible = true
  383.                             end
  384.                             if not pickup.labelVisible then
  385.                                 pickup.label:color(255, 255, 255, 255)
  386.                             end
  387.                             pickup.label:visible(true)
  388.                         else
  389.                             pickup.label:color(255, 255, 255, 0)
  390.                             pickup.labelVisible = false
  391.                             pickup.label:visible(false)
  392.                         end
  393.                     else
  394.                         if pickup.labelInRange then
  395.                             if pickup.anim then
  396.                                 pickup.anim:remove()
  397.                             end
  398.                             pickup.anim = Animation.createAndPlay(
  399.                                 pickup.label,
  400.                                 Animation.presets.dxTextFadeOut(1000)
  401.                             )
  402.                             pickup.labelInRange = false
  403.                             pickup.labelVisible = false
  404.                             pickup.label:visible(true)
  405.                         end
  406.                     end
  407.                     local scale = (60/distanceToPickup)*0.7
  408.                     pickup.label:scale(scale)
  409.                     pickup.label:position(x, y, false)
  410.                 else
  411.                     pickup.label:color(255, 255, 255, 0)
  412.                     pickup.labelVisible = false
  413.                     pickup.label:visible(false)
  414.                 end
  415.                 if Spectate.fadedout then
  416.                     pickup.label:visible(false) -- Hide pickup labels when screen is black
  417.                 end
  418.             end
  419.         else
  420.             if pickup.label then
  421.                 pickup.label:visible(false)
  422.                 if pickup.labelInRange then
  423.                     pickup.label:color(255, 255, 255, 0)
  424.                     pickup.labelInRange = false
  425.                 end
  426.             end
  427.         end
  428.     end
  429. end
  430. addEventHandler('onClientRender', g_Root, updatePickups)
  431.  
  432. addEventHandler('onClientColShapeHit', g_Root,
  433.     function(elem)
  434.         local pickup = g_Pickups[source]
  435.         outputDebug( 'CHECKPOINT', 'onClientColShapeHit'
  436.                         .. ' elem:' .. tostring(elem)
  437.                         .. ' g_Vehicle:' .. tostring(g_Vehicle)
  438.                         .. ' isVehicleBlown(g_Vehicle):' .. tostring(isVehicleBlown(g_Vehicle))
  439.                         .. ' g_Me:' .. tostring(g_Me)
  440.                         .. ' getElementHealth(g_Me):' .. tostring(getElementHealth(g_Me))
  441.                         .. ' source:' .. tostring(source)
  442.                         .. ' pickup:' .. tostring(pickup)
  443.                         )
  444.         if elem ~= g_Vehicle or not pickup or isVehicleBlown(g_Vehicle) or getElementHealth(g_Me) == 0 then
  445.             return
  446.         end
  447.         if pickup.load then
  448.             handleHitPickup(pickup)
  449.         end
  450.     end
  451. )
  452.  
  453. function handleHitPickup(pickup)
  454.     if pickup.type == 'vehiclechange' then
  455.         if pickup.vehicle == getElementModel(g_Vehicle) then
  456.             return
  457.         end
  458.         local health = nil
  459.         g_PrevVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  460.         alignVehicleWithUp()
  461.         if checkModelIsAirplane(pickup.vehicle) then -- Hack fix for Issue #4104
  462.             health = getElementHealth(g_Vehicle)
  463.         end
  464.         setElementModel(g_Vehicle, pickup.vehicle)
  465.         if health then
  466.             fixVehicle(g_Vehicle)
  467.             setElementHealth(g_Vehicle, health)
  468.         end
  469.         vehicleChanging(g_MapOptions.classicchangez, pickup.vehicle)
  470.     elseif pickup.type == 'nitro' then
  471.         addVehicleUpgrade(g_Vehicle, 1010)
  472.     elseif pickup.type == 'repair' then
  473.         fixVehicle(g_Vehicle)
  474.     end
  475.     triggerServerEvent('onPlayerPickUpRacePickupInternal', g_Me, pickup.id, pickup.respawn)
  476.     playSoundFrontEnd(46)
  477. end
  478.  
  479. function removeVehicleNitro()
  480.     removeVehicleUpgrade(g_Vehicle, 1010)
  481. end
  482.  
  483. function unloadPickup(pickupID)
  484.     for colshape,pickup in pairs(g_Pickups) do
  485.         if pickup.id == pickupID then
  486.             pickup.load = false
  487.             setElementAlpha(pickup.object, 0)
  488.             return
  489.         end
  490.     end
  491. end
  492.  
  493. function loadPickup(pickupID)
  494.     for colshape,pickup in pairs(g_Pickups) do
  495.         if pickup.id == pickupID then
  496.             setElementAlpha(pickup.object, 255)
  497.             pickup.load = true
  498.             if isElementWithinColShape(g_Vehicle, colshape) then
  499.                 handleHitPickup(pickup)
  500.             end
  501.             return
  502.         end
  503.     end
  504. end
  505.  
  506. function vehicleChanging( changez, newModel )
  507.     if getElementModel(g_Vehicle) ~= newModel then
  508.         outputConsole( "Vehicle change model mismatch (" .. tostring(getElementModel(g_Vehicle)) .. "/" .. tostring(newModel) .. ")" )
  509.     end
  510.     local newVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  511.     local x, y, z = getElementPosition(g_Vehicle)
  512.     if g_PrevVehicleHeight and newVehicleHeight > g_PrevVehicleHeight then
  513.         z = z - g_PrevVehicleHeight + newVehicleHeight
  514.     end
  515.     if changez then
  516.         z = z + 1
  517.     end
  518.     setElementPosition(g_Vehicle, x, y, z)
  519.     g_PrevVehicleHeight = nil
  520.     updateVehicleWeapons()
  521.     checkVehicleIsHelicopter()
  522. end
  523.  
  524. function updateVehicleWeapons()
  525.     if g_Vehicle then
  526.         local weapons = not g_ArmedVehicleIDs[getElementModel(g_Vehicle)] or g_MapOptions.vehicleweapons
  527.         toggleControl('vehicle_fire', weapons)
  528.         if getElementModel(g_Vehicle) == g_HunterID and not g_MapOptions.hunterminigun then
  529.             weapons = false
  530.         end
  531.         toggleControl('vehicle_secondary_fire', weapons)
  532.     end
  533. end
  534.  
  535. function vehicleUnloading()
  536.     g_Vehicle = nil
  537. end
  538.  
  539. function updateBars()
  540.     if g_Vehicle then
  541.         g_GUI.healthbar:setProgress(getElementHealth(g_Vehicle))
  542.         local vx, vy, vz = getElementVelocity(g_Vehicle)
  543.         g_GUI.speedbar:setProgress(math.sqrt(vx*vx + vy*vy + vz*vz))
  544.     end
  545. end
  546.  
  547. function updateTime()
  548.     local tick = getTickCount()
  549.     local msPassed = tick - g_StartTick
  550.     if not isPlayerFinished(g_Me) then
  551.         --g_dxGUI.timepassed:text(msToTimeStr(msPassed))
  552.     end
  553.     local timeLeft = g_Duration - msPassed
  554.     guiSetText(g_GUI.timeleft, msToTimeStr(timeLeft > 0 and timeLeft or 0))
  555.     if g_HurryDuration and g_GUI.hurry == nil and timeLeft <= g_HurryDuration then
  556.         startHurry()
  557.     end
  558. end
  559.  
  560. addEventHandler('onClientElementDataChange', g_Me,
  561.     function(dataName)
  562.         if dataName == 'race rank' and not Spectate.active then
  563.             --setRankDisplay( getElementData(g_Me, 'race rank') )
  564.         end
  565.     end,
  566.     false
  567. )
  568.  
  569. function setRankDisplay( rank )
  570.     if not tonumber(rank) then
  571.         g_dxGUI.ranknum:text('')
  572.         g_dxGUI.ranksuffix:text('')
  573.         return
  574.     end
  575.     g_dxGUI.ranknum:text(tostring(rank))
  576.     g_dxGUI.ranksuffix:text( (rank < 10 or rank > 20) and ({ [1] = 'st', [2] = 'nd', [3] = 'rd' })[rank % 10] or 'th' )
  577. end
  578.  
  579.  
  580. addEventHandler('onClientElementDataChange', g_Root,
  581.     function(dataName)
  582.         if dataName == 'race.finished' then
  583.             if isPlayerFinished(source) then
  584.                 Spectate.dropCamera( source, 2000 )
  585.             end
  586.         end
  587.         if dataName == 'race.spectating' then
  588.             if isPlayerSpectating(source) then
  589.                 Spectate.validateTarget( source )   -- No spectate at this player
  590.             end
  591.         end
  592.     end
  593. )
  594.  
  595.  
  596. function checkWater()
  597.     if g_Vehicle then
  598.         if not g_WaterCraftIDs[getElementModel(g_Vehicle)] then
  599.             local x, y, z = getElementPosition(g_Me)
  600.             local waterZ = getWaterLevel(x, y, z)
  601.             if waterZ and z < waterZ - 0.5 and not isPlayerRaceDead(g_Me) and not isPlayerFinished(g_Me) and g_MapOptions then
  602.                 if g_MapOptions.firewater then
  603.                     blowVehicle ( g_Vehicle, true )
  604.                 else
  605.                     setElementHealth(g_Me,0)
  606.                     triggerServerEvent('onRequestKillPlayer',g_Me)
  607.                 end
  608.             end
  609.         end
  610.         -- Check stalled vehicle
  611.         if not getVehicleEngineState( g_Vehicle ) then
  612.             setVehicleEngineState( g_Vehicle, true )
  613.         end
  614.         -- Check dead vehicle
  615.         if getElementHealth( g_Vehicle ) == 0 and not isPlayerRaceDead(g_Me) and not isPlayerFinished(g_Me)then
  616.             setElementHealth(g_Me,0)
  617.             triggerServerEvent('onRequestKillPlayer',g_Me)
  618.         end
  619.     end
  620. end
  621.  
  622. function showNextCheckpoint(bOtherPlayer)
  623.     g_CurrentCheckpoint = g_CurrentCheckpoint + 1
  624.     local i = g_CurrentCheckpoint
  625.     g_dxGUI.checkpoint:text((i - 1) .. ' / ' .. #g_Checkpoints)
  626.     if i > 1 then
  627.         destroyCheckpoint(i-1)
  628.     else
  629.         createCheckpoint(1)
  630.     end
  631.     makeCheckpointCurrent(i,bOtherPlayer)
  632.     if i < #g_Checkpoints then
  633.         local curCheckpoint = g_Checkpoints[i]
  634.         local nextCheckpoint = g_Checkpoints[i+1]
  635.         local nextMarker = createCheckpoint(i+1)
  636.         setMarkerTarget(curCheckpoint.marker, unpack(nextCheckpoint.position))
  637.     end
  638.     if not Spectate.active then
  639.         setElementData(g_Me, 'race.checkpoint', i)
  640.     end
  641. end
  642.  
  643. -------------------------------------------------------------------------------
  644. -- Show checkpoints and rank info that is relevant to the player being spectated
  645. local prevWhich = nil
  646. local cpValuePrev = nil
  647. local rankValuePrev = nil
  648.  
  649. function updateSpectatingCheckpointsAndRank()
  650.     local which = getWhichDataSourceToUse()
  651.  
  652.     -- Do nothing if we are keeping the last thing displayed
  653.     if which == "keeplast" then
  654.         return
  655.     end
  656.  
  657.     local dataSourceChangedToLocal = which ~= prevWhich and which=="local"
  658.     local dataSourceChangedFromLocal = which ~= prevWhich and prevWhich=="local"
  659.     prevWhich = which
  660.  
  661.     if dataSourceChangedFromLocal or dataSourceChangedToLocal then
  662.         cpValuePrev = nil
  663.         rankValuePrev = nil
  664.     end
  665.  
  666.     if Spectate.active or dataSourceChangedToLocal then
  667.         local watchedPlayer = getWatchedPlayer()
  668.  
  669.         if g_CurrentCheckpoint and g_Checkpoints and #g_Checkpoints > 0 then
  670.             local cpValue = getElementData(watchedPlayer, 'race.checkpoint') or 0
  671.             if cpValue > 0 and cpValue <= #g_Checkpoints then
  672.                 if cpValue ~= cpValuePrev then
  673.                     cpValuePrev = cpValue
  674.                     setCurrentCheckpoint( cpValue, Spectate.active and watchedPlayer ~= g_Me )
  675.                 end
  676.             end
  677.         end
  678.  
  679.         local rankValue = getElementData(watchedPlayer, 'race rank') or 0
  680.         if rankValue ~= rankValuePrev then
  681.             rankValuePrev = rankValue
  682.             --setRankDisplay( rankValue )  
  683.         end
  684.     end
  685. end
  686.  
  687. -- "local"          If not spectating
  688. -- "spectarget"     If spectating valid target
  689. -- "keeplast"       If spectating nil target and dropcam
  690. -- "local"          If spectating nil target and no dropcam
  691. function getWhichDataSourceToUse()
  692.     if not Spectate.active          then    return "local"          end
  693.     if Spectate.target              then    return "spectarget"     end
  694.     if Spectate.hasDroppedCamera()  then    return "keeplast"       end
  695.     return "local"
  696. end
  697.  
  698. function getWatchedPlayer()
  699.     if not Spectate.active          then    return g_Me             end
  700.     if Spectate.target              then    return Spectate.target  end
  701.     if Spectate.hasDroppedCamera()  then    return nil              end
  702.     return g_Me
  703. end
  704. -------------------------------------------------------------------------------
  705.  
  706. function checkpointReached(elem)
  707.     outputDebug( 'CP', 'checkpointReached'
  708.                     .. ' ' .. tostring(g_CurrentCheckpoint)
  709.                     .. ' elem:' .. tostring(elem)
  710.                     .. ' g_Vehicle:' .. tostring(g_Vehicle)
  711.                     .. ' isVehicleBlown(g_Vehicle):' .. tostring(isVehicleBlown(g_Vehicle))
  712.                     .. ' g_Me:' .. tostring(g_Me)
  713.                     .. ' getElementHealth(g_Me):' .. tostring(getElementHealth(g_Me))
  714.                     )
  715.     if elem ~= g_Vehicle or isVehicleBlown(g_Vehicle) or getElementHealth(g_Me) == 0 or Spectate.active then
  716.         return
  717.     end
  718.    
  719.     if g_Checkpoints[g_CurrentCheckpoint].vehicle and g_Checkpoints[g_CurrentCheckpoint].vehicle ~= getElementModel(g_Vehicle) then
  720.         g_PrevVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  721.         local health = nil
  722.         alignVehicleWithUp()
  723.         if checkModelIsAirplane(g_Checkpoints[g_CurrentCheckpoint].vehicle) then -- Hack fix for Issue #4104
  724.             health = getElementHealth(g_Vehicle)
  725.         end
  726.         setElementModel(g_Vehicle, g_Checkpoints[g_CurrentCheckpoint].vehicle)
  727.         if health then
  728.             fixVehicle(g_Vehicle)
  729.             setElementHealth(g_Vehicle, health)
  730.         end
  731.         vehicleChanging(g_MapOptions.classicchangez, g_Checkpoints[g_CurrentCheckpoint].vehicle)
  732.     end
  733.     triggerServerEvent('onPlayerReachCheckpointInternal', g_Me, g_CurrentCheckpoint)
  734.     playSoundFrontEnd(43)
  735.     if g_CurrentCheckpoint < #g_Checkpoints then
  736.         showNextCheckpoint()
  737.     else
  738.         g_dxGUI.checkpoint:text(#g_Checkpoints .. ' / ' .. #g_Checkpoints)
  739.         local rc = getRadioChannel()
  740.         setRadioChannel(0)
  741.         addEventHandler("onClientPlayerRadioSwitch", g_Root, onChange)
  742.         playSound("audio/mission_accomplished.mp3")
  743.         setTimer(changeRadioStation, 8000, 1, rc)
  744.         if g_GUI.hurry then
  745.             Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  746.             g_GUI.hurry = false
  747.         end
  748.         destroyCheckpoint(#g_Checkpoints)
  749.         triggerEvent('onClientPlayerFinish', g_Me)
  750.         toggleAllControls(false, true, false)
  751.     end
  752. end
  753.  
  754. function onChange()
  755.     cancelEvent()
  756. end
  757.  
  758. function changeRadioStation(rc)
  759.     removeEventHandler("onClientPlayerRadioSwitch", g_Root, onChange)
  760.     setRadioChannel(tonumber(rc))
  761. end
  762.  
  763. function startHurry()
  764.     if not isPlayerFinished(g_Me) then
  765.         local screenWidth, screenHeight = guiGetScreenSize()
  766.         local w, h = resAdjust(370), resAdjust(112)
  767.         g_GUI.hurry = guiCreateStaticImage(screenWidth/2 - w/2, screenHeight - h - 40, w, h, 'img/hurry.png', false, nil)
  768.         guiSetAlpha(g_GUI.hurry, 0)
  769.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeIn(800))
  770.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiPulse(1000))
  771.     end
  772.     guiLabelSetColor(g_GUI.timeleft, 255, 0, 0)
  773. end
  774.  
  775. function setTimeLeft(timeLeft)
  776.     g_Duration = (getTickCount() - g_StartTick) + timeLeft
  777. end
  778.  
  779. -----------------------------------------------------------------------
  780. -- Spectate
  781. -----------------------------------------------------------------------
  782. Spectate = {}
  783. Spectate.active = false
  784. Spectate.target = nil
  785. Spectate.blockUntilTimes = {}
  786. Spectate.savePos = false
  787. Spectate.manual = false
  788. Spectate.droppedCameraTimer = Timer:create()
  789. Spectate.tickTimer = Timer:create()
  790. Spectate.fadedout = true
  791. Spectate.blockManual = false
  792. Spectate.blockManualTimer = nil
  793.  
  794.  
  795. -- Request to switch on
  796. function Spectate.start(type)
  797.     outputDebug( 'SPECTATE', 'Spectate.start '..type )
  798.     assert(type=='manual' or type=='auto', "Spectate.start : type == auto or manual")
  799.     Spectate.blockManual = false
  800.     if type == 'manual' then
  801.         if Spectate.active then
  802.             return                  -- Ignore if manual request and already on
  803.         end
  804.         Spectate.savePos = true -- Savepos and start if manual request and was off
  805.     elseif type == 'auto' then
  806.         Spectate.savePos = false    -- Clear restore pos if an auto spectate is requested
  807.     end
  808.     if not Spectate.active then
  809.         Spectate._start()           -- Switch on here, if was off
  810.     end
  811. end
  812.  
  813.  
  814. -- Request to switch off
  815. function Spectate.stop(type)
  816.     outputDebug( 'SPECTATE', 'Spectate.stop '..type )
  817.     assert(type=='manual' or type=='auto', "Spectate.stop : type == auto or manual")
  818.     if type == 'auto' then
  819.         Spectate.savePos = false    -- Clear restore pos if an auto spectate is requested
  820.     end
  821.     if Spectate.active then
  822.         Spectate._stop()            -- Switch off here, if was on
  823.     end
  824. end
  825.  
  826.  
  827. function Spectate._start()
  828.     outputDebug( 'SPECTATE', 'Spectate._start ' )
  829.     triggerServerEvent('onClientNotifySpectate', g_Me, true )
  830.     assert(not Spectate.active, "Spectate._start - not Spectate.active")
  831.     local screenWidth, screenHeight = guiGetScreenSize()
  832.     g_GUI.specprev = guiCreateStaticImage(screenWidth/2 - 100 - 58, screenHeight - 123, 58, 82, 'img/specprev.png', false, nil)
  833.     g_GUI.specprevhi = guiCreateStaticImage(screenWidth/2 - 100 - 58, screenHeight - 123, 58, 82, 'img/specprev_hi.png', false, nil)
  834.     g_GUI.specnext = guiCreateStaticImage(screenWidth/2 + 100, screenHeight - 123, 58, 82, 'img/specnext.png', false, nil)
  835.     g_GUI.specnexthi = guiCreateStaticImage(screenWidth/2 + 100, screenHeight - 123, 58, 82, 'img/specnext_hi.png', false, nil)
  836.     g_GUI.speclabel = guiCreateLabel(screenWidth/2 - 100, screenHeight - 100, 200, 70, '', false)
  837.     Spectate.updateGuiFadedOut()
  838.     guiLabelSetHorizontalAlign(g_GUI.speclabel, 'center')
  839.     hideGUIComponents('specprevhi', 'specnexthi')
  840.     if Spectate.savePos then
  841.         savePosition()
  842.     end
  843.     Spectate.setTarget( Spectate.findNewTarget(g_Me,1) )
  844.     bindKey('arrow_l', 'down', Spectate.previous)
  845.     bindKey('arrow_r', 'down', Spectate.next)
  846.     MovePlayerAway.start()
  847.     Spectate.setTarget( Spectate.target )
  848.     Spectate.validateTarget(Spectate.target)
  849.     Spectate.tickTimer:setTimer( Spectate.tick, 500, 0 )
  850. end
  851.  
  852. -- Stop spectating. Will restore position if Spectate.savePos is set
  853. function Spectate._stop()
  854.     Spectate.cancelDropCamera()
  855.     Spectate.tickTimer:killTimer()
  856.     triggerServerEvent('onClientNotifySpectate', g_Me, false )
  857.     outputDebug( 'SPECTATE', 'Spectate._stop ' )
  858.     assert(Spectate.active, "Spectate._stop - Spectate.active")
  859.     for i,name in ipairs({'specprev', 'specprevhi', 'specnext', 'specnexthi', 'speclabel'}) do
  860.         if g_GUI[name] then
  861.             destroyElement(g_GUI[name])
  862.             g_GUI[name] = nil
  863.         end
  864.     end
  865.     unbindKey('arrow_l', 'down', Spectate.previous)
  866.     unbindKey('arrow_r', 'down', Spectate.next)
  867.     MovePlayerAway.stop()
  868.     setCameraTarget(g_Me)
  869.     Spectate.target = nil
  870.     Spectate.active = false
  871.     if Spectate.savePos then
  872.         Spectate.savePos = false
  873.         restorePosition()
  874.     end
  875. end
  876.  
  877. function Spectate.previous(bGUIFeedback)
  878.     Spectate.setTarget( Spectate.findNewTarget(Spectate.target,-1) )
  879.     if bGUIFeedback then
  880.         setGUIComponentsVisible({ specprev = false, specprevhi = true })
  881.         setTimer(setGUIComponentsVisible, 100, 1, { specprevhi = false, specprev = true })
  882.     end
  883. end
  884.  
  885. function Spectate.next(bGUIFeedback)
  886.     Spectate.setTarget( Spectate.findNewTarget(Spectate.target,1) )
  887.     if bGUIFeedback then
  888.         setGUIComponentsVisible({ specnext = false, specnexthi = true })
  889.         setTimer(setGUIComponentsVisible, 100, 1, { specnexthi = false, specnext = true })
  890.     end
  891. end
  892.  
  893. ---------------------------------------------
  894. -- Step along to the next player to spectate
  895. local playersRankSorted = {}
  896. local playersRankSortedTime = 0
  897.  
  898. function Spectate.findNewTarget(current,dir)
  899.  
  900.     -- Time to update sorted list?
  901.     local bUpdateSortedList = ( getTickCount() - playersRankSortedTime > 1000 )
  902.  
  903.     -- Need to update sorted list because g_Players has changed size?
  904.     bUpdateSortedList = bUpdateSortedList or ( #playersRankSorted ~= #g_Players )
  905.  
  906.     if not bUpdateSortedList then
  907.         -- Check playersRankSorted contains the same elements as g_Players
  908.         for _,item in ipairs(playersRankSorted) do
  909.             if not table.find(g_Players, item.player) then
  910.                 bUpdateSortedList = true
  911.                 break
  912.             end
  913.         end
  914.     end
  915.  
  916.     -- Update sorted list if required
  917.     if bUpdateSortedList then
  918.         -- Remake list
  919.         playersRankSorted = {}
  920.         for _,player in ipairs(g_Players) do
  921.             local rank = tonumber(getElementData(player, 'race rank')) or 0
  922.             table.insert( playersRankSorted, {player=player, rank=rank} )
  923.         end
  924.         -- Sort it by rank
  925.         table.sort(playersRankSorted, function(a,b) return(a.rank > b.rank) end)
  926.  
  927.         playersRankSortedTime = getTickCount()
  928.     end
  929.  
  930.     -- Find next player in list
  931.     local pos = table.find(playersRankSorted, 'player', current) or 1
  932.     for i=1,#playersRankSorted do
  933.         pos = ((pos + dir - 1) % #playersRankSorted ) + 1
  934.         if Spectate.isValidTarget(playersRankSorted[pos].player) then
  935.             return playersRankSorted[pos].player
  936.         end
  937.     end
  938.     return nil
  939. end
  940. ---------------------------------------------
  941.  
  942. function Spectate.isValidTarget(player)
  943.     if player == nil then
  944.         return true
  945.     end
  946.     if player == g_Me or isPlayerFinished(player) or isPlayerRaceDead(player) or isPlayerSpectating(player) then
  947.         return false
  948.     end
  949.     if ( Spectate.blockUntilTimes[player] or 0 ) > getTickCount() then
  950.         return false
  951.     end
  952.     if not table.find(g_Players, player) or not isElement(player) then
  953.         return false
  954.     end
  955.     local x,y,z = getElementPosition(player)
  956.     if z > 20000 then
  957.         return false
  958.     end
  959.     if x > -1 and x < 1 and y > -1 and y < 1 then
  960.         return false
  961.     end
  962.     return true
  963. end
  964.  
  965. -- If player is the current target, check to make sure is valid
  966. function Spectate.validateTarget(player)
  967.     if Spectate.active and player == Spectate.target then
  968.         if not Spectate.isValidTarget(player) then
  969.             Spectate.previous(false)
  970.         end
  971.     end
  972. end
  973.  
  974. function Spectate.dropCamera( player, time )
  975.     if Spectate.active and player == Spectate.target then
  976.         if not Spectate.hasDroppedCamera() then
  977.             setCameraMatrix( getCameraMatrix() )
  978.             Spectate.target = nil
  979.             Spectate.droppedCameraTimer:setTimer(Spectate.cancelDropCamera, time, 1, player )
  980.         end
  981.     end
  982. end
  983.  
  984. function Spectate.hasDroppedCamera()
  985.     return Spectate.droppedCameraTimer:isActive()
  986. end
  987.  
  988. function Spectate.cancelDropCamera()
  989.     if Spectate.hasDroppedCamera() then
  990.         Spectate.droppedCameraTimer:killTimer()
  991.         Spectate.tick()
  992.     end
  993. end
  994.  
  995.  
  996. function Spectate.setTarget( player )
  997.     if Spectate.hasDroppedCamera() then
  998.         return
  999.     end
  1000.  
  1001.     Spectate.active = true
  1002.     Spectate.target = player
  1003.     if Spectate.target then
  1004.         if Spectate.getCameraTargetPlayer() ~= Spectate.target then
  1005.             setCameraTarget(Spectate.target)
  1006.         end
  1007.         guiSetText(g_GUI.speclabel, 'Currently spectating:\n' .. getPlayerName(Spectate.target))
  1008.     else
  1009.         local x,y,z = getElementPosition(g_Me)
  1010.         x = x - ( x % 32 )
  1011.         y = y - ( y % 32 )
  1012.         z = getGroundPosition ( x, y, 5000 ) or 40
  1013.         setCameraTarget( g_Me )
  1014.         setCameraMatrix( x,y,z+10,x,y+50,z+60)
  1015.         guiSetText(g_GUI.speclabel, 'Currently spectating:\n No one to spectate')
  1016.     end
  1017.     if Spectate.active and Spectate.savePos then
  1018.         guiSetText(g_GUI.speclabel, guiGetText(g_GUI.speclabel) .. "\n\nPress 'B' to join")
  1019.     end
  1020. end
  1021.  
  1022. function Spectate.blockAsTarget( player, ticks )
  1023.     Spectate.blockUntilTimes[player] = getTickCount() + ticks
  1024.     Spectate.validateTarget(player)
  1025. end
  1026.  
  1027. function Spectate.tick()
  1028.     if Spectate.target and Spectate.getCameraTargetPlayer() and Spectate.getCameraTargetPlayer() ~= Spectate.target then
  1029.         if Spectate.isValidTarget(Spectate.target) then
  1030.             setCameraTarget(Spectate.target)
  1031.             return
  1032.         end
  1033.     end
  1034.     if not Spectate.target or ( Spectate.getCameraTargetPlayer() and Spectate.getCameraTargetPlayer() ~= Spectate.target ) or not Spectate.isValidTarget(Spectate.target) then
  1035.         Spectate.previous(false)
  1036.     end
  1037. end
  1038.  
  1039. function Spectate.getCameraTargetPlayer()
  1040.     local element = getCameraTarget()
  1041.     if element and getElementType(element) == "vehicle" then
  1042.         element = getVehicleController(element)
  1043.     end
  1044.     return element
  1045. end
  1046.  
  1047.  
  1048. g_SavedPos = {}
  1049. function savePosition()
  1050.     g_SavedPos.x, g_SavedPos.y, g_SavedPos.z = getElementPosition(g_Me)
  1051.     g_SavedPos.rz = getPedRotation(g_Me)
  1052.     g_SavedPos.vx, g_SavedPos.vy, g_SavedPos.vz = getElementPosition(g_Vehicle)
  1053.     g_SavedPos.vrx, g_SavedPos.vry, g_SavedPos.vrz = getElementRotation(g_Vehicle)
  1054. end
  1055.  
  1056. function restorePosition()
  1057.     setElementPosition( g_Me, g_SavedPos.x, g_SavedPos.y, g_SavedPos.z )
  1058.     setPedRotation( g_Me, g_SavedPos.rz )
  1059.     setElementPosition( g_Vehicle, g_SavedPos.vx, g_SavedPos.vy, g_SavedPos.vz )
  1060.     setElementRotation( g_Vehicle, g_SavedPos.vrx, g_SavedPos.vry, g_SavedPos.vrz )
  1061. end
  1062.  
  1063.  
  1064. addEvent ( "onClientScreenFadedOut", true )
  1065. addEventHandler ( "onClientScreenFadedOut", g_Root,
  1066.     function()
  1067.         Spectate.fadedout = true
  1068.         Spectate.updateGuiFadedOut()
  1069.     end
  1070. )
  1071.  
  1072. addEvent ( "onClientScreenFadedIn", true )
  1073. addEventHandler ( "onClientScreenFadedIn", g_Root,
  1074.     function()
  1075.         Spectate.fadedout = false
  1076.         Spectate.updateGuiFadedOut()
  1077.     end
  1078. )
  1079.  
  1080. addEvent ( "onClientPreRender", true )
  1081. addEventHandler ( "onClientPreRender", g_Root,
  1082.     function()
  1083.         if isPlayerRaceDead( g_Me ) then
  1084.             setCameraMatrix( getCameraMatrix() )
  1085.         end
  1086.         updateSpectatingCheckpointsAndRank()
  1087.     end
  1088. )
  1089.  
  1090. function Spectate.updateGuiFadedOut()
  1091.     if g_GUI and g_GUI.specprev then
  1092.         if Spectate.fadedout then
  1093.             setGUIComponentsVisible({ specprev = false, specnext = false, speclabel = false })
  1094.         else
  1095.             setGUIComponentsVisible({ specprev = true, specnext = true, speclabel = true })
  1096.         end
  1097.     end
  1098. end
  1099.  
  1100. -----------------------------------------------------------------------
  1101.  
  1102. -----------------------------------------------------------------------
  1103. -- MovePlayerAway - Super hack - Fixes the spec cam problem
  1104. -----------------------------------------------------------------------
  1105. MovePlayerAway = {}
  1106. MovePlayerAway.timer = Timer:create()
  1107. MovePlayerAway.posX = 0
  1108. MovePlayerAway.posY = 0
  1109. MovePlayerAway.posZ = 0
  1110. MovePlayerAway.rotZ = 0
  1111. MovePlayerAway.health = 0
  1112.  
  1113. function MovePlayerAway.start()
  1114.     local element = g_Vehicle or getPedOccupiedVehicle(g_Me) or g_Me
  1115.     MovePlayerAway.posX, MovePlayerAway.posY, MovePlayerAway.posZ = getElementPosition(element)
  1116.     MovePlayerAway.posZ = 34567 + math.random(0,4000)
  1117.     MovePlayerAway.rotZ = 0
  1118.     MovePlayerAway.health = math.max(1,getElementHealth(element))
  1119.     setElementHealth( element, 2000 )
  1120.     setElementHealth( g_Me, 90 )
  1121.     MovePlayerAway.update(true)
  1122.     MovePlayerAway.timer:setTimer(MovePlayerAway.update,500,0)
  1123.     triggerServerEvent("onRequestMoveAwayBegin", g_Me)
  1124. end
  1125.  
  1126.  
  1127. function MovePlayerAway.update(nozcheck)
  1128.     -- Move our player far away
  1129.     local camTarget = getCameraTarget()
  1130.     if not getPedOccupiedVehicle(g_Me) then
  1131.         setElementPosition( g_Me, MovePlayerAway.posX-10, MovePlayerAway.posY-10, MovePlayerAway.posZ )
  1132.     end
  1133.     if getPedOccupiedVehicle(g_Me) then
  1134.         if not nozcheck then
  1135.             if camTarget then
  1136.                 MovePlayerAway.posX, MovePlayerAway.posY = getElementPosition(camTarget)
  1137.                 if getElementType(camTarget) ~= "vehicle" then
  1138.                     outputDebug( 'SPECTATE', 'camera target type:' .. getElementType(camTarget) )
  1139.                 end
  1140.                 if getElementType(camTarget) == 'ped' then
  1141.                     MovePlayerAway.rotZ = getPedRotation(camTarget)
  1142.                 else
  1143.                     _,_, MovePlayerAway.rotZ = getElementRotation(camTarget)
  1144.                 end
  1145.             end  
  1146.         end
  1147.         local vehicle = g_Vehicle
  1148.         if vehicle then
  1149.             fixVehicle( vehicle )
  1150.             setElementFrozen ( vehicle, true )
  1151.             setElementPosition( vehicle, MovePlayerAway.posX, MovePlayerAway.posY, MovePlayerAway.posZ )
  1152.             setElementVelocity( vehicle, 0,0,0 )
  1153.             setVehicleTurnVelocity( vehicle, 0,0,0 )
  1154.             setElementRotation ( vehicle, 0,0,MovePlayerAway.rotZ )
  1155.         end
  1156.     end
  1157.     setElementHealth( g_Me, 90 )
  1158.  
  1159.     if camTarget and camTarget ~= getCameraTarget() then
  1160.         setCameraTarget(camTarget)
  1161.     end
  1162. end
  1163.  
  1164. function MovePlayerAway.stop()
  1165.     triggerServerEvent("onRequestMoveAwayEnd", g_Me)
  1166.     if MovePlayerAway.timer:isActive() then
  1167.         MovePlayerAway.timer:killTimer()
  1168.         local vehicle = g_Vehicle
  1169.         if vehicle then
  1170.             setElementVelocity( vehicle, 0,0,0 )
  1171.             setVehicleTurnVelocity( vehicle, 0,0,0 )
  1172.             setElementFrozen ( vehicle, false )
  1173.             setVehicleDamageProof ( vehicle, false )
  1174.             setElementHealth ( vehicle, MovePlayerAway.health )
  1175.         end
  1176.         setElementVelocity( g_Me, 0,0,0 )
  1177.     end
  1178. end
  1179.  
  1180. -----------------------------------------------------------------------
  1181. -- Camera transition for our player's respawn
  1182. -----------------------------------------------------------------------
  1183. function remoteStopSpectateAndBlack()
  1184.     Spectate.stop('auto')
  1185.     fadeCamera(false,0.0, 0,0,0)            -- Instant black
  1186. end
  1187.  
  1188. function remoteSoonFadeIn( bNoCameraMove )
  1189.     setTimer(fadeCamera,250+500,1,true,1.0)     -- And up
  1190.     if not bNoCameraMove then
  1191.         setTimer( function() setCameraBehindVehicle( g_Vehicle ) end ,250+500-150,1 )
  1192.     end
  1193.     setTimer(checkVehicleIsHelicopter,250+500,1)
  1194. end
  1195. -----------------------------------------------------------------------
  1196.  
  1197. function raceTimeout()
  1198.     removeEventHandler('onClientRender', g_Root, updateTime)
  1199.     if g_CurrentCheckpoint then
  1200.         destroyCheckpoint(g_CurrentCheckpoint)
  1201.         destroyCheckpoint(g_CurrentCheckpoint + 1)
  1202.     end
  1203.     guiSetText(g_GUI.timeleft, msToTimeStr(0))
  1204.     if g_GUI.hurry then
  1205.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  1206.         g_GUI.hurry = nil
  1207.     end
  1208.     triggerEvent("onClientPlayerOutOfTime", g_Me)
  1209.     toggleAllControls(false, true, false)
  1210. end
  1211.  
  1212. function unloadAll()
  1213.     triggerEvent('onClientMapStopping', g_Me)
  1214.     for i=1,#g_Checkpoints do
  1215.         destroyCheckpoint(i)
  1216.     end
  1217.     g_Checkpoints = {}
  1218.     g_CurrentCheckpoint = nil
  1219.    
  1220.     for colshape,pickup in pairs(g_Pickups) do
  1221.         destroyElement(colshape)
  1222.         if pickup.object then
  1223.             destroyElement(pickup.object)
  1224.         end
  1225.         if pickup.label then
  1226.             pickup.label:destroy()
  1227.         end
  1228.     end
  1229.     g_Pickups = {}
  1230.     g_VisiblePickups = {}
  1231.    
  1232.     table.each(g_Objects, destroyElement)
  1233.     g_Objects = {}
  1234.    
  1235.     setElementData(g_Me, 'race.checkpoint', nil)
  1236.    
  1237.     g_Vehicle = nil
  1238.     removeEventHandler('onClientRender', g_Root, updateTime)
  1239.    
  1240.     toggleAllControls(true)
  1241.    
  1242.     if g_GUI then
  1243.         hideGUIComponents('timeleftbg', 'timeleft', 'checkpoint')
  1244.         if g_GUI.hurry then
  1245.             Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  1246.             g_GUI.hurry = nil
  1247.         end
  1248.     end
  1249.     TimerManager.destroyTimersFor("map")
  1250.     g_StartTick = nil
  1251.     g_HurryDuration = nil
  1252.     if Spectate.active then
  1253.         Spectate.stop('auto')
  1254.     end
  1255. end
  1256.  
  1257. function createCheckpoint(i)
  1258.     local checkpoint = g_Checkpoints[i]
  1259.     if checkpoint.marker then
  1260.         return
  1261.     end
  1262.     local pos = checkpoint.position
  1263.     local color = checkpoint.color or { 0, 0, 255 }
  1264.     checkpoint.marker = createMarker(pos[1], pos[2], pos[3], checkpoint.type or 'checkpoint', checkpoint.size, color[1], color[2], color[3])
  1265.     if (not checkpoint.type or checkpoint.type == 'checkpoint') and i == #g_Checkpoints then
  1266.         setMarkerIcon(checkpoint.marker, 'finish')
  1267.     end
  1268.     if checkpoint.type == 'ring' and i < #g_Checkpoints then
  1269.         setMarkerTarget(checkpoint.marker, unpack(g_Checkpoints[i+1].position))
  1270.     end
  1271.     checkpoint.blip = createBlip(pos[1], pos[2], pos[3], 0, isCurrent and 2 or 1, color[1], color[2], color[3])
  1272.     setBlipOrdering(checkpoint.blip, 1)
  1273.     return checkpoint.marker
  1274. end
  1275.  
  1276. function makeCheckpointCurrent(i,bOtherPlayer)
  1277.     local checkpoint = g_Checkpoints[i]
  1278.     local pos = checkpoint.position
  1279.     local color = checkpoint.color or { 255, 0, 0 }
  1280.     if not checkpoint.blip then
  1281.         checkpoint.blip = createBlip(pos[1], pos[2], pos[3], 0, 2, color[1], color[2], color[3])
  1282.         setBlipOrdering(checkpoint.blip, 1)
  1283.     else
  1284.         setBlipSize(checkpoint.blip, 2)
  1285.     end
  1286.    
  1287.     if not checkpoint.type or checkpoint.type == 'checkpoint' then
  1288.         checkpoint.colshape = createColCircle(pos[1], pos[2], checkpoint.size + 4)
  1289.     else
  1290.         checkpoint.colshape = createColSphere(pos[1], pos[2], pos[3], checkpoint.size + 4)
  1291.     end
  1292.     if not bOtherPlayer then
  1293.         addEventHandler('onClientColShapeHit', checkpoint.colshape, checkpointReached)
  1294.     end
  1295. end
  1296.  
  1297. function destroyCheckpoint(i)
  1298.     local checkpoint = g_Checkpoints[i]
  1299.     if checkpoint and checkpoint.marker then
  1300.         destroyElement(checkpoint.marker)
  1301.         checkpoint.marker = nil
  1302.         destroyElement(checkpoint.blip)
  1303.         checkpoint.blip = nil
  1304.         if checkpoint.colshape then
  1305.             destroyElement(checkpoint.colshape)
  1306.             checkpoint.colshape = nil
  1307.         end
  1308.     end
  1309. end
  1310.  
  1311. function setCurrentCheckpoint(i, bOtherPlayer)
  1312.     destroyCheckpoint(g_CurrentCheckpoint)
  1313.     destroyCheckpoint(g_CurrentCheckpoint + 1)
  1314.     createCheckpoint(i)
  1315.     g_CurrentCheckpoint = i - 1
  1316.     showNextCheckpoint(bOtherPlayer)
  1317. end
  1318.  
  1319. function isPlayerRaceDead(player)
  1320.     return not getElementHealth(player) or getElementHealth(player) < 1e-45 or isPlayerDead(player)
  1321. end
  1322.  
  1323. function isPlayerFinished(player)
  1324.     return getElementData(player, 'race.finished')
  1325. end
  1326.  
  1327. function isPlayerSpectating(player)
  1328.     return getElementData(player, 'race.spectating')
  1329. end
  1330.  
  1331. addEventHandler('onClientPlayerJoin', g_Root,
  1332.     function()
  1333.         table.insertUnique(g_Players, source)
  1334.     end
  1335. )
  1336.  
  1337. addEventHandler('onClientPlayerSpawn', g_Root,
  1338.     function()
  1339.         Spectate.blockAsTarget( source, 2000 )  -- No spectate at this player for 2 seconds
  1340.     end
  1341. )
  1342.  
  1343. addEventHandler('onClientPlayerWasted', g_Root,
  1344.     function()
  1345.         if not g_StartTick then
  1346.             return
  1347.         end
  1348.         local player = source
  1349.         local vehicle = getPedOccupiedVehicle(player)
  1350.         if player == g_Me then
  1351.             if #g_Players > 1 and (g_MapOptions.respawn == 'none' or g_MapOptions.respawntime >= 10000) then
  1352.                 if Spectate.blockManualTimer and isTimer(Spectate.blockManualTimer) then
  1353.                     killTimer(Spectate.blockManualTimer)
  1354.                 end
  1355.                 TimerManager.createTimerFor("map"):setTimer(Spectate.start, 2000, 1, 'auto')
  1356.             end
  1357.         else
  1358.             Spectate.dropCamera( player, 1000 )
  1359.         end
  1360.     end
  1361. )
  1362.  
  1363. addEventHandler('onClientPlayerQuit', g_Root,
  1364.     function()
  1365.         table.removevalue(g_Players, source)
  1366.         Spectate.blockUntilTimes[source] = nil
  1367.         Spectate.validateTarget(source)     -- No spectate at this player
  1368.     end
  1369. )
  1370.  
  1371. addEventHandler('onClientResourceStop', g_ResRoot,
  1372.     function()
  1373.         unloadAll()
  1374.         --removeEventHandler('onClientRender', g_Root, updateBars)
  1375.         killTimer(g_WaterCheckTimer)
  1376.         showHUD(true)
  1377.         setPedCanBeKnockedOffBike(g_Me, true)
  1378.     end
  1379. )
  1380.  
  1381. ------------------------
  1382. -- Make vehicle upright
  1383.  
  1384. function directionToRotation2D( x, y )
  1385.     return rem( math.atan2( y, x ) * (360/6.28) - 90, 360 )
  1386. end
  1387.  
  1388. function alignVehicleWithUp()
  1389.     local vehicle = g_Vehicle
  1390.     if not vehicle then return end
  1391.  
  1392.     local matrix = getElementMatrix( vehicle )
  1393.     local Right = Vector3D:new( matrix[1][1], matrix[1][2], matrix[1][3] )
  1394.     local Fwd   = Vector3D:new( matrix[2][1], matrix[2][2], matrix[2][3] )
  1395.     local Up    = Vector3D:new( matrix[3][1], matrix[3][2], matrix[3][3] )
  1396.  
  1397.     local Velocity = Vector3D:new( getElementVelocity( vehicle ) )
  1398.     local rz
  1399.  
  1400.     if Velocity:Length() > 0.05 and Up.z < 0.001 then
  1401.         -- If velocity is valid, and we are upside down, use it to determine rotation
  1402.         rz = directionToRotation2D( Velocity.x, Velocity.y )
  1403.     else
  1404.         -- Otherwise use facing direction to determine rotation
  1405.         rz = directionToRotation2D( Fwd.x, Fwd.y )
  1406.     end
  1407.  
  1408.     setElementRotation( vehicle, 0, 0, rz )
  1409. end
  1410.  
  1411.  
  1412. ------------------------
  1413. -- Script integrity test
  1414.  
  1415. setTimer(
  1416.     function ()
  1417.         if g_Vehicle and not isElement(g_Vehicle) then
  1418.             outputChatBox( "Race integrity test fail (client): Your vehicle has been destroyed. Please panic." )
  1419.         end
  1420.     end,
  1421.     1000,0
  1422. )
  1423.  
  1424. ---------------------------------------------------------------------------
  1425. --
  1426. -- Commands and binds
  1427. --
  1428. --
  1429. --
  1430. ---------------------------------------------------------------------------
  1431.  
  1432.  
  1433. function kill()
  1434.     if Spectate.active then
  1435.         if Spectate.savePos then
  1436.             triggerServerEvent('onClientRequestSpectate', g_Me, false )
  1437.         end
  1438.     else
  1439.         Spectate.blockManual = true
  1440.         triggerServerEvent('onRequestKillPlayer', g_Me)
  1441.         Spectate.blockManualTimer = setTimer(function() Spectate.blockManual = false end, 3000, 1)
  1442.     end
  1443. end
  1444. addCommandHandler('kill',kill)
  1445. addCommandHandler('Commit suicide',kill)
  1446. bindKey ( next(getBoundKeys"enter_exit"), "down", "Commit suicide" )
  1447.  
  1448.  
  1449. function spectate()
  1450.     if Spectate.active then
  1451.         if Spectate.savePos then
  1452.             triggerServerEvent('onClientRequestSpectate', g_Me, false )
  1453.         end
  1454.     else
  1455.         if not Spectate.blockManual then
  1456.             triggerServerEvent('onClientRequestSpectate', g_Me, true )
  1457.         end
  1458.     end
  1459. end
  1460. addCommandHandler('spectate',spectate)
  1461. addCommandHandler('Toggle spectator',spectate)
  1462. bindKey("b","down","Toggle spectator")
  1463.  
  1464. function setPipeDebug(bOn)
  1465.     g_bPipeDebug = bOn
  1466.     outputConsole( 'bPipeDebug set to ' .. tostring(g_bPipeDebug) )
  1467. end
Advertisement
Add Comment
Please, Sign In to add comment