Guest User

Untitled

a guest
Mar 18th, 2012
70
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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">type">type">type('stroke', 2, 0, 0, 0, 255)
  29.         g_dxGUI.ranksuffix:type">type">type('stroke', 2, 0, 0, 0, 255)
  30.         g_dxGUI.checkpoint:type">type">type('stroke', 1, 0, 0, 0, 255)
  31.         g_dxGUI.timepassed:type">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', 'healthbar', 'speedbar', 'ranknum', 'ranksuffix', 'checkpoint', 'timepassed')
  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">pairs">pairs">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">pairs">pairs(pickups) do
  216.         pos = pickup.position
  217.         object = createObject(g_ModelForPickupType[pickup.type">type">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">pairs(pickup) do
  222.             g_Pickups[colshape][k] = v
  223.         end
  224.         g_Pickups[colshape].load">load">load">load = true
  225.         if g_Pickups[colshape].type">type">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">type">type("shadow",2)
  229.         end
  230.     end
  231.    
  232.     -- objects
  233.     g_Objects = {}
  234.     local pos, rot
  235.     for i,object in ipairs">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('healthbar', 'speedbar', '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">type">type">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">pairs">pairs(g_VisiblePickups) do
  359.         pickup = g_Pickups[colshape]
  360.         if pickup.load">load">load then
  361.             setElementRotation(elem, 0, 0, angle)
  362.             if pickup.label then
  363.                 cX, cY, cZ = getCameraMatrix()
  364.                 pickX, pickY, pickZ = unpack">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">tostring">tostring">tostring(elem)
  437.                         .. ' g_Vehicle:' .. tostring">tostring">tostring(g_Vehicle)
  438.                         .. ' isVehicleBlown(g_Vehicle):' .. tostring">tostring">tostring(isVehicleBlown(g_Vehicle))
  439.                         .. ' g_Me:' .. tostring">tostring(g_Me)
  440.                         .. ' getElementHealth(g_Me):' .. tostring">tostring">tostring">tostring(getElementHealth(g_Me))
  441.                         .. ' source:' .. tostring">tostring">tostring(source)
  442.                         .. ' pickup:' .. tostring">tostring">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">load then
  448.             handleHitPickup(pickup)
  449.         end
  450.     end
  451. )
  452.  
  453. function handleHitPickup(pickup)
  454.     if pickup.type">type">type">type == 'vehiclechange' then
  455.         if pickup.vehicle == getElementModel(g_Vehicle) then
  456.             return
  457.         end
  458.         g_PrevVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  459.     end
  460.     triggerServerEvent('onPlayerPickUpRacePickupInternal', g_Me, pickup.id, pickup.respawn)
  461.     playSoundFrontEnd(46)
  462. end
  463.  
  464. function unloadPickup(pickupID)
  465.     for colshape,pickup in pairs">pairs">pairs(g_Pickups) do
  466.         if pickup.id == pickupID then
  467.             pickup.load">load">load = false
  468.             setElementAlpha(pickup.object, 0)
  469.             return
  470.         end
  471.     end
  472. end
  473.  
  474. function loadPickup(pickupID)
  475.     for colshape,pickup in pairs">pairs(g_Pickups) do
  476.         if pickup.id == pickupID then
  477.             setElementAlpha(pickup.object, 255)
  478.             pickup.load">load">load">load = true
  479.             if isElementWithinColShape(g_Vehicle, colshape) then
  480.                 handleHitPickup(pickup)
  481.             end
  482.             return
  483.         end
  484.     end
  485. end
  486.  
  487. function vehicleChanging( changez, newModel )
  488.     if getElementModel(g_Vehicle) ~= newModel then
  489.         outputConsole( "Vehicle change model mismatch (" .. tostring">tostring">tostring(getElementModel(g_Vehicle)) .. "/" .. tostring">tostring">tostring(newModel) .. ")" )
  490.     end
  491.     local newVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  492.     local x, y, z = getElementPosition(g_Vehicle)
  493.     if g_PrevVehicleHeight and newVehicleHeight > g_PrevVehicleHeight then
  494.         z = z - g_PrevVehicleHeight + newVehicleHeight
  495.     end
  496.     if changez then
  497.         z = z + 1
  498.     end
  499.     setElementPosition(g_Vehicle, x, y, z)
  500.     g_PrevVehicleHeight = nil
  501.     updateVehicleWeapons()
  502.     checkVehicleIsHelicopter()
  503. end
  504.  
  505. function updateVehicleWeapons()
  506.     if g_Vehicle then
  507.         local weapons = not g_ArmedVehicleIDs[getElementModel(g_Vehicle)] or g_MapOptions.vehicleweapons
  508.         toggleControl('vehicle_fire', weapons)
  509.         if getElementModel(g_Vehicle) == g_HunterID and not g_MapOptions.hunterminigun then
  510.             weapons = false
  511.         end
  512.         toggleControl('vehicle_secondary_fire', weapons)
  513.     end
  514. end
  515.  
  516. function vehicleUnloading()
  517.     g_Vehicle = nil
  518. end
  519.  
  520. function updateBars()
  521.     if g_Vehicle then
  522.         g_GUI.healthbar:setProgress(getElementHealth(g_Vehicle))
  523.         local vx, vy, vz = getElementVelocity(g_Vehicle)
  524.         g_GUI.speedbar:setProgress(math.sqrt(vx*vx + vy*vy + vz*vz))
  525.     end
  526. end
  527.  
  528. function updateTime()
  529.     local tick = getTickCount()
  530.     local msPassed = tick - g_StartTick
  531.     if not isPlayerFinished(g_Me) then
  532.         g_dxGUI.timepassed:text(msToTimeStr(msPassed))
  533.     end
  534.     local timeLeft = g_Duration - msPassed
  535.     guiSetText(g_GUI.timeleft, msToTimeStr(timeLeft > 0 and timeLeft or 0))
  536.     if g_HurryDuration and g_GUI.hurry == nil and timeLeft <= g_HurryDuration then
  537.         startHurry()
  538.     end
  539. end
  540.  
  541. addEventHandler('onClientElementDataChange', g_Me,
  542.     function(dataName)
  543.         if dataName == 'race rank' and not Spectate.active then
  544.             setRankDisplay( getElementData(g_Me, 'race rank') )
  545.         end
  546.     end,
  547.     false
  548. )
  549.  
  550. function setRankDisplay( rank )
  551.     if not tonumber">tonumber(rank) then
  552.         g_dxGUI.ranknum:text('')
  553.         g_dxGUI.ranksuffix:text('')
  554.         return
  555.     end
  556.     g_dxGUI.ranknum:text(tostring">tostring">tostring">tostring(rank))
  557.     g_dxGUI.ranksuffix:text( (rank < 10 or rank > 20) and ({ [1] = 'st', [2] = 'nd', [3] = 'rd' })[rank % 10] or 'th' )
  558. end
  559.  
  560.  
  561. addEventHandler('onClientElementDataChange', g_Root,
  562.     function(dataName)
  563.         if dataName == 'race.finished' then
  564.             if isPlayerFinished(source) then
  565.                 Spectate.dropCamera( source, 2000 )
  566.             end
  567.         end
  568.         if dataName == 'race.spectating' then
  569.             if isPlayerSpectating(source) then
  570.                 Spectate.validateTarget( source )   -- No spectate at this player
  571.             end
  572.         end
  573.     end
  574. )
  575.  
  576.  
  577. function checkWater()
  578.     if g_Vehicle then
  579.         if not g_WaterCraftIDs[getElementModel(g_Vehicle)] then
  580.             local x, y, z = getElementPosition(g_Me)
  581.             local waterZ = getWaterLevel(x, y, z)
  582.             if waterZ and z < waterZ - 0.5 and not isPlayerRaceDead(g_Me) and not isPlayerFinished(g_Me) and g_MapOptions then
  583.                 if g_MapOptions.firewater then
  584.                     blowVehicle ( g_Vehicle, true )
  585.                 else
  586.                     setElementHealth(g_Me,0)
  587.                     triggerServerEvent('onRequestKillPlayer',g_Me)
  588.                 end
  589.             end
  590.         end
  591.         -- Check stalled vehicle
  592.         if not getVehicleEngineState( g_Vehicle ) then
  593.             setVehicleEngineState( g_Vehicle, true )
  594.         end
  595.         -- Check dead vehicle
  596.         if getElementHealth( g_Vehicle ) == 0 and not isPlayerRaceDead(g_Me) and not isPlayerFinished(g_Me)then
  597.             setElementHealth(g_Me,0)
  598.             triggerServerEvent('onRequestKillPlayer',g_Me)
  599.         end
  600.     end
  601. end
  602.  
  603. function showNextCheckpoint(bOtherPlayer)
  604.     g_CurrentCheckpoint = g_CurrentCheckpoint + 1
  605.     local i = g_CurrentCheckpoint
  606.     g_dxGUI.checkpoint:text((i - 1) .. ' / ' .. #g_Checkpoints)
  607.     if i > 1 then
  608.         destroyCheckpoint(i-1)
  609.     else
  610.         createCheckpoint(1)
  611.     end
  612.     makeCheckpointCurrent(i,bOtherPlayer)
  613.     if i < #g_Checkpoints then
  614.         local curCheckpoint = g_Checkpoints[i]
  615.         local nextCheckpoint = g_Checkpoints[i+1]
  616.         local nextMarker = createCheckpoint(i+1)
  617.         setMarkerTarget(curCheckpoint.marker, unpack">unpack">unpack(nextCheckpoint.position))
  618.     end
  619.     if not Spectate.active then
  620.         setElementData(g_Me, 'race.checkpoint', i)
  621.     end
  622. end
  623.  
  624. -------------------------------------------------------------------------------
  625. -- Show checkpoints and rank info that is relevant to the player being spectated
  626. local prevWhich = nil
  627. local cpValuePrev = nil
  628. local rankValuePrev = nil
  629.  
  630. function updateSpectatingCheckpointsAndRank()
  631.     local which = getWhichDataSourceToUse()
  632.  
  633.     -- Do nothing if we are keeping the last thing displayed
  634.     if which == "keeplast" then
  635.         return
  636.     end
  637.  
  638.     local dataSourceChangedToLocal = which ~= prevWhich and which=="local"
  639.     local dataSourceChangedFromLocal = which ~= prevWhich and prevWhich=="local"
  640.     prevWhich = which
  641.  
  642.     if dataSourceChangedFromLocal or dataSourceChangedToLocal then
  643.         cpValuePrev = nil
  644.         rankValuePrev = nil
  645.     end
  646.  
  647.     if Spectate.active or dataSourceChangedToLocal then
  648.         local watchedPlayer = getWatchedPlayer()
  649.  
  650.         if g_CurrentCheckpoint and g_Checkpoints and #g_Checkpoints > 0 then
  651.             local cpValue = getElementData(watchedPlayer, 'race.checkpoint') or 0
  652.             if cpValue > 0 and cpValue <= #g_Checkpoints then
  653.                 if cpValue ~= cpValuePrev then
  654.                     cpValuePrev = cpValue
  655.                     setCurrentCheckpoint( cpValue, Spectate.active and watchedPlayer ~= g_Me )
  656.                 end
  657.             end
  658.         end
  659.  
  660.         local rankValue = getElementData(watchedPlayer, 'race rank') or 0
  661.         if rankValue ~= rankValuePrev then
  662.             rankValuePrev = rankValue
  663.             setRankDisplay( rankValue ) 
  664.         end
  665.     end
  666. end
  667.  
  668. -- "local"          If not spectating
  669. -- "spectarget"     If spectating valid target
  670. -- "keeplast"       If spectating nil target and dropcam
  671. -- "local"          If spectating nil target and no dropcam
  672. function getWhichDataSourceToUse()
  673.     if not Spectate.active          then    return "local"          end
  674.     if Spectate.target              then    return "spectarget"     end
  675.     if Spectate.hasDroppedCamera()  then    return "keeplast"       end
  676.     return "local"
  677. end
  678.  
  679. function getWatchedPlayer()
  680.     if not Spectate.active          then    return g_Me             end
  681.     if Spectate.target              then    return Spectate.target  end
  682.     if Spectate.hasDroppedCamera()  then    return nil              end
  683.     return g_Me
  684. end
  685. -------------------------------------------------------------------------------
  686.  
  687. function checkpointReached(elem)
  688.     outputDebug( 'CP', 'checkpointReached'
  689.                     .. ' ' .. tostring">tostring">tostring(g_CurrentCheckpoint)
  690.                     .. ' elem:' .. tostring">tostring(elem)
  691.                     .. ' g_Vehicle:' .. tostring">tostring">tostring">tostring(g_Vehicle)
  692.                     .. ' isVehicleBlown(g_Vehicle):' .. tostring">tostring">tostring(isVehicleBlown(g_Vehicle))
  693.                     .. ' g_Me:' .. tostring">tostring">tostring(g_Me)
  694.                     .. ' getElementHealth(g_Me):' .. tostring">tostring(getElementHealth(g_Me))
  695.                     )
  696.     if elem ~= g_Vehicle or isVehicleBlown(g_Vehicle) or getElementHealth(g_Me) == 0 or Spectate.active then
  697.         return
  698.     end
  699.    
  700.     if g_Checkpoints[g_CurrentCheckpoint].vehicle then
  701.         g_PrevVehicleHeight = getElementDistanceFromCentreOfMassToBaseOfModel(g_Vehicle)
  702.     end
  703.     triggerServerEvent('onPlayerReachCheckpointInternal', g_Me, g_CurrentCheckpoint)
  704.     playSoundFrontEnd(43)
  705.     if g_CurrentCheckpoint < #g_Checkpoints then
  706.         showNextCheckpoint()
  707.     else
  708.         g_dxGUI.checkpoint:text(#g_Checkpoints .. ' / ' .. #g_Checkpoints)
  709.         local rc = getRadioChannel()
  710.         setRadioChannel(0)
  711.         addEventHandler("onClientPlayerRadioSwitch", g_Root, onChange)
  712.         playSound("audio/mission_accomplished.mp3")
  713.         setTimer(changeRadioStation, 8000, 1, rc)
  714.         if g_GUI.hurry then
  715.             Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  716.             g_GUI.hurry = false
  717.         end
  718.         destroyCheckpoint(#g_Checkpoints)
  719.         triggerEvent('onClientPlayerFinish', g_Me)
  720.         toggleAllControls(false, true, false)
  721.     end
  722. end
  723.  
  724. function onChange()
  725.     cancelEvent()
  726. end
  727.  
  728. function changeRadioStation(rc)
  729.     removeEventHandler("onClientPlayerRadioSwitch", g_Root, onChange)
  730.     setRadioChannel(tonumber">tonumber">tonumber">tonumber(rc))
  731. end
  732.  
  733. function startHurry()
  734.     if not isPlayerFinished(g_Me) then
  735.         local screenWidth, screenHeight = guiGetScreenSize()
  736.         local w, h = resAdjust(370), resAdjust(112)
  737.         g_GUI.hurry = guiCreateStaticImage(screenWidth/2 - w/2, screenHeight - h - 40, w, h, 'img/hurry.png', false, nil)
  738.         guiSetAlpha(g_GUI.hurry, 0)
  739.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeIn(800))
  740.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiPulse(1000))
  741.     end
  742.     guiLabelSetColor(g_GUI.timeleft, 255, 0, 0)
  743. end
  744.  
  745. function setTimeLeft(timeLeft)
  746.     g_Duration = (getTickCount() - g_StartTick) + timeLeft
  747. end
  748.  
  749. -----------------------------------------------------------------------
  750. -- Spectate
  751. -----------------------------------------------------------------------
  752. Spectate = {}
  753. Spectate.active = false
  754. Spectate.target = nil
  755. Spectate.blockUntilTimes = {}
  756. Spectate.savePos = false
  757. Spectate.manual = false
  758. Spectate.droppedCameraTimer = Timer:create()
  759. Spectate.tickTimer = Timer:create()
  760. Spectate.fadedout = true
  761. Spectate.blockManual = false
  762. Spectate.blockManualTimer = nil
  763.  
  764.  
  765. -- Request to switch on
  766. function Spectate.start(type">type">type)
  767.     outputDebug( 'SPECTATE', 'Spectate.start '..type">type">type )
  768.     assert">assert(type">type">type">type=='manual' or type">type">type=='auto', "Spectate.start : type">type == auto or manual")
  769.     Spectate.blockManual = false
  770.     if type">type">type == 'manual' then
  771.         if Spectate.active then
  772.             return                  -- Ignore if manual request and already on
  773.         end
  774.         Spectate.savePos = true -- Savepos and start if manual request and was off
  775.     elseif type">type == 'auto' then
  776.         Spectate.savePos = false    -- Clear restore pos if an auto spectate is requested
  777.     end
  778.     if not Spectate.active then
  779.         Spectate._start()           -- Switch on here, if was off
  780.     end
  781. end
  782.  
  783.  
  784. -- Request to switch off
  785. function Spectate.stop(type">type">type">type)
  786.     outputDebug( 'SPECTATE', 'Spectate.stop '..type">type">type )
  787.     assert">assert">assert(type">type=='manual' or type">type">type">type=='auto', "Spectate.stop : type">type == auto or manual")
  788.     if type">type == 'auto' then
  789.         Spectate.savePos = false    -- Clear restore pos if an auto spectate is requested
  790.     end
  791.     if Spectate.active then
  792.         Spectate._stop()            -- Switch off here, if was on
  793.     end
  794. end
  795.  
  796.  
  797. function Spectate._start()
  798.     outputDebug( 'SPECTATE', 'Spectate._start ' )
  799.     triggerServerEvent('onClientNotifySpectate', g_Me, true )
  800.     assert">assert">assert">assert(not Spectate.active, "Spectate._start - not Spectate.active")
  801.     local screenWidth, screenHeight = guiGetScreenSize()
  802.     g_GUI.specprev = guiCreateStaticImage(screenWidth/2 - 100 - 58, screenHeight - 123, 58, 82, 'img/specprev.png', false, nil)
  803.     g_GUI.specprevhi = guiCreateStaticImage(screenWidth/2 - 100 - 58, screenHeight - 123, 58, 82, 'img/specprev_hi.png', false, nil)
  804.     g_GUI.specnext = guiCreateStaticImage(screenWidth/2 + 100, screenHeight - 123, 58, 82, 'img/specnext.png', false, nil)
  805.     g_GUI.specnexthi = guiCreateStaticImage(screenWidth/2 + 100, screenHeight - 123, 58, 82, 'img/specnext_hi.png', false, nil)
  806.     g_GUI.speclabel = guiCreateLabel(screenWidth/2 - 100, screenHeight - 100, 200, 70, '', false)
  807.     Spectate.updateGuiFadedOut()
  808.     guiLabelSetHorizontalAlign(g_GUI.speclabel, 'center')
  809.     hideGUIComponents('specprevhi', 'specnexthi')
  810.     if Spectate.savePos then
  811.         savePosition()
  812.     end
  813.     Spectate.setTarget( Spectate.findNewTarget(g_Me,1) )
  814.     bindKey('arrow_l', 'down', Spectate.previous)
  815.     bindKey('arrow_r', 'down', Spectate.next">next">next)
  816.     MovePlayerAway.start()
  817.     Spectate.setTarget( Spectate.target )
  818.     Spectate.validateTarget(Spectate.target)
  819.     Spectate.tickTimer:setTimer( Spectate.tick, 500, 0 )
  820. end
  821.  
  822. -- Stop spectating. Will restore position if Spectate.savePos is set
  823. function Spectate._stop()
  824.     Spectate.cancelDropCamera()
  825.     Spectate.tickTimer:killTimer()
  826.     triggerServerEvent('onClientNotifySpectate', g_Me, false )
  827.     outputDebug( 'SPECTATE', 'Spectate._stop ' )
  828.     assert">assert">assert(Spectate.active, "Spectate._stop - Spectate.active")
  829.     for i,name in ipairs">ipairs({'specprev', 'specprevhi', 'specnext', 'specnexthi', 'speclabel'}) do
  830.         if g_GUI[name] then
  831.             destroyElement(g_GUI[name])
  832.             g_GUI[name] = nil
  833.         end
  834.     end
  835.     unbindKey('arrow_l', 'down', Spectate.previous)
  836.     unbindKey('arrow_r', 'down', Spectate.next">next">next">next)
  837.     MovePlayerAway.stop()
  838.     setCameraTarget(g_Me)
  839.     Spectate.target = nil
  840.     Spectate.active = false
  841.     if Spectate.savePos then
  842.         Spectate.savePos = false
  843.         restorePosition()
  844.     end
  845. end
  846.  
  847. function Spectate.previous(bGUIFeedback)
  848.     Spectate.setTarget( Spectate.findNewTarget(Spectate.target,-1) )
  849.     if bGUIFeedback then
  850.         setGUIComponentsVisible({ specprev = false, specprevhi = true })
  851.         setTimer(setGUIComponentsVisible, 100, 1, { specprevhi = false, specprev = true })
  852.     end
  853. end
  854.  
  855. function Spectate.next">next">next(bGUIFeedback)
  856.     Spectate.setTarget( Spectate.findNewTarget(Spectate.target,1) )
  857.     if bGUIFeedback then
  858.         setGUIComponentsVisible({ specnext = false, specnexthi = true })
  859.         setTimer(setGUIComponentsVisible, 100, 1, { specnexthi = false, specnext = true })
  860.     end
  861. end
  862.  
  863. ---------------------------------------------
  864. -- Step along to the next player to spectate
  865. local playersRankSorted = {}
  866. local playersRankSortedTime = 0
  867.  
  868. function Spectate.findNewTarget(current,dir)
  869.  
  870.     -- Time to update sorted list?
  871.     local bUpdateSortedList = ( getTickCount() - playersRankSortedTime > 1000 )
  872.  
  873.     -- Need to update sorted list because g_Players has changed size?
  874.     bUpdateSortedList = bUpdateSortedList or ( #playersRankSorted ~= #g_Players )
  875.  
  876.     if not bUpdateSortedList then
  877.         -- Check playersRankSorted contains the same elements as g_Players
  878.         for _,item in ipairs">ipairs">ipairs(playersRankSorted) do
  879.             if not table.find(g_Players, item.player) then
  880.                 bUpdateSortedList = true
  881.                 break
  882.             end
  883.         end
  884.     end
  885.  
  886.     -- Update sorted list if required
  887.     if bUpdateSortedList then
  888.         -- Remake list
  889.         playersRankSorted = {}
  890.         for _,player in ipairs">ipairs(g_Players) do
  891.             local rank = tonumber">tonumber">tonumber">tonumber(getElementData(player, 'race rank')) or 0
  892.             table.insert( playersRankSorted, {player=player, rank=rank} )
  893.         end
  894.         -- Sort it by rank
  895.         table.sort(playersRankSorted, function(a,b) return(a.rank > b.rank) end)
  896.  
  897.         playersRankSortedTime = getTickCount()
  898.     end
  899.  
  900.     -- Find next player in list
  901.     local pos = table.find(playersRankSorted, 'player', current) or 1
  902.     for i=1,#playersRankSorted do
  903.         pos = ((pos + dir - 1) % #playersRankSorted ) + 1
  904.         if Spectate.isValidTarget(playersRankSorted[pos].player) then
  905.             return playersRankSorted[pos].player
  906.         end
  907.     end
  908.     return nil
  909. end
  910. ---------------------------------------------
  911.  
  912. function Spectate.isValidTarget(player)
  913.     if player == nil then
  914.         return true
  915.     end
  916.     if player == g_Me or isPlayerFinished(player) or isPlayerRaceDead(player) or isPlayerSpectating(player) then
  917.         return false
  918.     end
  919.     if ( Spectate.blockUntilTimes[player] or 0 ) > getTickCount() then
  920.         return false
  921.     end
  922.     if not table.find(g_Players, player) or not isElement(player) then
  923.         return false
  924.     end
  925.     local x,y,z = getElementPosition(player)
  926.     if z > 20000 then
  927.         return false
  928.     end
  929.     if x > -1 and x < 1 and y > -1 and y < 1 then
  930.         return false
  931.     end
  932.     return true
  933. end
  934.  
  935. -- If player is the current target, check to make sure is valid
  936. function Spectate.validateTarget(player)
  937.     if Spectate.active and player == Spectate.target then
  938.         if not Spectate.isValidTarget(player) then
  939.             Spectate.previous(false)
  940.         end
  941.     end
  942. end
  943.  
  944. function Spectate.dropCamera( player, time )
  945.     if Spectate.active and player == Spectate.target then
  946.         if not Spectate.hasDroppedCamera() then
  947.             setCameraMatrix( getCameraMatrix() )
  948.             Spectate.target = nil
  949.             Spectate.droppedCameraTimer:setTimer(Spectate.cancelDropCamera, time, 1, player )
  950.         end
  951.     end
  952. end
  953.  
  954. function Spectate.hasDroppedCamera()
  955.     return Spectate.droppedCameraTimer:isActive()
  956. end
  957.  
  958. function Spectate.cancelDropCamera()
  959.     if Spectate.hasDroppedCamera() then
  960.         Spectate.droppedCameraTimer:killTimer()
  961.         Spectate.tick()
  962.     end
  963. end
  964.  
  965.  
  966. function Spectate.setTarget( player )
  967.     if Spectate.hasDroppedCamera() then
  968.         return
  969.     end
  970.  
  971.     Spectate.active = true
  972.     Spectate.target = player
  973.     if Spectate.target then
  974.         if Spectate.getCameraTargetPlayer() ~= Spectate.target then
  975.             setCameraTarget(Spectate.target)
  976.         end
  977.         guiSetText(g_GUI.speclabel, 'Currently spectating:\n' .. getPlayerName(Spectate.target))
  978.     else
  979.         local x,y,z = getElementPosition(g_Me)
  980.         x = x - ( x % 32 )
  981.         y = y - ( y % 32 )
  982.         z = getGroundPosition ( x, y, 5000 ) or 40
  983.         setCameraTarget( g_Me )
  984.         setCameraMatrix( x,y,z+10,x,y+50,z+60)
  985.         guiSetText(g_GUI.speclabel, 'Currently spectating:\n No one to spectate')
  986.     end
  987.     if Spectate.active and Spectate.savePos then
  988.         guiSetText(g_GUI.speclabel, guiGetText(g_GUI.speclabel) .. "\n\nPress 'B' to join")
  989.     end
  990. end
  991.  
  992. function Spectate.blockAsTarget( player, ticks )
  993.     Spectate.blockUntilTimes[player] = getTickCount() + ticks
  994.     Spectate.validateTarget(player)
  995. end
  996.  
  997. function Spectate.tick()
  998.     if Spectate.target and Spectate.getCameraTargetPlayer() and Spectate.getCameraTargetPlayer() ~= Spectate.target then
  999.         if Spectate.isValidTarget(Spectate.target) then
  1000.             setCameraTarget(Spectate.target)
  1001.             return
  1002.         end
  1003.     end
  1004.     if not Spectate.target or ( Spectate.getCameraTargetPlayer() and Spectate.getCameraTargetPlayer() ~= Spectate.target ) or not Spectate.isValidTarget(Spectate.target) then
  1005.         Spectate.previous(false)
  1006.     end
  1007. end
  1008.  
  1009. function Spectate.getCameraTargetPlayer()
  1010.     local element = getCameraTarget()
  1011.     if element and getElementType(element) == "vehicle" then
  1012.         element = getVehicleController(element)
  1013.     end
  1014.     return element
  1015. end
  1016.  
  1017.  
  1018. g_SavedPos = {}
  1019. function savePosition()
  1020.     g_SavedPos.x, g_SavedPos.y, g_SavedPos.z = getElementPosition(g_Me)
  1021.     g_SavedPos.rz = getPedRotation(g_Me)
  1022.     g_SavedPos.vx, g_SavedPos.vy, g_SavedPos.vz = getElementPosition(g_Vehicle)
  1023.     g_SavedPos.vrx, g_SavedPos.vry, g_SavedPos.vrz = getElementRotation(g_Vehicle)
  1024. end
  1025.  
  1026. function restorePosition()
  1027.     setElementPosition( g_Me, g_SavedPos.x, g_SavedPos.y, g_SavedPos.z )
  1028.     setPedRotation( g_Me, g_SavedPos.rz )
  1029.     setElementPosition( g_Vehicle, g_SavedPos.vx, g_SavedPos.vy, g_SavedPos.vz )
  1030.     setElementRotation( g_Vehicle, g_SavedPos.vrx, g_SavedPos.vry, g_SavedPos.vrz )
  1031. end
  1032.  
  1033.  
  1034. addEvent ( "onClientScreenFadedOut", true )
  1035. addEventHandler ( "onClientScreenFadedOut", g_Root,
  1036.     function()
  1037.         Spectate.fadedout = true
  1038.         Spectate.updateGuiFadedOut()
  1039.     end
  1040. )
  1041.  
  1042. addEvent ( "onClientScreenFadedIn", true )
  1043. addEventHandler ( "onClientScreenFadedIn", g_Root,
  1044.     function()
  1045.         Spectate.fadedout = false
  1046.         Spectate.updateGuiFadedOut()
  1047.     end
  1048. )
  1049.  
  1050. addEvent ( "onClientPreRender", true )
  1051. addEventHandler ( "onClientPreRender", g_Root,
  1052.     function()
  1053.         if isPlayerRaceDead( g_Me ) then
  1054.             setCameraMatrix( getCameraMatrix() )
  1055.         end
  1056.         updateSpectatingCheckpointsAndRank()
  1057.     end
  1058. )
  1059.  
  1060. function Spectate.updateGuiFadedOut()
  1061.     if g_GUI and g_GUI.specprev then
  1062.         if Spectate.fadedout then
  1063.             setGUIComponentsVisible({ specprev = false, specnext = false, speclabel = false })
  1064.         else
  1065.             setGUIComponentsVisible({ specprev = true, specnext = true, speclabel = true })
  1066.         end
  1067.     end
  1068. end
  1069.  
  1070. -----------------------------------------------------------------------
  1071.  
  1072. -----------------------------------------------------------------------
  1073. -- MovePlayerAway - Super hack - Fixes the spec cam problem
  1074. -----------------------------------------------------------------------
  1075. MovePlayerAway = {}
  1076. MovePlayerAway.timer = Timer:create()
  1077. MovePlayerAway.posX = 0
  1078. MovePlayerAway.posY = 0
  1079. MovePlayerAway.posZ = 0
  1080. MovePlayerAway.rotZ = 0
  1081. MovePlayerAway.health = 0
  1082.  
  1083. function MovePlayerAway.start()
  1084.     local element = g_Vehicle or getPedOccupiedVehicle(g_Me) or g_Me
  1085.     MovePlayerAway.posX, MovePlayerAway.posY, MovePlayerAway.posZ = getElementPosition(element)
  1086.     MovePlayerAway.posZ = 34567 + math.random(0,4000)
  1087.     MovePlayerAway.rotZ = 0
  1088.     MovePlayerAway.health = math.max(1,getElementHealth(element))
  1089.     setElementHealth( element, 2000 )
  1090.     setElementHealth( g_Me, 90 )
  1091.     MovePlayerAway.update(true)
  1092.     MovePlayerAway.timer:setTimer(MovePlayerAway.update,500,0)
  1093.     triggerServerEvent("onRequestMoveAwayBegin", g_Me)
  1094. end
  1095.  
  1096.  
  1097. function MovePlayerAway.update(nozcheck)
  1098.     -- Move our player far away
  1099.     local camTarget = getCameraTarget()
  1100.     if not getPedOccupiedVehicle(g_Me) then
  1101.         setElementPosition( g_Me, MovePlayerAway.posX-10, MovePlayerAway.posY-10, MovePlayerAway.posZ )
  1102.     end
  1103.     if getPedOccupiedVehicle(g_Me) then
  1104.         if not nozcheck then
  1105.             if camTarget then
  1106.                 MovePlayerAway.posX, MovePlayerAway.posY = getElementPosition(camTarget)
  1107.                 if getElementType(camTarget) ~= "vehicle" then
  1108.                     outputDebug( 'SPECTATE', 'camera target type:' .. getElementType(camTarget) )
  1109.                 end
  1110.                 if getElementType(camTarget) == 'ped' then
  1111.                     MovePlayerAway.rotZ = getPedRotation(camTarget)
  1112.                 else
  1113.                     _,_, MovePlayerAway.rotZ = getElementRotation(camTarget)
  1114.                 end
  1115.             end  
  1116.         end
  1117.         local vehicle = g_Vehicle
  1118.         if vehicle then
  1119.             fixVehicle( vehicle )
  1120.             setElementFrozen ( vehicle, true )
  1121.             setElementPosition( vehicle, MovePlayerAway.posX, MovePlayerAway.posY, MovePlayerAway.posZ )
  1122.             setElementVelocity( vehicle, 0,0,0 )
  1123.             setVehicleTurnVelocity( vehicle, 0,0,0 )
  1124.             setElementRotation ( vehicle, 0,0,MovePlayerAway.rotZ )
  1125.         end
  1126.     end
  1127.     setElementHealth( g_Me, 90 )
  1128.  
  1129.     if camTarget and camTarget ~= getCameraTarget() then
  1130.         setCameraTarget(camTarget)
  1131.     end
  1132. end
  1133.  
  1134. function MovePlayerAway.stop()
  1135.     triggerServerEvent("onRequestMoveAwayEnd", g_Me)
  1136.     if MovePlayerAway.timer:isActive() then
  1137.         MovePlayerAway.timer:killTimer()
  1138.         local vehicle = g_Vehicle
  1139.         if vehicle then
  1140.             setElementVelocity( vehicle, 0,0,0 )
  1141.             setVehicleTurnVelocity( vehicle, 0,0,0 )
  1142.             setElementFrozen ( vehicle, false )
  1143.             setVehicleDamageProof ( vehicle, false )
  1144.             setElementHealth ( vehicle, MovePlayerAway.health )
  1145.         end
  1146.         setElementVelocity( g_Me, 0,0,0 )
  1147.     end
  1148. end
  1149.  
  1150. -----------------------------------------------------------------------
  1151. -- Camera transition for our player's respawn
  1152. -----------------------------------------------------------------------
  1153. function remoteStopSpectateAndBlack()
  1154.     Spectate.stop('auto')
  1155.     fadeCamera(false,0.0, 0,0,0)            -- Instant black
  1156. end
  1157.  
  1158. function remoteSoonFadeIn( bNoCameraMove )
  1159.     setTimer(fadeCamera,250+500,1,true,1.0)     -- And up
  1160.     if not bNoCameraMove then
  1161.         setTimer( function() setCameraBehindVehicle( g_Vehicle ) end ,250+500-150,1 )
  1162.     end
  1163.     setTimer(checkVehicleIsHelicopter,250+500,1)
  1164. end
  1165. -----------------------------------------------------------------------
  1166.  
  1167. function raceTimeout()
  1168.     removeEventHandler('onClientRender', g_Root, updateTime)
  1169.     if g_CurrentCheckpoint then
  1170.         destroyCheckpoint(g_CurrentCheckpoint)
  1171.         destroyCheckpoint(g_CurrentCheckpoint + 1)
  1172.     end
  1173.     guiSetText(g_GUI.timeleft, msToTimeStr(0))
  1174.     if g_GUI.hurry then
  1175.         Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  1176.         g_GUI.hurry = nil
  1177.     end
  1178.     triggerEvent("onClientPlayerOutOfTime", g_Me)
  1179.     toggleAllControls(false, true, false)
  1180. end
  1181.  
  1182. function unloadAll()
  1183.     triggerEvent('onClientMapStopping', g_Me)
  1184.     for i=1,#g_Checkpoints do
  1185.         destroyCheckpoint(i)
  1186.     end
  1187.     g_Checkpoints = {}
  1188.     g_CurrentCheckpoint = nil
  1189.    
  1190.     for colshape,pickup in pairs">pairs">pairs(g_Pickups) do
  1191.         destroyElement(colshape)
  1192.         if pickup.object then
  1193.             destroyElement(pickup.object)
  1194.         end
  1195.         if pickup.label then
  1196.             pickup.label:destroy()
  1197.         end
  1198.     end
  1199.     g_Pickups = {}
  1200.     g_VisiblePickups = {}
  1201.    
  1202.     table.each(g_Objects, destroyElement)
  1203.     g_Objects = {}
  1204.    
  1205.     setElementData(g_Me, 'race.checkpoint', nil)
  1206.    
  1207.     g_Vehicle = nil
  1208.     removeEventHandler('onClientRender', g_Root, updateTime)
  1209.    
  1210.     toggleAllControls(true)
  1211.    
  1212.     if g_GUI then
  1213.         hideGUIComponents('timeleftbg', 'timeleft', 'healthbar', 'speedbar', 'ranknum', 'ranksuffix', 'checkpoint', 'timepassed')
  1214.         if g_GUI.hurry then
  1215.             Animation.createAndPlay(g_GUI.hurry, Animation.presets.guiFadeOut(500), destroyElement)
  1216.             g_GUI.hurry = nil
  1217.         end
  1218.     end
  1219.     TimerManager.destroyTimersFor("map")
  1220.     g_StartTick = nil
  1221.     g_HurryDuration = nil
  1222.     if Spectate.active then
  1223.         Spectate.stop('auto')
  1224.     end
  1225. end
  1226.  
  1227. function createCheckpoint(i)
  1228.     local checkpoint = g_Checkpoints[i]
  1229.     if checkpoint.marker then
  1230.         return
  1231.     end
  1232.     local pos = checkpoint.position
  1233.     local color = checkpoint.color or { 0, 0, 255 }
  1234.     checkpoint.marker = createMarker(pos[1], pos[2], pos[3], checkpoint.type">type">type or 'checkpoint', checkpoint.size, color[1], color[2], color[3])
  1235.     if (not checkpoint.type">type or checkpoint.type">type">type">type == 'checkpoint') and i == #g_Checkpoints then
  1236.         setMarkerIcon(checkpoint.marker, 'finish')
  1237.     end
  1238.     if checkpoint.type">type">type == 'ring' and i < #g_Checkpoints then
  1239.         setMarkerTarget(checkpoint.marker, unpack">unpack">unpack(g_Checkpoints[i+1].position))
  1240.     end
  1241.     checkpoint.blip = createBlip(pos[1], pos[2], pos[3], 0, isCurrent and 2 or 1, color[1], color[2], color[3])
  1242.     setBlipOrdering(checkpoint.blip, 1)
  1243.     return checkpoint.marker
  1244. end
  1245.  
  1246. function makeCheckpointCurrent(i,bOtherPlayer)
  1247.     local checkpoint = g_Checkpoints[i]
  1248.     local pos = checkpoint.position
  1249.     local color = checkpoint.color or { 255, 0, 0 }
  1250.     if not checkpoint.blip then
  1251.         checkpoint.blip = createBlip(pos[1], pos[2], pos[3], 0, 2, color[1], color[2], color[3])
  1252.         setBlipOrdering(checkpoint.blip, 1)
  1253.     else
  1254.         setBlipSize(checkpoint.blip, 2)
  1255.     end
  1256.    
  1257.     if not checkpoint.type">type or checkpoint.type">type">type">type == 'checkpoint' then
  1258.         checkpoint.colshape = createColCircle(pos[1], pos[2], checkpoint.size + 4)
  1259.     else
  1260.         checkpoint.colshape = createColSphere(pos[1], pos[2], pos[3], checkpoint.size + 4)
  1261.     end
  1262.     if not bOtherPlayer then
  1263.         addEventHandler('onClientColShapeHit', checkpoint.colshape, checkpointReached)
  1264.     end
  1265. end
  1266.  
  1267. function destroyCheckpoint(i)
  1268.     local checkpoint = g_Checkpoints[i]
  1269.     if checkpoint and checkpoint.marker then
  1270.         destroyElement(checkpoint.marker)
  1271.         checkpoint.marker = nil
  1272.         destroyElement(checkpoint.blip)
  1273.         checkpoint.blip = nil
  1274.         if checkpoint.colshape then
  1275.             destroyElement(checkpoint.colshape)
  1276.             checkpoint.colshape = nil
  1277.         end
  1278.     end
  1279. end
  1280.  
  1281. function setCurrentCheckpoint(i, bOtherPlayer)
  1282.     destroyCheckpoint(g_CurrentCheckpoint)
  1283.     destroyCheckpoint(g_CurrentCheckpoint + 1)
  1284.     createCheckpoint(i)
  1285.     g_CurrentCheckpoint = i - 1
  1286.     showNextCheckpoint(bOtherPlayer)
  1287. end
  1288.  
  1289. function isPlayerRaceDead(player)
  1290.     return not getElementHealth(player) or getElementHealth(player) < 1e-45 or isPlayerDead(player)
  1291. end
  1292.  
  1293. function isPlayerFinished(player)
  1294.     return getElementData(player, 'race.finished')
  1295. end
  1296.  
  1297. function isPlayerSpectating(player)
  1298.     return getElementData(player, 'race.spectating')
  1299. end
  1300.  
  1301. addEventHandler('onClientPlayerJoin', g_Root,
  1302.     function()
  1303.         table.insertUnique(g_Players, source)
  1304.     end
  1305. )
  1306.  
  1307. addEventHandler('onClientPlayerSpawn', g_Root,
  1308.     function()
  1309.         Spectate.blockAsTarget( source, 2000 )  -- No spectate at this player for 2 seconds
  1310.     end
  1311. )
  1312.  
  1313. addEventHandler('onClientPlayerWasted', g_Root,
  1314.     function()
  1315.         if not g_StartTick then
  1316.             return
  1317.         end
  1318.         local player = source
  1319.         local vehicle = getPedOccupiedVehicle(player)
  1320.         if player == g_Me then
  1321.             if #g_Players > 1 and (g_MapOptions.respawn == 'none' or g_MapOptions.respawntime >= 10000) then
  1322.                 if Spectate.blockManualTimer and isTimer(Spectate.blockManualTimer) then
  1323.                     killTimer(Spectate.blockManualTimer)
  1324.                 end
  1325.                 TimerManager.createTimerFor("map"):setTimer(Spectate.start, 2000, 1, 'auto')
  1326.             end
  1327.         else
  1328.             Spectate.dropCamera( player, 1000 )
  1329.         end
  1330.     end
  1331. )
  1332.  
  1333. addEventHandler('onClientPlayerQuit', g_Root,
  1334.     function()
  1335.         table.removevalue(g_Players, source)
  1336.         Spectate.blockUntilTimes[source] = nil
  1337.         Spectate.validateTarget(source)     -- No spectate at this player
  1338.     end
  1339. )
  1340.  
  1341. addEventHandler('onClientResourceStop', g_ResRoot,
  1342.     function()
  1343.         unloadAll()
  1344.         removeEventHandler('onClientRender', g_Root, updateBars)
  1345.         killTimer(g_WaterCheckTimer)
  1346.         showHUD(true)
  1347.         setPedCanBeKnockedOffBike(g_Me, true)
  1348.     end
  1349. )
  1350.  
  1351. ------------------------
  1352. -- Make vehicle upright
  1353.  
  1354. function directionToRotation2D( x, y )
  1355.     return rem( math.atan2( y, x ) * (360/6.28) - 90, 360 )
  1356. end
  1357.  
  1358. function alignVehicleWithUp()
  1359.     local vehicle = g_Vehicle
  1360.     if not vehicle then return end
  1361.  
  1362.     local matrix = getElementMatrix( vehicle )
  1363.     local Right = Vector3D:new( matrix[1][1], matrix[1][2], matrix[1][3] )
  1364.     local Fwd   = Vector3D:new( matrix[2][1], matrix[2][2], matrix[2][3] )
  1365.     local Up    = Vector3D:new( matrix[3][1], matrix[3][2], matrix[3][3] )
  1366.  
  1367.     local Velocity = Vector3D:new( getElementVelocity( vehicle ) )
  1368.     local rz
  1369.  
  1370.     if Velocity:Length() > 0.05 and Up.z < 0.001 then
  1371.         -- If velocity is valid, and we are upside down, use it to determine rotation
  1372.         rz = directionToRotation2D( Velocity.x, Velocity.y )
  1373.     else
  1374.         -- Otherwise use facing direction to determine rotation
  1375.         rz = directionToRotation2D( Fwd.x, Fwd.y )
  1376.     end
  1377.  
  1378.     setElementRotation( vehicle, 0, 0, rz )
  1379. end
  1380.  
  1381.  
  1382. ------------------------
  1383. -- Script integrity test
  1384.  
  1385. setTimer(
  1386.     function ()
  1387.         if g_Vehicle and not isElement(g_Vehicle) then
  1388.             outputChatBox( "Race integrity test fail (client): Your vehicle has been destroyed. Please panic." )
  1389.         end
  1390.     end,
  1391.     1000,0
  1392. )
  1393.  
  1394. ---------------------------------------------------------------------------
  1395. --
  1396. -- Commands and binds
  1397. --
  1398. --
  1399. --
  1400. ---------------------------------------------------------------------------
  1401.  
  1402.  
  1403. function kill()
  1404.     if Spectate.active then
  1405.         if Spectate.savePos then
  1406.             triggerServerEvent('onClientRequestSpectate', g_Me, false )
  1407.         end
  1408.     else
  1409.         Spectate.blockManual = true
  1410.         triggerServerEvent('onRequestKillPlayer', g_Me)
  1411.         Spectate.blockManualTimer = setTimer(function() Spectate.blockManual = false end, 3000, 1)
  1412.     end
  1413. end
  1414. addCommandHandler('kill',kill)
  1415. addCommandHandler('Commit suicide',kill)
  1416. bindKey ( next">next">next(getBoundKeys"enter_exit"), "down", "Commit suicide" )
  1417.  
  1418.  
  1419. function spectate()
  1420.     if Spectate.active then
  1421.         if Spectate.savePos then
  1422.             triggerServerEvent('onClientRequestSpectate', g_Me, false )
  1423.         end
  1424.     else
  1425.         if not Spectate.blockManual then
  1426.             triggerServerEvent('onClientRequestSpectate', g_Me, true )
  1427.         end
  1428.     end
  1429. end
  1430. addCommandHandler('spectate',spectate)
  1431. addCommandHandler('Toggle spectator',spectate)
  1432. bindKey("b","down","Toggle spectator")
  1433.  
  1434. function setPipeDebug(bOn)
  1435.     g_bPipeDebug = bOn
  1436.     outputConsole( 'bPipeDebug set to ' .. tostring">tostring">tostring(g_bPipeDebug) )
  1437. end
RAW Paste Data