Need a unique gift idea?
A Pastebin account makes a great Christmas gift
SHARE
TWEET

Untitled

Kenix157 Sep 23rd, 2016 245 Never
Upgrade to PRO!
ENDING IN00days00hours00mins00secs
 
  1. --
  2. -- Indicators script v1.1
  3. -- By Alberto "ryden" Alonso.
  4. -- Coded for Valhalla MTA Roleplay server.
  5. -- (Because Fenix can't code).
  6. --
  7. -- Licensed under the BSD license conditions.
  8. --
  9. -- Uses client-side synced element data to sync the
  10. -- indicators state. The element data names can be
  11. -- either 'i:left' and 'i:right', being possible to
  12. -- have both switched on. A true value on an element
  13. -- data means that the indicator is activated. False
  14. -- or nil means deactivated.
  15. --
  16. -- * Version 1.1:
  17. --   - Added tick sounds
  18. --   - Added auto switching off when taking a turn
  19. --
  20.  
  21. --[[ Configuration ]]--
  22. local INDICATOR_SIZE = 0.32                     -- Size for the corona markers
  23. local INDICATOR_COLOR = { 255, 100, 10, 255 }   -- Color in R G B A format
  24. local INDICATOR_FADE_MS = 150                   -- Miliseconds to fade out the indicators
  25. local INDICATOR_SWITCH_TIMES = { 300, 400 }     -- In miliseconds. First is time to switch them off, second to switch them on.
  26. local INDICATOR_AUTOSWITCH_OFF_THRESHOLD = 62   -- A value in degrees ranging (0, 90) preferibly far from the limits.
  27.  
  28.  
  29. --[[ Some globals to this context ]]--
  30. local root = getRootElement()
  31. local localPlayer = getLocalPlayer()
  32. local vehiclesWithIndicator = {}
  33.  
  34.  
  35. -- Precalculate some stuff
  36. INDICATOR_AUTOSWITCH_OFF_THRESHOLD = INDICATOR_AUTOSWITCH_OFF_THRESHOLD / 90
  37.  
  38.  
  39. --[[
  40. * vectorLength
  41. Gets the length of a vector.
  42. --]]
  43. local function vectorLength ( vector )
  44.     return math.sqrt ( vector[1]*vector[1] + vector[2]*vector[2] + vector[3]*vector[3] )
  45. end
  46.  
  47. --[[
  48. * normalizeVector
  49. Normalizes a vector, when possible, and returns the normalized vector plus the length.
  50. --]]
  51. local function normalizeVector ( vector )
  52.     local length = vectorLength ( vector )
  53.     if length > 0 then
  54.         local normalizedVector = {}
  55.         normalizedVector[1] = vector[1] / length
  56.         normalizedVector[2] = vector[2] / length
  57.         normalizedVector[3] = vector[3] / length
  58.         return normalizedVector, length
  59.     else
  60.         return nil, length
  61.     end
  62. end
  63.  
  64. --[[
  65. * crossProduct
  66. Calculates the cross product of two vectors.
  67. --]]
  68. local function crossProduct ( v, w )
  69.     local result = {}
  70.     result[1] = v[2]*w[3] - v[3]*w[2]
  71.     result[2] = w[1]*v[3] - w[3]*v[1]
  72.     result[3] = v[1]*w[2] - v[2]*w[1]
  73.     return result
  74. end
  75.  
  76. --[[
  77. * getFakeVelocity
  78. Gets a fake unitary velocity for a vehicle calculated using the current vehicle angle.
  79. --]]
  80. local function getFakeVelocity ( vehicle )
  81.     -- Get the angle around the Z axis
  82.     local _, _, angle = getElementRotation ( vehicle )
  83.     local velocity = { 0, 0, 0 }
  84.     velocity[1] = -math.sin ( angle )
  85.     velocity[2] = math.cos ( angle )
  86.     return velocity
  87. end
  88.  
  89. --[[
  90. * createIndicator
  91. Creates a marker for an indicator.
  92. --]]
  93. local function createIndicator ()
  94.     local x, y, z = getElementPosition(localPlayer)
  95.     local indicator = createMarker (    x, y, z+4, 'corona',
  96.                                         INDICATOR_SIZE,
  97.                                         INDICATOR_COLOR[1],
  98.                                         INDICATOR_COLOR[2],
  99.                                         INDICATOR_COLOR[3],
  100.                                         0
  101.                                     )
  102.     setElementStreamable ( indicator, false )
  103.     return indicator
  104. end
  105.  
  106. --[[
  107. * createIndicatorState
  108. Creates a table with information about the indicators state.
  109. --]]
  110. local function createIndicatorState ( vehicle, indicatorLeft, indicatorRight )
  111.     local t = { vehicle       = vehicle,        -- The vehicle that this state refers to
  112.                 left          = indicatorLeft,  -- The state of the left indicator
  113.                 right         = indicatorRight, -- The state of the right indicator
  114.                 coronaLeft    = nil,            -- The corona elements for the left indicator
  115.                 coronaRight   = nil,            -- The corona elements for the right indicator
  116.                 nextChange    = 0,              -- The time for the next change of the indicators
  117.                 timeElapsed   = 0,              -- Elapsed time since the last change
  118.                 currentState  = false,          -- If set to true, the coronas are activated.
  119.                 activationDir = nil,            -- Direction that the vehicle was following when the indicator got activated, for auto shut down.
  120.               }
  121.     return t
  122. end
  123.  
  124. --[[
  125. * updateIndicatorState
  126. Updates the indicator state (i.e. creates/destroys the coronas).
  127. --]]
  128. local function updateIndicatorState ( state )
  129.     if not state then return end
  130.  
  131.     -- Store the number of indicators activated
  132.     local numberOfIndicators = 0
  133.    
  134.     -- Get the vehicle bounding box
  135.     local xmin, ymin, zmin, xmax, ymax, zmax = getElementBoundingBox ( state.vehicle )
  136.  
  137.     -- Transform the bounding box positions to fit properly the vehicle
  138.     xmin = xmin + 0.2
  139.     xmax = xmax - 0.2
  140.     ymin = ymin + 0.2
  141.     ymax = ymax - 0.2
  142.     zmin = zmin + 0.6
  143.  
  144.     -- Check the left indicator
  145.     if state.left then
  146.         if not state.coronaLeft then
  147.             state.coronaLeft = { createIndicator (), createIndicator () }
  148.             attachElements ( state.coronaLeft[1], state.vehicle, xmin,  ymax, zmin )
  149.             attachElements ( state.coronaLeft[2], state.vehicle, xmin, -ymax, zmin )
  150.         end
  151.         numberOfIndicators = numberOfIndicators + 1
  152.     elseif state.coronaLeft then
  153.         destroyElement ( state.coronaLeft[1] )
  154.         destroyElement ( state.coronaLeft[2] )
  155.         state.coronaLeft = nil
  156.     end
  157.    
  158.     -- Check the right indicator
  159.     if state.right then
  160.         if not state.coronaRight then
  161.             state.coronaRight = { createIndicator (), createIndicator () }
  162.             attachElements ( state.coronaRight[1], state.vehicle, -xmin,  ymax, zmin )
  163.             attachElements ( state.coronaRight[2], state.vehicle, -xmin, -ymax, zmin )
  164.         end
  165.         numberOfIndicators = numberOfIndicators + 1
  166.     elseif state.coronaRight then
  167.         destroyElement ( state.coronaRight[1] )
  168.         destroyElement ( state.coronaRight[2] )
  169.         state.coronaRight = nil
  170.     end
  171.    
  172.     -- Check if this is the car that you are driving and that there is one and only one indicator
  173.     -- to enable auto switching off
  174.     if numberOfIndicators == 1 and getVehicleOccupant ( state.vehicle, 0 ) == localPlayer then
  175.         -- Store the current velocity, normalized, to check when will we have to switch it off.
  176.         state.activationDir = normalizeVector ( { getElementVelocity ( state.vehicle ) } )
  177.         if not state.activationDir then
  178.             -- The vehicle is stopped, get a fake velocity from the angle.
  179.             state.activationDir = getFakeVelocity ( state.vehicle )
  180.         end
  181.     else
  182.         state.activationDir = nil
  183.     end
  184. end
  185.  
  186. --[[
  187. * destroyIndicatorState
  188. Destroys an indicator state, deleting all its resources.
  189. --]]
  190. local function destroyIndicatorState ( state )
  191.     if not state then return end
  192.    
  193.     -- Destroy the left coronas
  194.     if state.coronaLeft then
  195.         destroyElement ( state.coronaLeft[1] )
  196.         destroyElement ( state.coronaLeft[2] )
  197.         state.coronaLeft = nil
  198.     end
  199.    
  200.     -- Destroy the right coronas
  201.     if state.coronaRight then
  202.         destroyElement ( state.coronaRight[1] )
  203.         destroyElement ( state.coronaRight[2] )
  204.         state.coronaRight = nil
  205.     end
  206.    
  207.     -- If I am the driver, reset the element data.
  208.     if getVehicleOccupant ( state.vehicle ) == localPlayer then
  209.         setElementData ( state.vehicle, 'i:left', false, true )
  210.         setElementData ( state.vehicle, 'i:right', false, true )
  211.     end
  212. end
  213.  
  214. --[[
  215. * performIndicatorChecks
  216. Checks how the indicators state should be: created, updated or destroyed.
  217. --]]
  218. local function performIndicatorChecks ( vehicle )
  219.     -- Get the current indicator states
  220.     local indicatorLeft = getElementData(vehicle, 'i:left')
  221.     local indicatorRight = getElementData(vehicle, 'i:right')
  222.  
  223.     -- Check if we at least have one indicator running
  224.     local anyIndicator = indicatorLeft or indicatorRight
  225.    
  226.     -- Grab the current indicators state in the flashing period.
  227.     local currentState = vehiclesWithIndicator [ vehicle ]
  228.  
  229.     -- If there's any indicator running, push it to the list of vehicles to draw the indicator.
  230.     -- Else, remove it from the list.
  231.     if anyIndicator then
  232.         -- Check if there is already a state for this vehicle
  233.         if currentState then
  234.             -- Update the state
  235.             currentState.left = indicatorLeft
  236.             currentState.right = indicatorRight
  237.         else
  238.             -- Create a new state
  239.             currentState = createIndicatorState ( vehicle, indicatorLeft, indicatorRight )
  240.             vehiclesWithIndicator [ vehicle ] = currentState
  241.         end
  242.         updateIndicatorState ( currentState )
  243.     elseif currentState then
  244.         -- Destroy the current state
  245.         destroyIndicatorState ( currentState )
  246.         vehiclesWithIndicator [ vehicle ] = nil
  247.     end
  248. end
  249.  
  250. --[[
  251. * setIndicatorsAlpha
  252. Sets all the active indicators alpha.
  253. --]]
  254. local function setIndicatorsAlpha ( state, alpha )
  255.     if state.coronaLeft then
  256.         setMarkerColor ( state.coronaLeft[1],   INDICATOR_COLOR[1],
  257.                                                 INDICATOR_COLOR[2],
  258.                                                 INDICATOR_COLOR[3],
  259.                                                 alpha )
  260.         setMarkerColor ( state.coronaLeft[2],   INDICATOR_COLOR[1],
  261.                                                 INDICATOR_COLOR[2],
  262.                                                 INDICATOR_COLOR[3],
  263.                                                 alpha )
  264.     end
  265.     if state.coronaRight then
  266.         setMarkerColor ( state.coronaRight[1],  INDICATOR_COLOR[1],
  267.                                                 INDICATOR_COLOR[2],
  268.                                                 INDICATOR_COLOR[3],
  269.                                                 alpha )
  270.         setMarkerColor ( state.coronaRight[2],  INDICATOR_COLOR[1],
  271.                                                 INDICATOR_COLOR[2],
  272.                                                 INDICATOR_COLOR[3],
  273.                                                 alpha )
  274.     end
  275. end
  276.  
  277. --[[
  278. * processIndicators
  279. Processes the indicators switching, and solves some MTA bugs.
  280. --]]
  281. local function processIndicators ( state )
  282.     -- Check first if the vehicle is blown up.
  283.     if getElementHealth ( state.vehicle ) == 0 then
  284.         -- Destroy the state.
  285.         destroyIndicatorState ( state )
  286.         vehiclesWithIndicator [ state.vehicle ] = nil
  287.         return
  288.     end
  289.    
  290.     -- Check if we must automatically deactivate the indicators.
  291.     if state.activationDir then
  292.         -- Get the current velocity and normalize it
  293.         local currentVelocity = normalizeVector ( { getElementVelocity ( state.vehicle ) } )
  294.        
  295.         -- If the vehicle is stopped, calculate a fake velocity from the angle.
  296.         if not currentVelocity then
  297.             currentVelocity = getFakeVelocity ( state.vehicle )
  298.         end
  299.        
  300.         -- Calculate the cross product between the velocities to get the angle and direction of any turn.
  301.         local cross = crossProduct ( state.activationDir, currentVelocity )
  302.            
  303.         -- Get the length of the resulting vector to calculate the "amount" of direction change [0..1].
  304.         local length = vectorLength ( cross )
  305.            
  306.         -- If the turn is over the threshold, deactivate the indicators
  307.         if length > INDICATOR_AUTOSWITCH_OFF_THRESHOLD then
  308.             -- Destroy the state
  309.             destroyIndicatorState ( state )
  310.             vehiclesWithIndicator [ state.vehicle ] = nil
  311.             return
  312.         end
  313.     end
  314.  
  315.     -- Check if we must switch the state
  316.     if state.nextChange <= state.timeElapsed then
  317.         -- Turn to switched on indicators, in both cases. When turning on,
  318.         -- it goes straight to the full alpha mode. When turning off, it
  319.         -- fades out from full alpha to full transparent.
  320.         setIndicatorsAlpha ( state, INDICATOR_COLOR[4] )
  321.        
  322.         -- Switch the state
  323.         state.currentState = not state.currentState
  324.    
  325.         -- Get the vehicle that we are in
  326.         local playerVehicle = getPedOccupiedVehicle ( localPlayer )
  327.        
  328.         -- Restart the timers and play a sound if we are in that vehicle
  329.         state.timeElapsed = 0
  330.         if state.currentState then
  331.             state.nextChange = INDICATOR_SWITCH_TIMES[1]
  332.             --if playerVehicle == state.vehicle then playSoundFrontEnd ( 37 ) end
  333.         else
  334.             state.nextChange = INDICATOR_SWITCH_TIMES[2]
  335.             --if playerVehicle == state.vehicle then playSoundFrontEnd ( 38 ) end
  336.         end
  337.        
  338.  
  339.     -- Check if we are turning them off
  340.     elseif state.currentState == false then
  341.         -- If the time elapsed is bigger than the time to fade out, then
  342.         -- just set the alpha to zero. Else, set it to the current alpha
  343.         -- value.
  344.         if state.timeElapsed >= INDICATOR_FADE_MS then
  345.             setIndicatorsAlpha ( state, 0 )
  346.         else
  347.             setIndicatorsAlpha ( state, (1 - (state.timeElapsed / INDICATOR_FADE_MS)) * INDICATOR_COLOR[4] )
  348.         end
  349.     end
  350. end
  351.  
  352. --[[
  353. * onClientElementDataChange
  354. Detects when the indicator state of a vehicle changes.
  355. --]]
  356. addEventHandler('onClientElementDataChange', root, function ( dataName, oldValue )
  357.     -- Check that the source is a vehicle and that the data name is what we are looking for.
  358.     if getElementType(source) == 'vehicle' and ( dataName == 'i:left' or dataName == 'i:right' ) then
  359.         -- If the vehicle is not streamed in, don't do anything.
  360.         if isElementStreamedIn(source) then
  361.             -- Perform the indicator checks for the new indicator states.
  362.             performIndicatorChecks ( source )
  363.         end
  364.     end
  365. end)
  366.  
  367. --[[
  368. * onClientElementStreamIn
  369. Detects when a vehicle streams in, to check if we must draw the indicators.
  370. --]]
  371. addEventHandler('onClientElementStreamIn', root, function ()
  372.     if getElementType(source) == 'vehicle' then
  373.         -- Perform the indicator checks for the just streamed in vehicle.
  374.         performIndicatorChecks ( source )
  375.     end
  376. end)
  377.  
  378. --[[
  379. * onClientElementStreamOut
  380. Detects when a vehicle streams out, to destroy its state.
  381. --]]
  382. addEventHandler('onClientElementStreamOut', root, function ()
  383.     if getElementType(source) == 'vehicle' then
  384.         -- Grab the current indicators state
  385.         local currentState = vehiclesWithIndicator [ source ]
  386.        
  387.         -- If it has a state, remove it.
  388.         if currentState then
  389.             destroyIndicatorState ( currentState )
  390.             vehiclesWithIndicator [ source ] = nil
  391.         end
  392.     end
  393. end)
  394.  
  395. --[[
  396. * indicator_left and indicator_right commands
  397. Changes the state of the indicators for the current vehicle.
  398. --]]
  399. local function switchIndicatorState ( indicator )
  400.     -- First check that we are in a vehicle.
  401.     local v = getPedOccupiedVehicle(localPlayer)
  402.     if v then
  403.         -- check for the correct vehicle type
  404.         if getVehicleType(v) == "Automobile" or getVehicleType(v) == "Bike" or getVehicleType(v) == "Quad" then
  405.             -- Check that we are the vehicle driver
  406.             if getVehicleOccupant(v, 0) == localPlayer then
  407.                 -- Switch the indicator state
  408.                 local dataName = 'i:' .. indicator
  409.                 local currentValue = getElementData(v, dataName) or false
  410.                 -- UNSAFE
  411.                 setElementData(v, dataName, not currentValue, true)
  412.             end
  413.         end
  414.     end
  415. end
  416. addCommandHandler('indicator_left', function () switchIndicatorState('left') end, false)
  417. addCommandHandler('indicator_right', function () switchIndicatorState('right') end, false)
  418.  
  419. --[[
  420. * onClientPreRender
  421. Calls processIndicators for every vehicle with the indicators activated.
  422. --]]
  423. addEventHandler('onClientPreRender', root, function ( timeSlice )
  424.     -- Process every vehicle with indicators
  425.     for vehicle, state in pairs(vehiclesWithIndicator) do
  426.         state.timeElapsed = state.timeElapsed + timeSlice
  427.         processIndicators ( state, state.lastChange )
  428.     end
  429. end)
  430.  
  431. function handleKeyBind( keyPressed, keyState )
  432.     if (keyPressed == "[") then
  433.         switchIndicatorState('left')
  434.     elseif (keyPressed == "]") then
  435.         switchIndicatorState('right')
  436.     end
  437. end
  438. --[[
  439. * onClientResourceStart
  440. Starts everything up.
  441. --]]
  442. addEventHandler('onClientResourceStart', getResourceRootElement(getThisResource()), function ()
  443.     -- Check all streamed in vehicles that have any indicator activated and create a state for them.
  444.     local vehicles = getElementsByType ( 'vehicle' )
  445.     for k, vehicle in ipairs(vehicles) do
  446.         if isElementStreamedIn ( vehicle ) then
  447.             local indicatorLeft = getElementData ( vehicle, 'i:left' )
  448.             local indicatorRight = getElementData ( vehicle, 'i:right' )
  449.             if indicatorLeft or indicatorRight then
  450.                 performIndicatorChecks ( vehicle )
  451.             end
  452.         end
  453.     end
  454.      
  455.     bindKey ( "[", "down", handleKeyBind )
  456.     bindKey ( "]", "down", handleKeyBind )
  457. end, false)
  458.  
  459. --[[
  460. * onClientVehicleRespawn
  461. Restore the state for vehicles respawning.
  462. --]]
  463. addEventHandler('onClientVehicleRespawn', root, function ()
  464.     if isElementStreamedIn ( source ) then
  465.         performIndicatorChecks ( source )
  466.     end
  467. end)
  468.  
  469. --[[
  470. * onClientElementDestroy
  471. Destroys the state for a vehicle when it's deleted.
  472. --]]
  473. addEventHandler('onClientElementDestroy', root, function ()
  474.     if getElementType ( source ) == 'vehicle' then
  475.         local currentState = vehiclesWithIndicator [ source ]
  476.         if currentState then
  477.             -- Destroy the state
  478.             destroyIndicatorState ( currentState )
  479.             vehiclesWithIndicator [ source ] = nil
  480.         end
  481.     end
  482. end)
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top