Yoshi-Networks

race_client.lua

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