fixing ulc script
@@ -0,0 +1,56 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"24ramambo"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {10},
|
||||
dExtras = {11}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
hornExtras = {},
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = false,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = false,
|
||||
driverSide = {enable = {}, disable = {}},
|
||||
passSide = {enable = {}, disable = {}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "Stage 1", key = 1, color = "red", extra = 2, linkedExtras = {2}, oppositeExtras = {}, offExtras = {1}, repair = false},
|
||||
{label = "Stage 2", key = 2, color = "red", extra = 1, linkedExtras = {1}, oppositeExtras = {}, offExtras = {2}, repair = false},
|
||||
{label = "Cruise", key = 3, color = "red", extra = 3, linkedExtras = {3}, oppositeExtras = {}, offExtras = {2,1,4,5,6}, repair = false},
|
||||
{label = "TKDN", key = 4, color = "red", extra = 4, linkedExtras = {4}, oppositeExtras = {}, offExtras = {3,2,1,5,6}, repair = false},
|
||||
{label = "<-", key = 5, color = "amber", extra = 5, linkedExtras = {5}, oppositeExtras = {}, offExtras = {6}, repair = false},
|
||||
{label = "->", key = 6, color = "amber", extra = 6, linkedExtras = {6}, oppositeExtras = {}, offExtras = {5}, repair = false}
|
||||
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@ return {names = {"24sub"},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {},
|
||||
pExtras = {2},
|
||||
dExtras = {1}
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {10},
|
||||
dExtras = {11}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CVehicleModelInfoVariation>
|
||||
<variationData>
|
||||
<Item>
|
||||
<modelName>ccso1</modelName>
|
||||
<colors>
|
||||
<Item>
|
||||
<indices content="char_array">
|
||||
0
|
||||
134
|
||||
0
|
||||
64
|
||||
64
|
||||
64
|
||||
64
|
||||
</indices>
|
||||
<liveries>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
<Item value="false"/>
|
||||
</liveries>
|
||||
</Item>
|
||||
</colors>
|
||||
<kits>
|
||||
<Item>0_default_modkit</Item>
|
||||
</kits>
|
||||
<windowsWithExposedEdges/>
|
||||
<plateProbabilities>
|
||||
<Probabilities>
|
||||
<Item>
|
||||
<Name>Police guv plate</Name>
|
||||
<Value value="100"/>
|
||||
</Item>
|
||||
</Probabilities>
|
||||
</plateProbabilities>
|
||||
<lightSettings value="1649874"/>
|
||||
<sirenSettings value="46546544"/>
|
||||
</Item>
|
||||
</variationData>
|
||||
</CVehicleModelInfoVariation>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<CHandlingDataMgr>
|
||||
<HandlingData>
|
||||
<Item type="CHandlingData">
|
||||
<handlingName>FUCKASSEXPLORER1</handlingName>
|
||||
<fMass value="2004.000000" />
|
||||
<fInitialDragCoeff value="5.900000" />
|
||||
<fPercentSubmerged value="85.000000" />
|
||||
<vecCentreOfMassOffset x="0.000000" y="-0.100000" z="0.000000" />
|
||||
<vecInertiaMultiplier x="1.000000" y="1.000000" z="1.200000" />
|
||||
<fDriveBiasFront value="0.500000" />
|
||||
<nInitialDriveGears value="10" />
|
||||
<fInitialDriveForce value="0.400000" />
|
||||
<fDriveInertia value="1.000000" />
|
||||
<fClutchChangeRateScaleUpShift value="2.000000" />
|
||||
<fClutchChangeRateScaleDownShift value="2.000000" />
|
||||
<fInitialDriveMaxFlatVel value="185.000000" />
|
||||
<fBrakeForce value="1.400000" />
|
||||
<fBrakeBiasFront value="0.650000" />
|
||||
<fHandBrakeForce value="0.800000" />
|
||||
<fSteeringLock value="40.000000" />
|
||||
<fTractionCurveMax value="2.800000" />
|
||||
<fTractionCurveMin value="2.300000" />
|
||||
<fTractionCurveLateral value="22.500000" />
|
||||
<fTractionSpringDeltaMax value="0.150000" />
|
||||
<fLowSpeedTractionLossMult value="1.000000" />
|
||||
<fCamberStiffnesss value="0.000000" />
|
||||
<fTractionBiasFront value="0.480000" />
|
||||
<fTractionLossMult value="1.000000" />
|
||||
<fSuspensionForce value="2.500000" />
|
||||
<fSuspensionCompDamp value="1.400000" />
|
||||
<fSuspensionReboundDamp value="1.800000" />
|
||||
<fSuspensionUpperLimit value="0.120000" />
|
||||
<fSuspensionLowerLimit value="-0.130000" />
|
||||
<fSuspensionRaise value="0.000000" />
|
||||
<fSuspensionBiasFront value="0.500000" />
|
||||
<fAntiRollBarForce value="0.900000" />
|
||||
<fAntiRollBarBiasFront value="0.550000" />
|
||||
<fRollCentreHeightFront value="0.400000" />
|
||||
<fRollCentreHeightRear value="0.400000" />
|
||||
<fCollisionDamageMult value="0.700000" />
|
||||
<fWeaponDamageMult value="1.000000" />
|
||||
<fDeformationDamageMult value="0.800000" />
|
||||
<fEngineDamageMult value="1.200000" />
|
||||
<fPetrolTankVolume value="65.000000" />
|
||||
<fOilVolume value="5.000000" />
|
||||
<fSeatOffsetDistX value="0.000000" />
|
||||
<fSeatOffsetDistY value="0.000000" />
|
||||
<fSeatOffsetDistZ value="0.000000" />
|
||||
<nMonetaryValue value="35000" />
|
||||
<strModelFlags>440010</strModelFlags>
|
||||
<strHandlingFlags>0</strHandlingFlags>
|
||||
<strDamageFlags>0</strDamageFlags>
|
||||
<AIHandling>AVERAGE</AIHandling>
|
||||
<SubHandlingData>
|
||||
<Item type="CCarHandlingData">
|
||||
<fBackEndPopUpCarImpulseMult value="0.100000" />
|
||||
<fBackEndPopUpBuildingImpulseMult value="0.030000" />
|
||||
<fBackEndPopUpMaxDeltaSpeed value="0.600000" />
|
||||
</Item>
|
||||
<Item type="NULL" />
|
||||
<Item type="NULL" />
|
||||
</SubHandlingData>
|
||||
</Item>
|
||||
</HandlingData>
|
||||
</CHandlingDataMgr>
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"ccso1"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {"ccso1, "615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo","ccso1", "gpdchief1",},
|
||||
pExtras = {1,2},
|
||||
dExtras = {3,4,10}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
hornExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = false,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = false,
|
||||
driverSide = {enable = {}, disable = {}},
|
||||
passSide = {enable = {}, disable = {}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "Park", key = 1, color = "green", extra = 1, linkedExtras = {2}, oppositeExtras = {}, offExtras = {3,4,5,6}, repair = false},
|
||||
{label = "Drive", key = 2, color = "green", extra = 3, linkedExtras = {4}, oppositeExtras = {}, offExtras = {1,2,6,5}, repair = false},
|
||||
{label = "Takedowns", key = 3, color = "green", extra = 5, linkedExtras = {}, oppositeExtras = {}, offExtras = {3}, repair = false},
|
||||
{label = "Cruise", key = 4, color = "green", extra = 6, linkedExtras = {7,8,9}, oppositeExtras = {}, offExtras = {}, repair = false}
|
||||
},
|
||||
stages = {
|
||||
useStages = false,
|
||||
stageKeys = {},
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CVehicleModelInfo__InitDataList>
|
||||
<residentTxd>vehshare</residentTxd>
|
||||
<residentAnims />
|
||||
<InitDatas>
|
||||
<Item>
|
||||
<modelName>ccso1</modelName>
|
||||
<txdName>ccso1</txdName>
|
||||
<handlingId>FUCKASSEXPLORER1</handlingId>
|
||||
<gameName>CODE3</gameName>
|
||||
<vehicleMakeName />
|
||||
<expressionDictName>null</expressionDictName>
|
||||
<expressionName>null</expressionName>
|
||||
<animConvRoofDictName>null</animConvRoofDictName>
|
||||
<animConvRoofName>null</animConvRoofName>
|
||||
<animConvRoofWindowsAffected />
|
||||
<ptfxAssetName>null</ptfxAssetName>
|
||||
<audioNameHash>ecoboostv6</audioNameHash>
|
||||
<layout>LAYOUT_STD_EXITFIXUP</layout>
|
||||
<coverBoundOffsets>POLICE3_COVER_OFFSET_INFO</coverBoundOffsets>
|
||||
<explosionInfo>EXPLOSION_INFO_DEFAULT</explosionInfo>
|
||||
<scenarioLayout />
|
||||
<cameraName>DEFAULT_FOLLOW_VEHICLE_CAMERA</cameraName>
|
||||
<aimCameraName>MID_BOX_VEHICLE_AIM_CAMERA</aimCameraName>
|
||||
<bonnetCameraName>VEHICLE_BONNET_CAMERA_MID_NEAR</bonnetCameraName>
|
||||
<povCameraName>DEFAULT_POV_CAMERA</povCameraName>
|
||||
<FirstPersonDriveByIKOffset x="0.000000" y="-0.060000" z="-0.030000" />
|
||||
<FirstPersonDriveByUnarmedIKOffset x="0.000000" y="0.000000" z="-0.020000" />
|
||||
<FirstPersonProjectileDriveByIKOffset x="0.055000" y="-0.075000" z="-0.045000" />
|
||||
<FirstPersonProjectileDriveByPassengerIKOffset x="-0.055000" y="-0.075000" z="-0.045000" />
|
||||
<FirstPersonProjectileDriveByRearLeftIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonProjectileDriveByRearRightIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonDriveByLeftPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonDriveByRightPassengerIKOffset x="0.000000" y="-0.060000" z="-0.030000" />
|
||||
<FirstPersonDriveByRightRearPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonDriveByLeftPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonDriveByRightPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<FirstPersonMobilePhoneOffset x="0.130000" y="0.275000" z="0.530000" />
|
||||
<FirstPersonPassengerMobilePhoneOffset x="0.136000" y="0.223000" z="0.425000" />
|
||||
<FirstPersonMobilePhoneSeatIKOffset>
|
||||
<Item>
|
||||
<Offset x="0.136000" y="0.156000" z="0.445000" />
|
||||
<SeatIndex value="2" />
|
||||
</Item>
|
||||
<Item>
|
||||
<Offset x="0.136000" y="0.156000" z="0.445000" />
|
||||
<SeatIndex value="3" />
|
||||
</Item>
|
||||
</FirstPersonMobilePhoneSeatIKOffset>
|
||||
<PovCameraOffset x="0.000000" y="-0.175000" z="0.675000" />
|
||||
<PovCameraVerticalAdjustmentForRollCage value="0.000000" />
|
||||
<PovPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<PovRearPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<vfxInfoName>VFXVEHICLEINFO_CAR_GENERIC</vfxInfoName>
|
||||
<shouldUseCinematicViewMode value="true" />
|
||||
<shouldCameraTransitionOnClimbUpDown value="false" />
|
||||
<shouldCameraIgnoreExiting value="false" />
|
||||
<AllowPretendOccupants value="true" />
|
||||
<AllowJoyriding value="false" />
|
||||
<AllowSundayDriving value="false" />
|
||||
<AllowBodyColorMapping value="false" />
|
||||
<wheelScale value="0.244000" />
|
||||
<wheelScaleRear value="0.244000" />
|
||||
<dirtLevelMin value="0.000000" />
|
||||
<dirtLevelMax value="0.300000" />
|
||||
<envEffScaleMin value="0.000000" />
|
||||
<envEffScaleMax value="1.000000" />
|
||||
<envEffScaleMin2 value="0.000000" />
|
||||
<envEffScaleMax2 value="1.000000" />
|
||||
<damageMapScale value="0.600000" />
|
||||
<damageOffsetScale value="1.000000" />
|
||||
<diffuseTint value="0x00FFFFFF" />
|
||||
<steerWheelMult value="1.000000" />
|
||||
<HDTextureDist value="5.000000" />
|
||||
<lodDistances content="float_array">
|
||||
35.000000
|
||||
55.000000
|
||||
70.000000
|
||||
140.000000
|
||||
500.000000
|
||||
500.000000
|
||||
</lodDistances>
|
||||
<minSeatHeight value="0.83" />
|
||||
<identicalModelSpawnDistance value="20" />
|
||||
<maxNumOfSameColor value="10" />
|
||||
<defaultBodyHealth value="1000.000000" />
|
||||
<pretendOccupantsScale value="1.000000" />
|
||||
<visibleSpawnDistScale value="1.000000" />
|
||||
<trackerPathWidth value="2.000000" />
|
||||
<weaponForceMult value="1.000000" />
|
||||
<frequency value="100" />
|
||||
<swankness>SWANKNESS_0</swankness>
|
||||
<maxNum value="2" />
|
||||
<flags>FLAG_EXTRAS_STRONG FLAG_HAS_LIVERY FLAG_EXTRAS_ALL FLAG_LAW_ENFORCEMENT FLAG_EMERGENCY_SERVICE FLAG_NO_RESPRAY FLAG_DONT_SPAWN_IN_CARGEN FLAG_HAS_INTERIOR_EXTRAS FLAG_REPORT_CRIME_IF_STANDING_ON</flags>
|
||||
<type>VEHICLE_TYPE_CAR</type>
|
||||
<plateType>VPT_BACK_PLATES</plateType>
|
||||
<dashboardType>VDT_FEROCI</dashboardType>
|
||||
<vehicleClass>VC_EMERGENCY</vehicleClass>
|
||||
<wheelType>VWT_SPORT</wheelType>
|
||||
<trailers />
|
||||
<additionalTrailers />
|
||||
<drivers>
|
||||
<Item>
|
||||
<driverName>S_M_Y_Cop_01</driverName>
|
||||
<npcName />
|
||||
</Item>
|
||||
</drivers>
|
||||
<extraIncludes />
|
||||
<doorsWithCollisionWhenClosed />
|
||||
<driveableDoors />
|
||||
<bumpersNeedToCollideWithMap value="false" />
|
||||
<needsRopeTexture value="false" />
|
||||
<requiredExtras />
|
||||
<rewards>
|
||||
<Item>REWARD_WEAPON_PUMPSHOTGUN</Item>
|
||||
<Item>REWARD_AMMO_PUMPSHOTGUN_ENTER_VEHICLE</Item>
|
||||
<Item>REWARD_STAT_WEAPON</Item>
|
||||
</rewards>
|
||||
<cinematicPartCamera>
|
||||
<Item>WHEEL_FRONT_RIGHT_CAMERA</Item>
|
||||
<Item>WHEEL_FRONT_LEFT_CAMERA</Item>
|
||||
<Item>WHEEL_REAR_RIGHT_CAMERA</Item>
|
||||
<Item>WHEEL_REAR_LEFT_CAMERA</Item>
|
||||
</cinematicPartCamera>
|
||||
<NmBraceOverrideSet />
|
||||
<buoyancySphereOffset x="0.000000" y="0.000000" z="0.000000" />
|
||||
<buoyancySphereSizeScale value="1.000000" />
|
||||
<pOverrideRagdollThreshold type="NULL" />
|
||||
<firstPersonDrivebyData>
|
||||
<Item>STD_POLICE3_FRONT_LEFT</Item>
|
||||
<Item>STD_POLICE3_FRONT_RIGHT</Item>
|
||||
<Item>STD_POLICE2_REAR_LEFT</Item>
|
||||
<Item>STD_POLICE2_REAR_RIGHT</Item>
|
||||
</firstPersonDrivebyData>
|
||||
</Item>
|
||||
</InitDatas>
|
||||
<txdRelationships>
|
||||
<Item>
|
||||
<parent>vehicles_feroci_interior</parent>
|
||||
<child>FPIUK</child>
|
||||
</Item>
|
||||
</txdRelationships>
|
||||
</CVehicleModelInfo__InitDataList>
|
||||
@@ -14,10 +14,10 @@ return {names = {"st23tahoe"},
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = false,
|
||||
syncWith = {},
|
||||
pExtras = {4},
|
||||
dExtras = {3,5}
|
||||
useSync = true,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {11},
|
||||
dExtras = {10,15}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"128"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {11},
|
||||
dExtras = {10}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
hornExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = false,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = false,
|
||||
driverSide = {enable = {}, disable = {}},
|
||||
passSide = {enable = {}, disable = {}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "GSP Cover", key = 1, color = "green", extra = 1, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Park Lights", key = 2, color = "green", extra = 2, linkedExtras = {3,4,5}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Drive Lights", key = 3, color = "green", extra = 6, linkedExtras = {7}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Cruise Lights", key = 4, color = "green", extra = 8, linkedExtras = {9,10,11}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Flood Lights", key = 5, color = "green", extra = 12, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false}
|
||||
},
|
||||
stages = {
|
||||
useStages = false,
|
||||
stageKeys = {},
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"640"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {10},
|
||||
dExtras = {11}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = true,
|
||||
hornExtras = {12},
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = true,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {7},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = true,
|
||||
driverSide = {enable = {}, disable = {5}},
|
||||
passSide = {enable = {}, disable = {6}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "Main Lights", key = 1, color = "green", extra = 1, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Cruise Lights", key = 2, color = "green", extra = 3, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false}
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"704"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = false,
|
||||
useSync = false,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {10},
|
||||
dExtras = {11}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
hornExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = false,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = false,
|
||||
driverSide = {enable = {}, disable = {}},
|
||||
passSide = {enable = {}, disable = {}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "GSP Cover", key = 1, color = "green", extra = 1, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Park Lights", key = 2, color = "green", extra = 2, linkedExtras = {3,4,5}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Drive Lights", key = 3, color = "green", extra = 6, linkedExtras = {7}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Cruise Lights", key = 4, color = "green", extra = 8, linkedExtras = {9,10,11}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Flood Lights", key = 5, color = "green", extra = 12, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false}
|
||||
},
|
||||
stages = {
|
||||
useStages = false,
|
||||
stageKeys = {},
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
--[[
|
||||
Ultimate Lighting Controller Config
|
||||
the ULC resource is required to use this configuration
|
||||
get the resource here: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/latest
|
||||
To learn how to setup and use ULC visit here: https://docs.dwnstr.com/ulc/overview
|
||||
]]
|
||||
|
||||
return {names = {"gpd7"},
|
||||
steadyBurnConfig = {
|
||||
forceOn = false, useTime = false,
|
||||
disableWithLights = false,
|
||||
sbExtras = {}
|
||||
},
|
||||
parkConfig = {
|
||||
usePark = true,
|
||||
useSync = true,
|
||||
syncWith = {"615", "376", "gpd7", "640", "128", "704", "st23tahoe", "24sub", "24ramambo", "23sierrafire", "23gmcleoslick", "23gmcleo", "ccso1", "gpdchief1" },
|
||||
pExtras = {11},
|
||||
dExtras = {10}
|
||||
},
|
||||
hornConfig = {
|
||||
useHorn = false,
|
||||
hornExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
brakeConfig = {
|
||||
useBrakes = false,
|
||||
speedThreshold = 3,
|
||||
brakeExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
reverseConfig = {
|
||||
useReverse = false,
|
||||
reverseExtras = {},
|
||||
disableExtras = {}
|
||||
},
|
||||
doorConfig = {
|
||||
useDoors = false,
|
||||
driverSide = {enable = {}, disable = {}},
|
||||
passSide = {enable = {}, disable = {}},
|
||||
trunk = {enable ={}, disable = {}}
|
||||
},
|
||||
buttons = {
|
||||
{label = "Front", key = 1, color = "green", extra = 1, linkedExtras = {}, oppositeExtras = {}, offExtras = {6,7}, repair = false},
|
||||
{label = "Front White", key = 2, color = "green", extra = 2, linkedExtras = {}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Rear", key = 3, color = "green", extra = 3, linkedExtras = {4}, oppositeExtras = {}, offExtras = {}, repair = false},
|
||||
{label = "Takedowns", key = 4, color = "green", extra = 5, linkedExtras = {}, oppositeExtras = {}, offExtras = {1,2}, repair = false},
|
||||
{label = "Cruise", key = 5, color = "green", extra = 6, linkedExtras = {7}, oppositeExtras = {}, offExtras = {}, repair = false}
|
||||
},
|
||||
stages = {
|
||||
useStages = false,
|
||||
stageKeys = {},
|
||||
},
|
||||
defaultStages = {
|
||||
useDefaults = false,
|
||||
enableKeys = {},
|
||||
disableKeys = {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
-------------------------
|
||||
--------- SOUND ---------
|
||||
-------------------------
|
||||
|
||||
function PlayBeep(highPitched)
|
||||
if highPitched then
|
||||
PlaySoundFrontend(-1, "5_SEC_WARNING", "HUD_MINI_GAME_SOUNDSET", 1)
|
||||
else
|
||||
PlaySoundFrontend(-1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", 1)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
coming soon, once client options arrive it will be opt in per client
|
||||
|
||||
---------------
|
||||
-- REMINDERS --
|
||||
---------------
|
||||
local mute = false
|
||||
|
||||
if Config.reminderBeeps then
|
||||
CreateThread(function()
|
||||
while true do Wait(Config.reminderBeepTime * 1000)
|
||||
if Lights and not mute then PlayBeep(false) end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
RegisterCommand('mutelights', function()
|
||||
mute = not mute
|
||||
if mute then
|
||||
print("Lighting reminders muted.")
|
||||
else
|
||||
print("Lighting reminders unmuted.")
|
||||
end
|
||||
end)
|
||||
]]
|
||||
@@ -0,0 +1,114 @@
|
||||
local rblIntegration = false
|
||||
|
||||
function ULC:SetBlackout(newState)
|
||||
--print("Setting blackout to " .. newState)
|
||||
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
|
||||
if newState == 0 then
|
||||
-- do blackout stuff
|
||||
-- turn off headlights
|
||||
SetVehicleLights(vehicle, 1)
|
||||
-- turn off emergency lights
|
||||
SetVehicleSiren(vehicle, false)
|
||||
-- turn off specified blackout extras?
|
||||
-- might need to just make a blackout file and config section, i think this can work when brake patterns aren't being used?
|
||||
-- turn off cruise lights (do in c_cruise.lua)
|
||||
-- if lights are turned on with q, or h, or a button is pressed, cancel effect, not sure how to do this.
|
||||
-- when these actions are done check [if Entity(GetVehiclePedIsIn(PlayerPedId())).state.rbl_blackout or ulc_blackout] <- depending on if these can be accessed when not defined, may have to just use a static global variable in here.
|
||||
|
||||
-- if rbl is not loaded, start checking if vehicle is moving to disable blackout, rbl handles this itself if loaded
|
||||
if not rblIntegration then
|
||||
CreateThread(function()
|
||||
while true do Wait(500)
|
||||
if Entity(vehicle).state.ulc_blackout == 1 then ULC:SetBlackout(1) return end
|
||||
local speed = GetEntitySpeed(vehicle) * 2.236936
|
||||
--print("Speed is " .. speed)
|
||||
if speed > 5 then ULC:SetBlackout(1) return end
|
||||
end
|
||||
end)
|
||||
end
|
||||
elseif newState == 1 then
|
||||
-- do undo blackout stuff
|
||||
SetVehicleLights(vehicle, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- add statebag change handler for ulc_blackout
|
||||
AddStateBagChangeHandler('ulc_blackout', null, function(bagName, key, value)
|
||||
Wait(0)
|
||||
local vehicle = GetEntityFromStateBagName(bagName)
|
||||
--print("ulc_blackout listener: Vehicle is " .. vehicle .. " and GetVehiclePedIsIn(PlayerPedId()) is " .. GetVehiclePedIsIn(PlayerPedId()))
|
||||
if vehicle == 0 or vehicle ~= GetVehiclePedIsIn(PlayerPedId()) then
|
||||
print("ulc_blackout listener: Vehicle is 0 or not mine.")
|
||||
return
|
||||
end
|
||||
local blackout = value
|
||||
--print("ulc_blackout listener: new state value is " .. tostring(blackout))
|
||||
if blackout == 0 then
|
||||
ULC:SetBlackout(0)
|
||||
elseif blackout == 1 then
|
||||
ULC:SetBlackout(1)
|
||||
end
|
||||
end)
|
||||
|
||||
-- add statebag change handler for rbl blackout
|
||||
AddStateBagChangeHandler('rbl_blackout', null, function(bagName, key, value)
|
||||
Wait(0)
|
||||
rblIntegration = true
|
||||
local vehicle = GetEntityFromStateBagName(bagName)
|
||||
--print("rbl_blackout listener: Vehicle is " .. vehicle .. " and GetVehiclePedIsIn(PlayerPedId()) is " .. GetVehiclePedIsIn(PlayerPedId()))
|
||||
if vehicle == 0 or vehicle ~= GetVehiclePedIsIn(PlayerPedId()) then
|
||||
--print("rbl_blackout listener: Vehicle is 0 or not mine")
|
||||
return
|
||||
end
|
||||
local blackout = value
|
||||
--print("rbl_blackout listener: new state value is " .. tostring(blackout))
|
||||
if blackout == true then
|
||||
--print("rbl_blackout listener: setting blackout to 0")
|
||||
ULC:SetBlackout(0)
|
||||
elseif blackout == false then
|
||||
--print("rbl_blackout listener: setting blackout to 1")
|
||||
ULC:SetBlackout(1)
|
||||
end
|
||||
end)
|
||||
|
||||
-- register command for blackout
|
||||
|
||||
-- if rbl loads first then ULC
|
||||
-- ulc will overwrite command
|
||||
-- ULC needs to trigger rbl:setBlackout state change on server
|
||||
-- ULC only manages the extras
|
||||
|
||||
-- if ulc loads first then rbl
|
||||
-- rbl will overwrite command
|
||||
-- rbl needs to trigger ulc:setBlackout state change on server
|
||||
-- rbl only manages the brake lights
|
||||
|
||||
RegisterCommand('blackout', function()
|
||||
local newState
|
||||
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
|
||||
if not vehicle then return end
|
||||
local currentState = Entity(vehicle).state.ulc_blackout
|
||||
--print("/blackout: Current state: " .. tostring(currentState))
|
||||
if currentState == nil or currentState == 1 then
|
||||
print("Setting blackout to true/0")
|
||||
newState = 0
|
||||
elseif currentState == 0 then
|
||||
print("Setting blackout to false/1")
|
||||
newState = 1
|
||||
end
|
||||
-- trigger server event to set blackout on my vehicle
|
||||
-- might need to extract this to an event/function to control the effect programmatically, like disbling when q pressed
|
||||
TriggerServerEvent('ulc:setBlackout', VehToNet(GetVehiclePedIsIn(PlayerPedId())), newState)
|
||||
TriggerServerEvent('rbl:setBlackout', VehToNet(GetVehiclePedIsIn(PlayerPedId())), newState)
|
||||
end)
|
||||
-- toggle blackout state on vehicle
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- DISABLE BLACKOUT TRIGGERS --
|
||||
-------------------------------
|
||||
|
||||
--TODO when H is pressed to control headlights disable blackout
|
||||
--TODO when Q is pressed to control emergency lights disable blackout
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
--print("[ULC] Brake Extras Loaded")
|
||||
local realBrakeThreshold = 3
|
||||
local shouldUseRealBrakes = function()
|
||||
return (MyVehicleConfig.brakeConfig.speedThreshold or 3) <= realBrakeThreshold
|
||||
end
|
||||
local braking = false
|
||||
|
||||
-------------------
|
||||
-- MAIN FUNCTIONS --
|
||||
-------------------
|
||||
|
||||
local disabledExtras = {}
|
||||
|
||||
local function setBrakeExtras(newState)
|
||||
for _, v in pairs(MyVehicleConfig.brakeConfig.brakeExtras) do
|
||||
local currentState
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, v) then currentState = 0 else currentState = 1 end
|
||||
--print("[ULC] setBrakeExtras() newState: " .. newState .. " currentState: " .. currentState)
|
||||
if currentState == newState then break end
|
||||
ULC:SetStage(v, newState, false, true, false, false, true, false)
|
||||
end
|
||||
if newState == 0 then
|
||||
-- disable the disable extras and save the ones that we change
|
||||
if not MyVehicleConfig.brakeConfig.disableExtras then return end
|
||||
for _, v in pairs(MyVehicleConfig.brakeConfig.disableExtras) do
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, v) then
|
||||
ULC:SetStage(v, 1, false, true, false, false, true, false)
|
||||
table.insert(disabledExtras, v)
|
||||
end
|
||||
end
|
||||
elseif newState == 1 then
|
||||
-- re-enable any extras that were disabled
|
||||
for _, v in pairs(disabledExtras) do
|
||||
ULC:SetStage(v, 0, false, true, false, false, true, false)
|
||||
end
|
||||
disabledExtras = {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
----------------------------
|
||||
-- REALISTIC BRAKE LIGHTS --
|
||||
----------------------------
|
||||
if shouldUseRealBrakes then
|
||||
print("Realistic brake light functionality intialized.")
|
||||
local mode = "STANDARD"
|
||||
|
||||
-- start checking if stopped manually with a loop
|
||||
CreateThread(function()
|
||||
local sleep = 1000
|
||||
while true do
|
||||
Wait(sleep)
|
||||
-- if rbl_brakelights change handler gets triggered that means rbl exists and we want to use that functionality instead, return from this loop
|
||||
if mode == "RBL" then
|
||||
print("real-brake-lights resource detected, integrating brakelight functionality.")
|
||||
return
|
||||
end
|
||||
if not MyVehicle then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
if not shouldUseRealBrakes() then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
if not MyVehicleConfig.brakeConfig.useBrakes then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
if braking then goto continue end
|
||||
sleep = 250
|
||||
local speed = GetVehicleSpeedConverted(MyVehicle)
|
||||
if speed < realBrakeThreshold and shouldUseRealBrakes() and not IsControlPressed(0, 72) then
|
||||
--print("[manual checks] Enabling brakes")
|
||||
setBrakeExtras(0)
|
||||
else
|
||||
--print("[manual checks] Disabling brakes")
|
||||
setBrakeExtras(1)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end)
|
||||
|
||||
-- add a statebag change handler for rbl_brakelights
|
||||
-- once this is triggered, disable manual checking
|
||||
AddStateBagChangeHandler('rbl_brakelights', null, function(bagName, key, value)
|
||||
Wait(0) -- Nedded as GetEntityFromStateBagName sometimes returns 0 on first frame
|
||||
mode = "RBL" -- set mode to RBL to disable manual checking
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.brakeConfig.useBrakes then return end
|
||||
local vehicle = GetEntityFromStateBagName(bagName)
|
||||
--print("state changed for vehicle")
|
||||
if vehicle == 0 or vehicle ~= MyVehicle then return end
|
||||
local newState
|
||||
if value then newState = 0 else newState = 1 end
|
||||
--print("ULC: Setting brakes to state" .. newState)
|
||||
setBrakeExtras(newState)
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------
|
||||
-- KEYBINDINGS --
|
||||
-----------------
|
||||
|
||||
-- pressed brakes
|
||||
RegisterCommand('+ulc:brakePattern', function()
|
||||
braking = true
|
||||
if MyVehicle and MyVehicleConfig.brakeConfig.useBrakes then
|
||||
if GetVehicleCurrentGear(MyVehicle) == 0 then return end -- disable while reversing
|
||||
--print("Enabling brakes")
|
||||
local speed = GetVehicleSpeedConverted(MyVehicle)
|
||||
-- if using real brakes always enable
|
||||
if shouldUseRealBrakes() or speed > (MyVehicleConfig.brakeConfig.speedThreshold or 3) then
|
||||
setBrakeExtras(0)
|
||||
end
|
||||
end
|
||||
SendNUIMessage({
|
||||
type = 'toggleBrakeIndicator',
|
||||
state = true
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterCommand('-ulc:brakePattern', function()
|
||||
braking = false
|
||||
if MyVehicle and MyVehicleConfig.brakeConfig.useBrakes then
|
||||
local speed = GetVehicleSpeedConverted(MyVehicle)
|
||||
if shouldUseRealBrakes() and speed < realBrakeThreshold then return end
|
||||
--print("Disabling brakes")
|
||||
setBrakeExtras(1)
|
||||
end
|
||||
SendNUIMessage({
|
||||
type = 'toggleBrakeIndicator',
|
||||
state = false
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterKeyMapping('+ulc:brakePattern', 'ULC: Activate Brake Pattern (Hold)', 'keyboard', 's')
|
||||
@@ -0,0 +1,275 @@
|
||||
--print("[ULC]: Stage Controls Loaded")
|
||||
|
||||
-------------------
|
||||
-------------------
|
||||
----- HELPERS -----
|
||||
-------------------
|
||||
-------------------
|
||||
|
||||
function GetExtraByKey(key)
|
||||
local result = nil
|
||||
for _, v in pairs(MyVehicleConfig.buttons) do
|
||||
if v.key == key then
|
||||
result = v.extra
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function GetButtonByExtra(extra)
|
||||
local result = nil
|
||||
for _, v in pairs(MyVehicleConfig.buttons) do
|
||||
if v.extra == extra then
|
||||
result = v
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function ULC:ChangeExtra(extra, newState, repair)
|
||||
--print("[ULC:ChangeExtra()] Changing extra: " .. extra .. " to: " .. newState)
|
||||
-- disable repair
|
||||
if not repair then
|
||||
SetVehicleAutoRepairDisabled(MyVehicle, true)
|
||||
end
|
||||
-- change extra
|
||||
SetVehicleExtra(MyVehicle, extra, newState)
|
||||
-- fix deformation if repair is true
|
||||
if repair then
|
||||
SetVehicleDeformationFixed(MyVehicle)
|
||||
end
|
||||
-- enable repair
|
||||
SetVehicleAutoRepairDisabled(MyVehicle, false)
|
||||
end
|
||||
|
||||
---------------
|
||||
---------------
|
||||
-- MAIN CODE --
|
||||
---------------
|
||||
---------------
|
||||
|
||||
-- new event
|
||||
AddEventHandler('ulc:SetStage', function(extra, action, playSound, extraOnly, repair, forceChange, forceUi)
|
||||
ULC:SetStage(extra, action, playSound, extraOnly, repair, forceChange, forceUi)
|
||||
end)
|
||||
|
||||
-- change specified extra, and if not extraOnly, and extra is in a button, act on the linked and off extras as well, acts recursively;
|
||||
-- action 0 enables, 1 disables, 2 toggles;
|
||||
-- updates ui whenever extra is used in a button
|
||||
function ULC:SetStage(extra, action, playSound, extraOnly, repair, forceChange, forceUi, allowOutside)
|
||||
----------
|
||||
-- checks
|
||||
if not MyVehicle then
|
||||
print("[ULC:SetStage()] MyVehicle is not defined right now :/")
|
||||
return false
|
||||
end
|
||||
if not allowOutside and not IsPedInAnyVehicle(PlayerPedId(), false) then
|
||||
print("[ULC:SetStage()] Player must be in a vehicle, or allowOutside must be true.")
|
||||
return false
|
||||
end
|
||||
|
||||
--print("[ulc:SetStage]", extra, action, playSound, extraOnly)
|
||||
|
||||
--------------
|
||||
-- definitions
|
||||
local button = GetButtonByExtra(extra)
|
||||
local buttonStates = {} -- track button states for UI
|
||||
|
||||
--------------------------
|
||||
-- determine the new state
|
||||
local newState
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, extra) then
|
||||
if action == 1 or action == 2 then
|
||||
newState = 1
|
||||
end
|
||||
else
|
||||
if action == 0 or action == 2 then
|
||||
newState = 0
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------
|
||||
-- built in don't try to change if it's the same already!
|
||||
--[[ forceChange is used to forceChange the change even if it's the same
|
||||
this is used to trigger the additional actions like linked and off extras
|
||||
even if the extra is already in the state we want it to be
|
||||
(used in cycling stages and one other place i cant remember)]]
|
||||
if not forceChange and not newState then return end
|
||||
|
||||
local canChange = true
|
||||
if repair then
|
||||
if not AreVehicleDoorsClosed(MyVehicle) then
|
||||
canChange = false
|
||||
print("[ULC:SetStage] Can't change stage with repair while a door is open.")
|
||||
end
|
||||
if not IsVehicleHealthy(MyVehicle) then
|
||||
canChange = false
|
||||
print("[ULC:SetStage] Can't change stage with repair while vehicle is damaged.")
|
||||
end
|
||||
end
|
||||
|
||||
if not canChange then return end
|
||||
|
||||
---------------------------------------
|
||||
-- if the extra corresponds to a button
|
||||
if button then
|
||||
--------------------
|
||||
-- sound
|
||||
if playSound then
|
||||
if newState == 0 then
|
||||
PlayBeep(true)
|
||||
else
|
||||
PlayBeep(false)
|
||||
end
|
||||
end
|
||||
|
||||
----------------------
|
||||
-- smart stages stuff
|
||||
local key = button.key
|
||||
if MyVehicleConfig.stages then
|
||||
local keyStage = contains(MyVehicleConfig.stages.stageKeys, key) -- find whether MyVehicleConfig.stages.stageKeys contain the key
|
||||
|
||||
-- # TODO we're not getting here for some reason when cycling stages at max stage
|
||||
-- if the key pressed is not a stage, just change the extra
|
||||
if not keyStage then
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
end
|
||||
|
||||
-- if the key pressed is a stage and extraOnly is false
|
||||
if keyStage and not extraOnly then
|
||||
print("key: " .. key .. " keyStage: " .. tostring(keyStage) .. " currentStage: " .. currentStage)
|
||||
-- if it's the same as the current stage, change the extra and proceed normally
|
||||
if keyStage == currentStage then
|
||||
print("Key is the same as current stage")
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
-- set the stage to 0
|
||||
print("Setting stage to: 0")
|
||||
currentStage = 0
|
||||
else
|
||||
-- if it's a different stage then we want to change to a state where that stage is enabled
|
||||
print("Key is not the same as current stage")
|
||||
newState = 0 -- change to newState to 0 since we want the new stage to be enabled
|
||||
|
||||
local currentPrimaryExtraState = IsVehicleExtraTurnedOn(MyVehicle, extra)
|
||||
print("New state: " ..
|
||||
newState .. "Extra " .. extra .. " current state: " .. tostring(currentPrimaryExtraState))
|
||||
|
||||
if not IsVehicleExtraTurnedOn(MyVehicle, extra) and newState == 0 then
|
||||
print("Extra needs to be turned on")
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
elseif IsVehicleExtraTurnedOn(MyVehicle, extra) and newState == 1 then
|
||||
print("Extra needs to be turned off")
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
else
|
||||
-- if it's in the correct state
|
||||
print("Extra is already in the correct state")
|
||||
end
|
||||
-- set the new stage
|
||||
print("Setting stage to: " .. keyStage)
|
||||
currentStage = keyStage
|
||||
end
|
||||
else -- if extraOnly is true
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
end
|
||||
else
|
||||
-- if there are no stages, just change the extra
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
end
|
||||
|
||||
|
||||
----------------------
|
||||
-- initialize UI changes
|
||||
-- add that button to the new button states for UI with it's extra and new state
|
||||
table.insert(buttonStates, { extra = extra, newState = newState })
|
||||
|
||||
-----------------------------
|
||||
-- additional actions/extras
|
||||
if not extraOnly then
|
||||
-- set linked extras
|
||||
if button.linkedExtras then
|
||||
for _, v in ipairs(button.linkedExtras) do
|
||||
ULC:SetStage(v, newState, false, true, repair, forceChange)
|
||||
-- add linked buttons to the new button states for UI with their extras and new state
|
||||
table.insert(buttonStates, { extra = v, newState = newState })
|
||||
end
|
||||
end
|
||||
|
||||
-- set opposite extras
|
||||
if button.oppositeExtras or false then -- in case they have old config without the feature
|
||||
local oppState
|
||||
if newState == 1 then oppState = 0 elseif newState == 0 then oppState = 1 end
|
||||
for _, v in pairs(button.oppositeExtras) do
|
||||
ULC:SetStage(v, oppState, false, true, repair, forceChange)
|
||||
-- add opposite buttons to the new button states for UI with their extras and new state
|
||||
table.insert(buttonStates, { extra = v, newState = oppState })
|
||||
end
|
||||
end
|
||||
|
||||
-- set off extras
|
||||
if button.offExtras then
|
||||
for _, v in ipairs(button.offExtras) do
|
||||
ULC:SetStage(v, 1, false, true, repair, forceChange)
|
||||
-- add off buttons to the new button states for UI with their extras and new state
|
||||
table.insert(buttonStates, { extra = v, newState = 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not extraOnly or forceUi then
|
||||
-- update UI
|
||||
ULC:SetButtons(buttonStates)
|
||||
end
|
||||
else -- if it's not a button, we just change the extra because we don't care about stages or linked extras etc.
|
||||
ULC:ChangeExtra(extra, newState, repair)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-----------------------
|
||||
------ KEYBINDS -------
|
||||
-----------------------
|
||||
-----------------------
|
||||
|
||||
for i = 1, 9, 1 do
|
||||
RegisterKeyMapping('ulc:num' .. i, 'ULC: Toggle Button ' .. i, 'keyboard', 'NUMPAD' .. i)
|
||||
RegisterCommand('ulc:num' .. i, function()
|
||||
local extra = GetExtraByKey(i)
|
||||
local button = GetButtonByExtra(extra)
|
||||
if not button then return end
|
||||
ULC:SetStage(extra, 2, true, false, button.repair or false)
|
||||
end)
|
||||
end
|
||||
|
||||
------------------
|
||||
------ HELP ------
|
||||
------------------
|
||||
|
||||
local activeButtons = {}
|
||||
local showingHelp = false
|
||||
|
||||
function ShowHelp()
|
||||
CreateThread(function()
|
||||
if not showingHelp then
|
||||
-- show help
|
||||
showingHelp = true
|
||||
for k, v in ipairs(activeButtons) do
|
||||
--print('Showing help for button: ' .. k .. ' : ' .. v.key)
|
||||
SendNUIMessage({
|
||||
type = 'showHelp',
|
||||
button = k,
|
||||
key = v.key,
|
||||
})
|
||||
end
|
||||
Wait(3000)
|
||||
-- hide help
|
||||
showingHelp = false
|
||||
for k, v in ipairs(activeButtons) do
|
||||
SendNUIMessage({
|
||||
type = 'hideHelp',
|
||||
button = k,
|
||||
label = string.upper(v.label),
|
||||
})
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,77 @@
|
||||
--print("[ULC]: Cruise lights Loaded")
|
||||
|
||||
-- 1 disabled, 0 enabled
|
||||
local sbState = 1
|
||||
|
||||
-- 0 on, 1 off
|
||||
local function setCruiseLights(newState)
|
||||
sbState = newState
|
||||
for _, v in pairs(MyVehicleConfig.steadyBurnConfig.sbExtras) do
|
||||
--print("Setting cruise lights extra: " .. v)
|
||||
ULC:SetStage(v, newState, false, true, false, false, true, false)
|
||||
end
|
||||
end
|
||||
|
||||
local function getSteadyBurnState()
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, MyVehicleConfig.steadyBurnConfig.sbExtras[1]) then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
if MyVehicle then
|
||||
TriggerEvent('ulc:CheckCruise', false)
|
||||
end
|
||||
Wait(1000)
|
||||
end
|
||||
end)
|
||||
|
||||
--TODO: disable when lights are on, enable when lights are off
|
||||
|
||||
AddEventHandler('ulc:lightsOn', function()
|
||||
--print("Lights on")
|
||||
if MyVehicle and (MyVehicleConfig.steadyBurnConfig.disableWithLights or false) then
|
||||
setCruiseLights(1)
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:lightsOff', function()
|
||||
--print("Lights off")
|
||||
if MyVehicle and (MyVehicleConfig.steadyBurnConfig.disableWithLights or false) then
|
||||
TriggerEvent('ulc:CheckCruise')
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:CheckCruise', function()
|
||||
sbState = getSteadyBurnState()
|
||||
if not MyVehicle then return end
|
||||
|
||||
if Entity(MyVehicle).state.ulc_blackout == 0 then
|
||||
-- print("Blackout is on, disabling cruise lights")
|
||||
setCruiseLights(1)
|
||||
return
|
||||
end
|
||||
|
||||
if MyVehicleConfig.steadyBurnConfig.forceOn then
|
||||
if sbState == 0 then return end
|
||||
if Lights and MyVehicleConfig.steadyBurnConfig.disableWithLights then return end
|
||||
--print("Setting cruise lights on")
|
||||
setCruiseLights(0)
|
||||
elseif MyVehicleConfig.steadyBurnConfig.useTime then
|
||||
local isTime = GetClockHours() > Config.SteadyBurnSettings.nightStartHour or
|
||||
GetClockHours() < Config.SteadyBurnSettings.nightEndHour
|
||||
if isTime then
|
||||
-- if lights are already on do nothing
|
||||
if sbState == 0 then return end
|
||||
if Lights and MyVehicleConfig.steadyBurnConfig.disableWithLights then return end
|
||||
setCruiseLights(0)
|
||||
else
|
||||
-- if already off do nothing
|
||||
if sbState == 1 then return end
|
||||
setCruiseLights(1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,85 @@
|
||||
local doors = {
|
||||
[0] = false, -- d front
|
||||
[1] = false, -- p front
|
||||
[2] = false, -- d rear
|
||||
[3] = false, -- p rear
|
||||
[4] = false, -- hood
|
||||
[5] = false -- trunk
|
||||
}
|
||||
|
||||
local function intNot(value)
|
||||
result = 0
|
||||
if value == 0 then
|
||||
result = 1
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- state 1 = closed, state 0 = open
|
||||
local function onDoorStateChange(door, newDoorState)
|
||||
--print("Handling door change", door, newDoorState)
|
||||
if door == 0 or door == 2 then -- if driver side
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.driverSide.enable) do
|
||||
--print("Enable extra:", v)
|
||||
ULC:SetStage(v, newDoorState, true, true, false, false, true, true)
|
||||
end
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.driverSide.disable) do
|
||||
--print("Disable extra:", v, intNot(newDoorState))
|
||||
ULC:SetStage(v, intNot(newDoorState), true, true, false, false, true, true)
|
||||
end
|
||||
elseif door == 1 or door == 3 then -- if pass side
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.passSide.enable) do
|
||||
--print("Enable extra:", v)
|
||||
ULC:SetStage(v, newDoorState, true, true, false, false, true, true)
|
||||
end
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.passSide.disable) do
|
||||
--print("Disable extra:", v, intNot(newDoorState))
|
||||
ULC:SetStage(v, intNot(newDoorState), true, true, false, false, true, true)
|
||||
end
|
||||
elseif door == 5 then -- if trunk
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.trunk.enable) do
|
||||
ULC:SetStage(v, newDoorState, true, true, false, false, true, true)
|
||||
end
|
||||
for _, v in pairs(MyVehicleConfig.doorConfig.trunk.disable) do
|
||||
ULC:SetStage(v, intNot(newDoorState), true, true, false, false, true, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
local sleep = 1000
|
||||
while true do
|
||||
Wait(sleep)
|
||||
if not MyVehicle then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
if not MyVehicleConfig.doorConfig or false then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
if not MyVehicleConfig.doorConfig.useDoors then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
sleep = 250
|
||||
|
||||
for k, v in pairs(doors) do
|
||||
if GetVehicleDoorAngleRatio(MyVehicle, k) > 0.0 then
|
||||
if v == false then
|
||||
-- print("Setting door", k, "open.")
|
||||
doors[k] = true -- set door open
|
||||
onDoorStateChange(k, 0) -- handle what to do
|
||||
end
|
||||
else
|
||||
if v == true then
|
||||
-- print("Setting door", k, "closed.")
|
||||
doors[k] = false -- set door closed
|
||||
onDoorStateChange(k, 1) -- handle what to do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,67 @@
|
||||
--print("[ULC]: Horn Extras Loaded")
|
||||
|
||||
local extraStates = {}
|
||||
|
||||
local function GetPreviousStateByExtra(extra)
|
||||
for k, v in pairs(extraStates) do
|
||||
--print(v.extra, v.state)
|
||||
if extra == v.extra then
|
||||
--print('Found state of : ' .. tostring(v.state) .. ' for extra ' .. extra)
|
||||
return v.state
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SetHornExtras(newState)
|
||||
-- print('SetHornExtras: ' .. newState)
|
||||
if newState == 0 then
|
||||
for _, extra in pairs(MyVehicleConfig.hornConfig.hornExtras) do
|
||||
local extraState = {
|
||||
extra = extra,
|
||||
state = IsVehicleExtraTurnedOn(MyVehicle, extra)
|
||||
}
|
||||
table.insert(extraStates, extraState)
|
||||
ULC:SetStage(extra, 0, false, true, false, false, true, false)
|
||||
end
|
||||
if not MyVehicleConfig.hornConfig.disableExtras then return end
|
||||
for _, extra in pairs(MyVehicleConfig.hornConfig.disableExtras) do
|
||||
local extraState = {
|
||||
extra = extra,
|
||||
state = IsVehicleExtraTurnedOn(MyVehicle, extra)
|
||||
}
|
||||
table.insert(extraStates, extraState)
|
||||
ULC:SetStage(extra, 1, false, true, false, false, true, false)
|
||||
end
|
||||
elseif newState == 1 then
|
||||
for _, extra in pairs(MyVehicleConfig.hornConfig.hornExtras) do
|
||||
local prevState = GetPreviousStateByExtra(extra)
|
||||
if not prevState then
|
||||
ULC:SetStage(extra, 1, false, true, false, false, true, false)
|
||||
end
|
||||
end
|
||||
if not MyVehicleConfig.hornConfig.disableExtras then return end
|
||||
for _, extra in pairs(MyVehicleConfig.hornConfig.disableExtras) do
|
||||
local prevState = GetPreviousStateByExtra(extra)
|
||||
if prevState then
|
||||
ULC:SetStage(extra, 0, false, true, false, false, true, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RegisterCommand('+ulc:horn', function()
|
||||
--print('horn')
|
||||
extraStates = {}
|
||||
|
||||
if MyVehicle and MyVehicleConfig.hornConfig.useHorn then
|
||||
SetHornExtras(0)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterCommand('-ulc:horn', function()
|
||||
if MyVehicle and MyVehicleConfig.hornConfig.useHorn then
|
||||
SetHornExtras(1)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterKeyMapping('+ulc:horn', 'ULC: Activate Horn Extras', 'keyboard', 'e')
|
||||
@@ -0,0 +1,298 @@
|
||||
-- MAIN FUNCTIONS --
|
||||
|
||||
function ULC:PopulateButtons(_buttons, placeholders)
|
||||
--print("Populating buttons")
|
||||
|
||||
local buttons = _buttons
|
||||
|
||||
if placeholders then
|
||||
buttons = {
|
||||
{ label = 'TEST STAGE', extra = 1, color = 'green', enabled = true },
|
||||
{ label = 'TEST STAGE', extra = 2, color = 'blue', enabled = false },
|
||||
{ label = 'TEST STAGE', extra = 3, color = 'blue', enabled = false },
|
||||
{ label = 'TEST STAGE', extra = 4, color = 'blue', enabled = true },
|
||||
{ label = 'test stage', extra = 5, color = 'red', enabled = true }
|
||||
}
|
||||
end
|
||||
|
||||
local buttonsToSend = {}
|
||||
for _, v in pairs(buttons) do
|
||||
local thisButton = {}
|
||||
local thisState = false
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, v.extra) then thisState = true end
|
||||
thisButton.extra = v.extra
|
||||
thisButton.enabled = thisState
|
||||
thisButton.color = v.color or 'green'
|
||||
thisButton.label = string.upper(v.label)
|
||||
thisButton.numKey = v.key
|
||||
|
||||
--print("Sending button: " .. json.encode(thisButton))
|
||||
table.insert(buttonsToSend, thisButton)
|
||||
end
|
||||
|
||||
SendNUIMessage({
|
||||
type = 'populateButtons',
|
||||
buttons = buttonsToSend
|
||||
})
|
||||
end
|
||||
|
||||
-- deprecated in exchange for "SetButtons"
|
||||
function ULC:SetButton(extra, enabled)
|
||||
local newState
|
||||
if enabled == 0 then
|
||||
newState = true
|
||||
elseif enabled == 1 then
|
||||
newState = false
|
||||
end
|
||||
|
||||
SendNUIMessage({
|
||||
type = 'setButton',
|
||||
extra = extra,
|
||||
newState = newState
|
||||
})
|
||||
end
|
||||
|
||||
function ULC:SetButtons(buttonStates)
|
||||
-- print("Setting buttons", json.encode(buttonStates))
|
||||
-- go through the buttons and replace newState with a boolean
|
||||
-- newState = 1 means false, 0 means true
|
||||
|
||||
for k, v in pairs(buttonStates) do
|
||||
if v.newState == 1 then
|
||||
v.newState = false
|
||||
elseif v.newState == 0 then
|
||||
v.newState = true
|
||||
end
|
||||
end
|
||||
|
||||
SendNUIMessage({
|
||||
type = 'setButtons',
|
||||
buttonStates = buttonStates
|
||||
})
|
||||
end
|
||||
|
||||
-----------------
|
||||
-- UI SETTINGS --
|
||||
-----------------
|
||||
|
||||
function ULC:SetDisplay(bool)
|
||||
if bool then
|
||||
SendNUIMessage({
|
||||
type = 'showHUD',
|
||||
})
|
||||
else
|
||||
SendNUIMessage({
|
||||
type = 'hideHUD',
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function ULC:SetPosition(x, y)
|
||||
SendNUIMessage({
|
||||
type = 'setPosition',
|
||||
x = x,
|
||||
y = y
|
||||
})
|
||||
end
|
||||
|
||||
function ULC:SetScale(float)
|
||||
SendNUIMessage({
|
||||
type = 'setScale',
|
||||
scale = float
|
||||
})
|
||||
end
|
||||
|
||||
-- TODO this is unused in game, should be in menu
|
||||
function ULC:SetUseLeftAnchor(bool)
|
||||
SendNUIMessage({
|
||||
type = 'setAnchor',
|
||||
bool = bool
|
||||
})
|
||||
end
|
||||
|
||||
function ULC:SetHudDisabled(bool)
|
||||
SendNUIMessage({
|
||||
type = 'setHudDisabled',
|
||||
bool = bool
|
||||
})
|
||||
end
|
||||
|
||||
function ULC:SetHelpDisplay(bool)
|
||||
if bool then
|
||||
SendNUIMessage({ type = 'showHelp' })
|
||||
else
|
||||
SendNUIMessage({ type = 'hideHelp' })
|
||||
end
|
||||
end
|
||||
|
||||
----------
|
||||
-- MENU --
|
||||
----------
|
||||
|
||||
-- TODO set this up in js
|
||||
function ULC:SetMenuDisplay(bool)
|
||||
--print("Client setting display", bool)
|
||||
if bool then
|
||||
SendNUIMessage({
|
||||
type = 'showMenu',
|
||||
})
|
||||
else
|
||||
SendNUIMessage({
|
||||
type = 'hideHideMenu',
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
----------------------
|
||||
-- USER PREFERENCES --
|
||||
----------------------
|
||||
print("[ULC] Client Storage Loaded")
|
||||
ClientPrefs = {}
|
||||
|
||||
local function loadUserPrefs()
|
||||
-- if prefs already exist
|
||||
local prefsExist = GetResourceKvpString('ulc')
|
||||
if prefsExist == "exists" then
|
||||
print("[ULC] Loading prefs")
|
||||
-- load
|
||||
ClientPrefs.hideUi = GetResourceKvpInt("ulc:hideUi")
|
||||
ClientPrefs.x = GetResourceKvpInt("ulc:x")
|
||||
ClientPrefs.y = GetResourceKvpInt("ulc:y")
|
||||
ClientPrefs.scale = GetResourceKvpFloat("ulc:scale")
|
||||
ClientPrefs.useLeftAnchor = GetResourceKvpString("ulc:useLeftAnchor")
|
||||
else
|
||||
print("[ULC] Creating prefs")
|
||||
-- set defaults
|
||||
SetResourceKvp('ulc', "exists")
|
||||
SetResourceKvpInt('ulc:x', 0)
|
||||
SetResourceKvpInt('ulc:y', 0)
|
||||
SetResourceKvpFloat('ulc:scale', 1.0)
|
||||
SetResourceKvpInt('ulc:hideUi', 0)
|
||||
SetResourceKvp('ulc:useLeftAnchor', 'false')
|
||||
|
||||
|
||||
loadUserPrefs()
|
||||
|
||||
Wait(5000)
|
||||
TriggerEvent('chat:addMessage', {
|
||||
color = { 0, 153, 204 },
|
||||
multiline = false,
|
||||
args = { "ULC", "^4This server uses ULC! Type /ulc to view settings and adjust the HUD!" }
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
loadUserPrefs()
|
||||
|
||||
-- use the values
|
||||
CreateThread(function()
|
||||
--print("CLIENT PREF DISABLED =", ClientPrefs.hideUi)
|
||||
Wait(1000)
|
||||
-- positioning
|
||||
if ClientPrefs.x then
|
||||
--print("Loaded position from kvp: ", ClientPrefs.x, ClientPrefs.y)
|
||||
ULC:SetPosition(ClientPrefs.x, ClientPrefs.y)
|
||||
end
|
||||
if ClientPrefs.scale then
|
||||
-- print("Loaded saved scale from kvp: " .. ClientPrefs.scale)
|
||||
ULC:SetScale(ClientPrefs.scale + 0.0)
|
||||
end
|
||||
if ClientPrefs.hideUi then
|
||||
-- print("Loaded disabled HUD kvp: " .. ClientPrefs.hideUi)
|
||||
ULC:SetHudDisabled(ClientPrefs.hideUi)
|
||||
end
|
||||
if ClientPrefs.useLeftAnchor then
|
||||
-- print("Loaded useLeftAnchor from kvp", ClientPrefs.useLeftAnchor)
|
||||
ULC:SetUseLeftAnchor(ClientPrefs.useLeftAnchor)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
--------------
|
||||
-- COMMANDS --
|
||||
--------------
|
||||
|
||||
RegisterCommand('ulc', function()
|
||||
if not MyVehicle then
|
||||
ULC:PopulateButtons({}, true)
|
||||
ULC:SetDisplay(true)
|
||||
end
|
||||
ULC:SetMenuDisplay(true)
|
||||
if MyVehicle then
|
||||
ULC:SetHelpDisplay(true)
|
||||
end
|
||||
SetNuiFocus(true, true)
|
||||
end)
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/ulc', 'Enables dragging ULC HUD and shows settings menu and controls.', {
|
||||
})
|
||||
|
||||
RegisterCommand("ulcReset", function()
|
||||
DeleteResourceKvp("ulc")
|
||||
loadUserPrefs()
|
||||
end)
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/ulcReset', 'Resets all saved ULC settings to defaults.', {
|
||||
})
|
||||
|
||||
-- NUI CALLBACKS --
|
||||
|
||||
RegisterNUICallback("savePosition", function(data, cb)
|
||||
--print("NUI Setting position", data.newX, data.newY, "type = ", type(data.newX))
|
||||
SetResourceKvpInt('ulc:x', data.newX)
|
||||
SetResourceKvpInt('ulc:y', data.newY)
|
||||
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("saveScale", function(data, cb)
|
||||
--print("NUI Setting Scale " .. data.scale + 0.0)
|
||||
SetResourceKvpFloat('ulc:scale', data.scale + 0.0)
|
||||
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("saveAnchor", function(data, cb)
|
||||
--print("NUI Setting Anchor ", data.useLeftAnchor)
|
||||
SetResourceKvp('ulc:useLeftAnchor', data.useLeftAnchor)
|
||||
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("focusGame", function(data, cb)
|
||||
ULC:SetMenuDisplay(false)
|
||||
SetNuiFocus(false, false)
|
||||
ULC:SetHelpDisplay(false)
|
||||
|
||||
if not MyVehicle then
|
||||
ULC:SetDisplay(false)
|
||||
end
|
||||
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("setHudDisabled", function(data, cb)
|
||||
--print("NUI Setting HUD Disabled ", data.hudDisabled)
|
||||
|
||||
if not data.hudDisabled then
|
||||
--print("Set HUD enabled")
|
||||
if MyVehicle then
|
||||
ULC:SetDisplay(true)
|
||||
end
|
||||
if #ClientPrefs > 0 then
|
||||
ClientPrefs.hideUi = 0
|
||||
--print("Are we here?")
|
||||
end
|
||||
SetResourceKvpInt('ulc:hideUi', 0)
|
||||
else
|
||||
--print("Set HUD disabled")
|
||||
ULC:SetDisplay(false)
|
||||
if #ClientPrefs > 0 then
|
||||
ClientPrefs.hideUi = 1
|
||||
--print("Are we here?")
|
||||
end
|
||||
SetResourceKvpInt('ulc:hideUi', 1)
|
||||
end
|
||||
|
||||
cb({ success = true })
|
||||
end)
|
||||
@@ -0,0 +1,32 @@
|
||||
print("[ULC] LVC Integrations Loaded")
|
||||
|
||||
-- going to store the LVC siren state just for fun
|
||||
LVC_SirenState = 0
|
||||
|
||||
-- received from s_lvc.lua when player changes main siren state in LVC
|
||||
-- sirenId is an int representing the index of a siren in lvc/SIRENS.lua:SIRENS
|
||||
RegisterNetEvent("ulc:LVC_MainSirenStateChange")
|
||||
AddEventHandler("ulc:LVC_MainSirenStateChange", function(sirenId)
|
||||
print("[ulc:LVC_MainSirenStateChange] " .. sirenId)
|
||||
-- # TODO check how much of this is actually needed
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.luxartVehicleControlConfig then return end
|
||||
if not MyVehicleConfig.luxartVehicleControlConfig.useLVC then return end
|
||||
|
||||
local config = MyVehicleConfig.luxartVehicleControlConfig
|
||||
|
||||
-- if sirenId is not in the config, return
|
||||
if not MyVehicleConfig.luxartVehicleControlConfig[sirenId] then
|
||||
print("[ULC: LVC_MainSirenStateChange()] siren [" ..
|
||||
sirenId .. "] is not defined in MyVehicleConfig.luxartVehicleControlConfig")
|
||||
return false
|
||||
end
|
||||
|
||||
for _, v in pairs(config[sirenId].enable) do
|
||||
ULC:SetStage(v, 0, false, false, false, false, false, false)
|
||||
end
|
||||
|
||||
for _, v in pairs(config[sirenId].disable) do
|
||||
ULC:SetStage(v, 1, false, false, false, false, false, false)
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,202 @@
|
||||
--print("[ULC]: Main Thread Loaded")
|
||||
|
||||
ULC = {}
|
||||
|
||||
-----------------
|
||||
-- DEFINITIONS --
|
||||
-----------------
|
||||
|
||||
Lights = false
|
||||
MyVehicle = nil
|
||||
MyVehicleConfig = nil
|
||||
|
||||
------------------------------------
|
||||
------------------------------------
|
||||
------- LIGHTS STATE HANDLER -------
|
||||
------------------------------------
|
||||
------------------------------------
|
||||
|
||||
if Config.controlLights then
|
||||
RegisterCommand('ulc:toggleLights', function()
|
||||
if Lights then
|
||||
SetVehicleSiren(MyVehicle, false)
|
||||
else
|
||||
SetVehicleSiren(MyVehicle, true)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterKeyMapping('ulc:toggleLights', 'Toggle Emergency Lights', 'keyboard', 'q')
|
||||
end
|
||||
|
||||
AddEventHandler('ulc:lightsOn', function()
|
||||
--print("Lights On")
|
||||
-- set Lights on
|
||||
Lights = true
|
||||
setDefaultStages()
|
||||
-- check if parked or driving for park patterns
|
||||
TriggerEvent('ulc:checkParkState', GetVehiclePedIsIn(PlayerPedId()), false)
|
||||
SendNUIMessage({
|
||||
type = 'toggleIndicator',
|
||||
state = Lights
|
||||
})
|
||||
if Config.controlLights then
|
||||
PlayBeep(true)
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:lightsOff', function()
|
||||
--print("Lights Off")
|
||||
Lights = false
|
||||
SendNUIMessage({
|
||||
type = 'toggleIndicator',
|
||||
state = Lights
|
||||
})
|
||||
if Config.controlLights then
|
||||
PlayBeep(false)
|
||||
end
|
||||
end)
|
||||
|
||||
-- check if lights are on 10 times a second;
|
||||
-- used to trigger above events
|
||||
CreateThread(function()
|
||||
local sleep = 1000
|
||||
while true do
|
||||
Wait(sleep)
|
||||
if not MyVehicle then
|
||||
sleep = 1000
|
||||
goto continue
|
||||
end
|
||||
sleep = 100
|
||||
|
||||
if not IsPedInAnyVehicle(PlayerPedId()) then goto continue end
|
||||
if IsVehicleSirenOn(GetVehiclePedIsIn(PlayerPedId())) then
|
||||
if not Lights then
|
||||
TriggerEvent('ulc:lightsOn')
|
||||
end
|
||||
else
|
||||
if Lights then
|
||||
TriggerEvent('ulc:lightsOff')
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
end)
|
||||
|
||||
---------------------------
|
||||
---------------------------
|
||||
-------- MAIN CODE --------
|
||||
---------------------------
|
||||
---------------------------
|
||||
|
||||
-- this event is called whenever player enters vehicle
|
||||
RegisterNetEvent('ulc:checkVehicle')
|
||||
AddEventHandler('ulc:checkVehicle', function()
|
||||
CreateThread(function()
|
||||
while not GlobalState.ulcloaded do
|
||||
print("ULC: Waiting for load.")
|
||||
Wait(250)
|
||||
end
|
||||
print("[ULC:checkVehicle] Checking for vehicle configuration")
|
||||
local ped = PlayerPedId()
|
||||
local vehicle = GetVehiclePedIsIn(ped)
|
||||
local passed, vehicleConfig = GetVehicleFromConfig(vehicle)
|
||||
|
||||
--print(passed, vehicleConfig)
|
||||
|
||||
if passed then
|
||||
MyVehicle = vehicle
|
||||
MyVehicleConfig = vehicleConfig
|
||||
table.sort(MyVehicleConfig.buttons, function(a, b) return a["key"] < b["key"] end)
|
||||
|
||||
|
||||
print("[ULC:checkVehicle] Found vehicle, ready to go.")
|
||||
|
||||
-- if i am driver
|
||||
if ped == GetPedInVehicleSeat(vehicle, -1) then
|
||||
ULC:PopulateButtons(MyVehicleConfig.buttons)
|
||||
--ShowHelp()
|
||||
if not Config.hideHud and ClientPrefs.hideUi == 0 then
|
||||
ULC:SetDisplay(true)
|
||||
else
|
||||
print(
|
||||
"HUD is hidden. Type /ulc to see if you disabled it. Otherwise, the server owner may have disabled the HUD.")
|
||||
end
|
||||
|
||||
TriggerEvent('ulc:CheckCruise')
|
||||
TriggerEvent('ulc:checkParkState', true)
|
||||
TriggerEvent('ulc:StartCheckingReverseState')
|
||||
currentStage = 0
|
||||
end
|
||||
else
|
||||
MyVehicle = nil
|
||||
TriggerEvent('ulc:cleanup')
|
||||
TriggerEvent('ulc:StopCheckingReverseState')
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
-- used to hide the hud
|
||||
RegisterNetEvent('ulc:cleanup')
|
||||
AddEventHandler('ulc:cleanup', function()
|
||||
-- MyVehicle = nil
|
||||
-- MyVehicleConfig = nil
|
||||
ULC:SetDisplay(false)
|
||||
-- hide hud
|
||||
-- SendNUIMessage({
|
||||
-- type = 'hideLightsHUD',
|
||||
-- })
|
||||
end)
|
||||
|
||||
-----------------
|
||||
-- CONFIG SYNC --
|
||||
-----------------
|
||||
|
||||
RegisterNetEvent('UpdateVehicleConfigs', function(newData)
|
||||
print("[ULC] Updating vehicle table. Done loading.")
|
||||
Config.Vehicles = newData
|
||||
end)
|
||||
|
||||
-- trigger checks when spawning from one vehicle into another directly, or from another seat to driver seat
|
||||
CreateThread(function()
|
||||
local lastVehicle
|
||||
local wasDriving
|
||||
while true do
|
||||
Wait(500)
|
||||
if IsPedInAnyVehicle(PlayerPedId()) then
|
||||
local currentVehicle = GetVehiclePedIsIn(PlayerPedId(), false)
|
||||
local driving = GetPedInVehicleSeat(MyVehicle, -1) == PlayerPedId()
|
||||
if currentVehicle ~= lastVehicle then
|
||||
TriggerEvent('ulc:checkVehicle')
|
||||
end
|
||||
if MyVehicle and not wasDriving and driving then
|
||||
TriggerEvent('ulc:checkVehicle')
|
||||
end
|
||||
lastVehicle = currentVehicle
|
||||
wasDriving = driving
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-------------------------
|
||||
-------------------------
|
||||
-- AUTO REPAIR HANDLER --
|
||||
-------------------------
|
||||
-------------------------
|
||||
|
||||
-- every second set no repair on all vehicles except my own
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(1000)
|
||||
local vehicles = GetGamePool("CVehicle")
|
||||
for _, v in pairs(vehicles) do
|
||||
if v ~= GetVehiclePedIsIn(PlayerPedId(), false) then
|
||||
SetVehicleAutoRepairDisabled(v, true)
|
||||
else
|
||||
--print("Enabling repair for" .. v)
|
||||
SetVehicleAutoRepairDisabled(v, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,150 @@
|
||||
--print("[ULC]: Park Patterns Loaded")
|
||||
|
||||
local veh = GetVehiclePedIsIn(PlayerPedId())
|
||||
parked = false
|
||||
local lastSync = 0
|
||||
local effectDelay = 1000
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
if IsPedInAnyVehicle(PlayerPedId()) then
|
||||
TriggerEvent('ulc:checkParkState', veh, false)
|
||||
|
||||
Wait(Config.ParkSettings.delay * 1000)
|
||||
else
|
||||
Wait(2000)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent("ulc:checkParkState", function(delay)
|
||||
CreateThread(function()
|
||||
--print('Checking park state')
|
||||
|
||||
if delay then
|
||||
--print('Delay...')
|
||||
Wait(5000)
|
||||
end
|
||||
local speed = GetVehicleSpeedConverted(MyVehicle)
|
||||
|
||||
|
||||
if speed > Config.ParkSettings.speedThreshold and parked then
|
||||
TriggerEvent("ulc:vehDrive")
|
||||
end
|
||||
if speed < Config.ParkSettings.speedThreshold and not parked then
|
||||
Wait(effectDelay)
|
||||
if not parked then -- double checks
|
||||
TriggerEvent('ulc:vehPark')
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:vehPark', function()
|
||||
if Lights then
|
||||
--print('[ulc:vehPark] My vehicle is parked.')
|
||||
parked = true
|
||||
|
||||
if MyVehicle and MyVehicleConfig.parkConfig.usePark then
|
||||
-- enable pExtras
|
||||
for _, v in pairs(MyVehicleConfig.parkConfig.pExtras) do
|
||||
ULC:SetStage(v, 0, false, true, false, false, true, false)
|
||||
end
|
||||
-- disable dExtras
|
||||
for _, v in pairs(MyVehicleConfig.parkConfig.dExtras) do
|
||||
ULC:SetStage(v, 1, false, true, false, false, true, false)
|
||||
end
|
||||
|
||||
-- park pattern sync stuff
|
||||
if MyVehicleConfig.parkConfig.useSync then
|
||||
-- cooldown
|
||||
local gameSeconds = GetGameTimer() / 1000
|
||||
if gameSeconds >= lastSync + Config.ParkSettings.syncCooldown then
|
||||
lastSync = gameSeconds
|
||||
|
||||
local loadedVehicles = GetGamePool("CVehicle")
|
||||
--print(#loadedVehicles .. " vehicles in pool")
|
||||
local vehsToSync = {}
|
||||
|
||||
for k, v in pairs(loadedVehicles) do
|
||||
-- don't include my vehicle
|
||||
if v ~= veh then
|
||||
local vehCoords = GetEntityCoords(v)
|
||||
local pedCoords = GetEntityCoords(PlayerPedId())
|
||||
local distance = GetDistanceBetweenCoords(vehCoords, pedCoords)
|
||||
|
||||
|
||||
if distance < Config.ParkSettings.syncDistance then
|
||||
if GetVehicleClass(v) == 18 then
|
||||
-- check if my vehicle is set to sync with this vehicle or if the vehicle is the same model as my vehicle
|
||||
if IsVehicleInTable(v, MyVehicleConfig.parkConfig.syncWith) or GetEntityModel(v) == GetEntityModel(MyVehicle) then
|
||||
--print('Vehicle' .. v .. ' should sync with me.')
|
||||
|
||||
local speed = GetVehicleSpeedConverted(veh)
|
||||
|
||||
if speed < Config.ParkSettings.speedThreshold then
|
||||
--print("Found an eligible sync vehicle.")
|
||||
table.insert(vehsToSync, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #vehsToSync > 0 then
|
||||
-- sync my vehicle
|
||||
SetVehicleSiren(veh, false)
|
||||
SetVehicleSiren(veh, true)
|
||||
|
||||
-- sync other vehicles on my screen
|
||||
for k, v in pairs(vehsToSync) do
|
||||
if IsVehicleSirenOn(v) then
|
||||
SetVehicleSiren(v, false)
|
||||
SetVehicleSiren(v, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- send sync to other clients nearby
|
||||
--print("Preparing to send sync to server")
|
||||
local vehsToSyncNet = {}
|
||||
for k, v in pairs(vehsToSync) do
|
||||
--print("Candidate: " .. VehToNet(v))
|
||||
table.insert(vehsToSyncNet, VehToNet(v))
|
||||
end
|
||||
TriggerServerEvent("sync:send", vehsToSyncNet)
|
||||
else --print('Found no vehicles to sync.')
|
||||
end
|
||||
else
|
||||
print("Sync on cooldown, time left: " ..
|
||||
Config.ParkSettings.syncCooldown - (gameSeconds - lastSync) .. " seconds.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('ulc:sync:receive', function(vehicles)
|
||||
--print("[sync:receive] Trying to sync " .. #vehicles .. " vehicles.")
|
||||
for _, v in pairs(vehicles) do
|
||||
--print("Attempting to sync: " .. NetToVeh(v))
|
||||
SetVehicleSiren(NetToVeh(v), false)
|
||||
SetVehicleSiren(NetToVeh(v), true)
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:vehDrive', function()
|
||||
if Lights then
|
||||
--print('[ulc:vehDrive] My vehicle is driving.')
|
||||
parked = false
|
||||
if MyVehicle and MyVehicleConfig.parkConfig.usePark then
|
||||
-- disable pExtras
|
||||
for _, v in pairs(MyVehicleConfig.parkConfig.pExtras) do
|
||||
ULC:SetStage(v, 1, false, true, false, false, true, false)
|
||||
end
|
||||
-- enable dExtras
|
||||
for _, v in pairs(MyVehicleConfig.parkConfig.dExtras) do
|
||||
ULC:SetStage(v, 0, false, true, false, false, true, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,125 @@
|
||||
--print("[ULC]: Reverse Extras Loaded")
|
||||
|
||||
local reversing = false
|
||||
local disabledExtras = {}
|
||||
local timerExpired = false
|
||||
|
||||
function setReverseExtras(newState)
|
||||
-- set enable extras to match the new state
|
||||
for _, v in ipairs(MyVehicleConfig.reverseConfig.reverseExtras) do
|
||||
ULC:SetStage(v, newState, false, true, false, false, true, false)
|
||||
end
|
||||
if not MyVehicleConfig.reverseConfig.disableExtras then return end
|
||||
if newState == 0 then
|
||||
-- set disable extras off and save the ones we changed
|
||||
for _, v in ipairs(MyVehicleConfig.reverseConfig.disableExtras) do
|
||||
--print("Checking extra " .. v .. " for reverse state")
|
||||
if IsVehicleExtraTurnedOn(MyVehicle, v) then
|
||||
ULC:SetStage(v, 1, false, true, false, false, true, false)
|
||||
table.insert(disabledExtras, v)
|
||||
end
|
||||
end
|
||||
else -- newState == 1
|
||||
-- set the disabled extras back on
|
||||
for _, v in ipairs(disabledExtras) do
|
||||
ULC:SetStage(v, 0, false, true, false, false, true, false)
|
||||
end
|
||||
disabledExtras = {}
|
||||
end
|
||||
end
|
||||
|
||||
AddEventHandler('ulc:StartCheckingReverseState', function()
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(250)
|
||||
--print("Checking reverse state")
|
||||
if not IsPedInAnyVehicle(PlayerPedId()) then return end
|
||||
-- this feels unncessary, but I think some people may not have .reverseConfig
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.reverseConfig then return end
|
||||
if not MyVehicleConfig.reverseConfig.useReverse then return end
|
||||
local gear = GetVehicleCurrentGear(MyVehicle)
|
||||
if gear == 0 then
|
||||
if not reversing then
|
||||
startTimer()
|
||||
reversing = true
|
||||
setReverseExtras(0)
|
||||
end
|
||||
else
|
||||
if reversing then
|
||||
reversing = false
|
||||
setReverseExtras(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
-- handle disabling lights after some time
|
||||
function startTimer()
|
||||
-- if disabled in config, don't start timer , if enabled or missing config, start timer
|
||||
if Config and Config.ReverseSettings and not Config.ReverseSettings.useRandomExpiration then return end
|
||||
-- timer thread
|
||||
CreateThread(function()
|
||||
local speed
|
||||
local duration = math.random(3, 8) * 1000
|
||||
local expirationTime
|
||||
|
||||
while true do
|
||||
--print("Reverse timer tick")
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.reverseConfig then return end
|
||||
if not MyVehicleConfig.reverseConfig.useReverse then return end
|
||||
if not reversing then
|
||||
timerExpired = false
|
||||
--print("Not reversing")
|
||||
return
|
||||
end
|
||||
|
||||
speed = GetVehicleSpeedConverted(MyVehicle)
|
||||
|
||||
if speed < 0.5 then -- if we are in reverse and stopped
|
||||
if timerExpired then
|
||||
goto continue
|
||||
end
|
||||
if Config and Config.ReverseSettings then
|
||||
duration = math.random(
|
||||
(Config.ReverseSettings.minExpiration or 3) * 1000,
|
||||
(Config.ReverseSettings.maxExpiration or 8) * 1000
|
||||
)
|
||||
end
|
||||
expirationTime = GetGameTimer() + duration
|
||||
while GetGameTimer() < expirationTime do
|
||||
Wait(500)
|
||||
--print("Reverse timer active")
|
||||
|
||||
if GetVehicleSpeedConverted(MyVehicle) > 1 then
|
||||
-- print("[ULC] Reverse: Moving, breaking timer")
|
||||
break
|
||||
end
|
||||
if not reversing then
|
||||
-- print("[ULC] Reverse: Not reversing, breaking timer")
|
||||
break
|
||||
end
|
||||
if not IsPedInAnyVehicle(PlayerPedId()) then
|
||||
-- print("[ULC] Reverse: Not in vehicle, breaking timer")
|
||||
break
|
||||
end
|
||||
if GetGameTimer() > expirationTime then
|
||||
print("[ULC] Reverse: Timer expired, disabling extras")
|
||||
timerExpired = true
|
||||
setReverseExtras(1)
|
||||
break
|
||||
end
|
||||
end
|
||||
else -- if we are in reverse and moving
|
||||
-- print("[ULC] Reverse: Resetting timer")
|
||||
setReverseExtras(0)
|
||||
timerExpired = false
|
||||
end
|
||||
|
||||
::continue::
|
||||
Wait(500)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,157 @@
|
||||
print("[ULC] Stages Loaded")
|
||||
|
||||
-- Definitions
|
||||
-- # TODO maybe currentStage should not be 0 when entering a vehicle?
|
||||
--[[ # TODO this file does not handle setting the currentStage, instead ULC:SetStage does,
|
||||
may want to change this if possible, leads to hacky stuff like in CycleStage function ]]
|
||||
-- this is set to 0 whenever ulc:checkVehicle is triggered
|
||||
currentStage = 0
|
||||
|
||||
|
||||
-- helpers
|
||||
local function checks()
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.stages then return end
|
||||
if not MyVehicleConfig.stages.useStages then return end
|
||||
if not MyVehicleConfig.stages.stageKeys
|
||||
then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function getMaxStage()
|
||||
if not MyVehicle then return end
|
||||
if not MyVehicleConfig.stages then return end
|
||||
if not MyVehicleConfig.stages.stageKeys then return end
|
||||
return #MyVehicleConfig.stages.stageKeys
|
||||
end
|
||||
|
||||
-- main functions
|
||||
function stageUp()
|
||||
print("[ULC:stageUp] Increasing stage from " .. currentStage)
|
||||
if currentStage == getMaxStage() then
|
||||
print("Already at max stage")
|
||||
return
|
||||
end
|
||||
|
||||
-- this is handled in ULC:SetStage?
|
||||
-- currentStage = currentStage + 1
|
||||
-- instead we just want to keep track locally
|
||||
local nextStage = currentStage + 1
|
||||
|
||||
-- # TODO might want to check if the key is actually a button that exists (maybe do this in the initial checks when script starts?)
|
||||
local key = MyVehicleConfig.stages.stageKeys[nextStage]
|
||||
|
||||
local extra = GetExtraByKey(key)
|
||||
local button = GetButtonByExtra(extra)
|
||||
if not button then
|
||||
print("[stageUp()] Could not find button for extra " .. extra)
|
||||
return
|
||||
end
|
||||
print("Setting stage to: " .. nextStage .. " using key " .. key .. " with extra " .. extra)
|
||||
ULC:SetStage(extra, 0, true, false, button.repair or false, false, true, false)
|
||||
end
|
||||
|
||||
function stageDown()
|
||||
print("[ULC:stageDown] Decreasing stage from " .. currentStage)
|
||||
if currentStage == 0 then
|
||||
print("Already stage 0")
|
||||
return
|
||||
end
|
||||
|
||||
-- this is handled in ULC:SetStage?
|
||||
-- currentStage = currentStage - 1
|
||||
-- instead we just want to keep track locally
|
||||
local nextStage = currentStage - 1
|
||||
|
||||
-- # TODO might want to check if the key is actually a button that exists (maybe do this in the initial checks when script starts?)
|
||||
local key = MyVehicleConfig.stages.stageKeys[nextStage]
|
||||
local extra = GetExtraByKey(key)
|
||||
local button = GetButtonByExtra(extra)
|
||||
if not button then
|
||||
print("[stageDown()] Could not find button for extra " .. extra)
|
||||
return
|
||||
end
|
||||
print("Setting stage to: " .. nextStage .. " using key " .. key .. " with extra " .. extra)
|
||||
ULC:SetStage(extra, 0, true, false, button.repair or false, false, true, false)
|
||||
end
|
||||
|
||||
function cycleStages()
|
||||
if not checks() then return end
|
||||
if currentStage == getMaxStage() then
|
||||
print("Tried to cycle stages at max stage, resetting to 0")
|
||||
-- we need to turn off the current stage
|
||||
local key = MyVehicleConfig.stages.stageKeys[currentStage]
|
||||
local extra = GetExtraByKey(key)
|
||||
local button = GetButtonByExtra(extra)
|
||||
if not button then
|
||||
print("[cycleStages()] Could not find button for extra " .. extra)
|
||||
return
|
||||
end
|
||||
print("Setting stage to: 0 using key " .. key .. " with extra " .. extra)
|
||||
ULC:SetStage(extra, 1, true, false, button.repair or false, true, true, false)
|
||||
return
|
||||
end
|
||||
stageUp()
|
||||
end
|
||||
|
||||
-- Keybinds
|
||||
RegisterKeyMapping("ulc:stage_down", "ULC: Stage Down", "keyboard", "SUBTRACT")
|
||||
RegisterCommand("ulc:stage_down", function()
|
||||
if not checks() then return end
|
||||
stageDown()
|
||||
end)
|
||||
|
||||
RegisterKeyMapping("ulc:stage_up", "ULC: Stage Up", "keyboard", "ADD")
|
||||
RegisterCommand("ulc:stage_up", function()
|
||||
if not checks() then return end
|
||||
stageUp()
|
||||
end)
|
||||
|
||||
RegisterKeyMapping("ulc:stage_cycle", "ULC: Cycle Stages", "keyboard", "NUMPAD0")
|
||||
RegisterCommand("ulc:stage_cycle", function()
|
||||
if not checks() then return end
|
||||
cycleStages()
|
||||
end)
|
||||
|
||||
--------------------
|
||||
--------------------
|
||||
-- DEFAULT STAGES --
|
||||
--------------------
|
||||
--------------------
|
||||
|
||||
-- checks if the button.key is contained in the stageKeys array and returns the index
|
||||
function getStageFromButton(button)
|
||||
if not button then return false end
|
||||
if not MyVehicle then return false end
|
||||
-- if MyVehicleConfig.stages.stageKeys is nil or doesn't contain the button.key return false
|
||||
if not MyVehicleConfig.stages.stageKeys then return false end
|
||||
for i, key in pairs(MyVehicleConfig.stages.stageKeys) do
|
||||
if key == button.key then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function setDefaultStages()
|
||||
-- default stages
|
||||
if not MyVehicleConfig.defaultStages or false then return end
|
||||
if not MyVehicleConfig.defaultStages.useDefaults then return end
|
||||
for _, e in pairs(MyVehicleConfig.defaultStages.enableKeys) do
|
||||
local button = GetButtonByExtra(GetExtraByKey(e))
|
||||
if not button then break end
|
||||
-- if the button is a stage
|
||||
local stage = getStageFromButton(button)
|
||||
-- if the index of this stage = the current stage do nothing
|
||||
if stage and stage == currentStage then return end
|
||||
-- if this button is not a stage or the stage is not the current stage proceed normally
|
||||
ULC:SetStage(GetExtraByKey(e), 0, false, false, button.repair, true, true, false)
|
||||
end
|
||||
for _, d in pairs(MyVehicleConfig.defaultStages.disableKeys) do
|
||||
local button = GetButtonByExtra(GetExtraByKey(d))
|
||||
if not button then break end
|
||||
ULC:SetStage(GetExtraByKey(d), 1, false, false, button.repair, true, true, false)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
-- Ultimate Lighting Controller by Dawnstar FiveM
|
||||
-- Written by Dawnstar
|
||||
-- Documentation: https://docs.dwnstr.com/ulc/overview
|
||||
-- For support: https://discord.gg/dwnstr-fivem
|
||||
|
||||
-- Most of these can be left at their default values.
|
||||
-- View documentation for details on each value
|
||||
Config = {
|
||||
-- whether to enable control of lights on/off state using Q key
|
||||
-- disabled by default to allow other scripts to control lights such as Luxart
|
||||
-- make sure to disable light controls in other scripts if you enable this
|
||||
controlLights = false,
|
||||
|
||||
-- HUD SETTINGS
|
||||
-- global toggle for UI (affects all clients)
|
||||
hideHud = false,
|
||||
-- whether to use KPH instead of MPH
|
||||
useKPH = false,
|
||||
|
||||
-- Park Pattern Settings;
|
||||
ParkSettings = {
|
||||
-- extras will toggle below this speed
|
||||
speedThreshold = 1,
|
||||
-- time between checks in seconds
|
||||
-- should not be any lower than .5 seconds
|
||||
delay = 0.5,
|
||||
-- distance at which to check for other vehicles to sync patterns with
|
||||
syncDistance = 32,
|
||||
-- seconds before a single client triggers sync again
|
||||
syncCooldown = 10,
|
||||
},
|
||||
|
||||
-- Steady Burn Config;
|
||||
-- changes settings for extras that are enabled at night, or enabled all the time.
|
||||
SteadyBurnSettings = {
|
||||
-- hour effect starts (extras are enabled)
|
||||
nightStartHour = 18,
|
||||
-- hour effect ends (extras are disabled)
|
||||
nightEndHour = 6,
|
||||
},
|
||||
|
||||
-- Brake Extras/Patterns Config;
|
||||
-- temporarily empty as of v1.3.0
|
||||
BrakeSettings = {},
|
||||
|
||||
-- Reverse Extras/Patterns Config;
|
||||
-- introduced in v1.8.0
|
||||
ReverseSettings = {
|
||||
-- these options control the expiration of the reverse extras
|
||||
-- if enabled, reverse extras will turn off after a random time between min and max
|
||||
-- this is to simulate more realistic behavior where the vehicle would shifted out of reverse
|
||||
-- after being stopped for some time
|
||||
useRandomExpiration = true,
|
||||
-- minimum time in seconds extras will stay on after stopping
|
||||
minExpiration = 3,
|
||||
-- maximum time in seconds extras will stay on after stopping
|
||||
maxExpiration = 8,
|
||||
},
|
||||
|
||||
-- Import confiurations here
|
||||
-- Add the resource names of vehicle resources that include a ulc.lua config file
|
||||
ExternalVehResources = {
|
||||
-- ex. "my-police-vehicle",
|
||||
"615",
|
||||
"ccso1",
|
||||
"24sub",
|
||||
"24ramambo",
|
||||
"704",
|
||||
"640",
|
||||
"128",
|
||||
"gpd7",
|
||||
"gpdchief1",
|
||||
""st23tahoe"",
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
Vehicles = {
|
||||
-- this is not required!
|
||||
-- see documentation for instructions!
|
||||
-- https://docs.dwnstr.com/ulc/configuration
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
fx_version 'cerulean'
|
||||
games { 'gta5' }
|
||||
lua54 'yes'
|
||||
|
||||
name "Ultimate Lighting Controls"
|
||||
description "The ultimate non-els lighting controller. Documentation: https://docs.dwnstr.com/ulc/overview"
|
||||
author "Dawnstar"
|
||||
version "1.8.0"
|
||||
|
||||
ui_page "html/index.html"
|
||||
|
||||
files {
|
||||
"html/index.html",
|
||||
"html/assets/*.js",
|
||||
"html/assets/*.css",
|
||||
"html/assets/*.png",
|
||||
"html/assets/*.jpg"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"baseevents",
|
||||
"/onesync"
|
||||
}
|
||||
|
||||
shared_scripts {
|
||||
'config.lua',
|
||||
'shared/shared_functions.lua'
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'client/c_main.lua',
|
||||
'client/c_hud.lua',
|
||||
'client/c_buttons.lua',
|
||||
'client/c_brake.lua',
|
||||
'client/c_blackout.lua',
|
||||
'client/c_cruise.lua',
|
||||
'client/c_horn.lua',
|
||||
'client/c_park.lua',
|
||||
'client/c_doors.lua',
|
||||
'client/c_reverse.lua',
|
||||
'client/c_stages.lua',
|
||||
'client/c_beeps.lua',
|
||||
|
||||
}
|
||||
|
||||
server_scripts {
|
||||
'server/s_main.lua',
|
||||
'server/s_main.js',
|
||||
'server/s_blackout.lua',
|
||||
}
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 57 KiB |
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
<script type="module" crossorigin src="./assets/index.7ebd96a6.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.e1c6fa6f.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,7 @@
|
||||
|
||||
RegisterNetEvent('ulc:setBlackout', function(netId, state)
|
||||
print("[ULC] Setting blackout to " .. tostring(state) .. " on vehicle " .. tostring(netId))
|
||||
local vehicle = NetworkGetEntityFromNetworkId(netId)
|
||||
Entity(vehicle).state.ulc_blackout = state
|
||||
end)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
print("[ULC] LVC Integrations Loaded")
|
||||
|
||||
-- triggers when player changes main siren state in LVC
|
||||
-- newState is an int representing the index of a siren in lvc/SIRENS.lua:SIRENS
|
||||
RegisterNetEvent("lvc:SetLxSirenState_s")
|
||||
AddEventHandler("lvc:SetLxSirenState_s", function(newState)
|
||||
local src = source
|
||||
print("[lvc:SetLxSirenState_s] " .. src .. " " .. newState)
|
||||
TriggerClientEvent("ulc:LVC_MainSirenStateChange", src, newState)
|
||||
end)
|
||||
|
||||
-- TODO: this isn't use anywhere yet
|
||||
@@ -0,0 +1,45 @@
|
||||
// This API died :(
|
||||
|
||||
// https.get('https://api.countapi.xyz/hit/dwnstr.com/ulcloadcount/', (res) => {
|
||||
// const { statusCode } = res;
|
||||
// const contentType = res.headers['content-type'];
|
||||
|
||||
// let error;
|
||||
// // Any 2xx status code signals a successful response but
|
||||
// // here we're only checking for 200.
|
||||
// if (statusCode !== 200) {
|
||||
// error = new Error('Request Failed.\n' +
|
||||
// `Status Code: ${statusCode}`);
|
||||
// } else if (!/^application\/json/.test(contentType)) {
|
||||
// error = new Error('Invalid content-type.\n' +
|
||||
// `Expected application/json but received ${contentType}`);
|
||||
// }
|
||||
// if (error) {
|
||||
// // console.error(error.message);
|
||||
// // Consume response data to free up memory
|
||||
// res.resume();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// res.setEncoding('utf8');
|
||||
// let rawData = '';
|
||||
// res.on('data', (chunk) => { rawData += chunk; });
|
||||
// res.on('end', () => {
|
||||
// try {
|
||||
// const parsedData = JSON.parse(rawData);
|
||||
// console.log(`[ULC] ULC has been loaded on servers ${parsedData.value} times :D`);
|
||||
// } catch (e) {
|
||||
// // console.error(e.message);
|
||||
// }
|
||||
// });
|
||||
// }).on('error', (e) => {
|
||||
// // console.error(`Got error: ${e.message}`);
|
||||
// });
|
||||
|
||||
// // Create a local server to receive data from
|
||||
// const server = http.createServer((req, res) => {
|
||||
// res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
// res.end(JSON.stringify({
|
||||
// data: 'Hello World!',
|
||||
// }));
|
||||
// });
|
||||
@@ -0,0 +1,390 @@
|
||||
print("Server thread loaded.")
|
||||
|
||||
AddEventHandler('ulc:error', function(error)
|
||||
print("^1[ULC ERROR] " .. error)
|
||||
end)
|
||||
|
||||
AddEventHandler('ulc:warn', function(error)
|
||||
print("^3[ULC WARNING] " .. error)
|
||||
end)
|
||||
|
||||
local myVersion = GetResourceMetadata("ulc", "version", 0)
|
||||
local latestVersion = ''
|
||||
|
||||
if GetCurrentResourceName() ~= 'ulc' then
|
||||
TriggerEvent('ulc:error', "Resource is named incorrectly. Version checks will not work.")
|
||||
end
|
||||
|
||||
--TODO change loading state to use this instead of events
|
||||
GlobalState.ulcloaded = false
|
||||
|
||||
PerformHttpRequest("https://api.github.com/repos/Flohhhhh/ultimate-lighting-controller/releases/latest",
|
||||
function(errorCode, resultData, resultHeaders)
|
||||
print("[ULC] My Version: [" .. myVersion .. "]")
|
||||
|
||||
local errorString = tostring(errorCode)
|
||||
if errorString == "403" or errorString == "404" then
|
||||
print("Got code " .. errorString .. " when trying to get version.")
|
||||
return
|
||||
end
|
||||
|
||||
latestVersion = json.decode(resultData).name
|
||||
print("^0[ULC] Latest Version: [" .. latestVersion .. "]")
|
||||
|
||||
print([[
|
||||
___ ___ ___ ________
|
||||
|\ \|\ \ |\ \ |\ ____\
|
||||
\ \ \\\ \\ \ \ \ \ \___|
|
||||
\ \ \\\ \\ \ \ \ \ \
|
||||
\ \ \\\ \\ \ \____ \ \ \____
|
||||
\ \_______\\ \_______\\ \_______\
|
||||
\|_______| \|_______| \|_______|
|
||||
|
||||
ULTIMATE LIGHTING CONTROLLER
|
||||
by Dawnstar
|
||||
^2Loaded
|
||||
]])
|
||||
if myVersion and ("v" .. myVersion) == latestVersion then
|
||||
print('[ULC] Up to date!')
|
||||
else
|
||||
print("^1[ULC] OUTDATED. A NEW VERSION (" .. latestVersion .. ") IS AVAILABLE.^0")
|
||||
print("^1[ULC] YOUR VERSION: " .. myVersion .. "^0")
|
||||
print("[ULC] GET LATEST VERSION HERE: https://github.com/Flohhhhh/ultimate-lighting-controller/releases/")
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
local function IsIntInTable(table, int)
|
||||
for k, v in ipairs(table) do
|
||||
if v == int then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
if Config.ParkSettings.delay < 0.5 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'Park Pattern delay is too short! This will hurt performance! Recommended values are above 0.5s.')
|
||||
end
|
||||
|
||||
-- removed v1.7.0
|
||||
-- if Config.SteadyBurnSettings.delay <= 2 then
|
||||
-- TriggerEvent("ulc:error", 'Steady burn delay is too short! Steady burns will be unstable or not work!')
|
||||
-- end
|
||||
|
||||
if Config.SteadyBurnSettings.nightStartHour < Config.SteadyBurnSettings.nightEndHour then
|
||||
TriggerEvent("ulc:error", 'Steady burn night start hour should be later/higher than night end hour.')
|
||||
end
|
||||
|
||||
-- removed v1.7.0
|
||||
-- if Config.SteadyBurnSettings.delay < 2 then
|
||||
-- TriggerEvent("ulc:error", "Steady burn check delay can never be lower than 2 seconds. Will cause stability issues.")
|
||||
-- end
|
||||
|
||||
local function CheckData(data, resourceName)
|
||||
if not data.name and not data.names then
|
||||
TriggerEvent("ulc:error", "^1Vehicle config in resource \"" .. resourceName .. "\" does not include model names!^0")
|
||||
return false
|
||||
elseif data.name then
|
||||
TriggerEvent("ulc:warn",
|
||||
"^1Vehicle config in resource \"" ..
|
||||
resourceName .. "\" uses deprecated 'name' field. Change to > names = {'yourvehicle'}^0")
|
||||
if type(data.name) ~= "string" then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Vehicle config in resource \"" .. resourceName .. "\" 'name' field can only accept a string.^0")
|
||||
return false
|
||||
end
|
||||
elseif data.names then
|
||||
if type(data.names) ~= "table" then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Vehicle config in resource \"" .. resourceName .. "\" 'names' field can only accept a table of strings.^0")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- check if data is missing
|
||||
if not data.parkConfig or not data.brakeConfig or not data.buttons or not data.hornConfig then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Vehicle config in resource \"" .. resourceName .. "\" is missing data or not formatted properly. View docs.^0")
|
||||
return false
|
||||
end
|
||||
|
||||
-- check if steady burns are enabled but no extras specified
|
||||
if (data.steadyBurnConfig.forceOn or data.steadyBurnConfig.useTime) and #data.steadyBurnConfig.sbExtras == 0 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' .. resourceName .. '" uses Steady Burns, but no extras were specified (sbExtras = {})')
|
||||
end
|
||||
|
||||
-- check if park pattern enabled but no extras specified
|
||||
if data.parkConfig.usePark then
|
||||
if #data.parkConfig.pExtras == 0 and #data.parkConfig.dExtras == 0 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' ..
|
||||
resourceName .. '" uses Park Patterns, but no park or drive extras were specified (pExtras = {}, dExtras = {})')
|
||||
end
|
||||
end
|
||||
|
||||
-- check if brakes enabled but no extras specified
|
||||
if data.brakeConfig.useBrakes and #data.brakeConfig.brakeExtras == 0 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' .. resourceName .. '" uses Brake Pattern, but no brake extras were specified.')
|
||||
end
|
||||
|
||||
-- check if horn enabled but no extras specified
|
||||
if data.hornConfig.useHorn and #data.hornConfig.hornExtras == 0 then
|
||||
TriggerEvent("ulc:warn", 'A config in "' .. resourceName .. '" uses Horn Extras, but no horn extras were specified.')
|
||||
end
|
||||
|
||||
-- stages
|
||||
if data.stages then
|
||||
-- check if stages are enabled but no keys specified
|
||||
if data.stages.useStages and #data.stages.stageKeys == 0 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' .. resourceName .. '" uses Stages, but no keys were specified.')
|
||||
end
|
||||
|
||||
-- check each key
|
||||
for _, v in pairs(data.stages.stageKeys) do
|
||||
-- if key is not a numpad value
|
||||
if v > 9 then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" has an invalid key in stageKeys (' .. v .. '). Value must be 1-9 representing numpad keys.')
|
||||
break
|
||||
end
|
||||
|
||||
-- make sure each item in data.stages.stageKeys corresponds to a button with key = the value
|
||||
local buttonExists = false
|
||||
for _, b in pairs(data.buttons) do
|
||||
if b.key == v then
|
||||
buttonExists = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not buttonExists then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" has a key in stageKeys (' .. v .. ') that does not correspond to a key assigned to a button.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------
|
||||
-- DEFAULT STAGES --
|
||||
--------------------
|
||||
if data.defaultStages or false then
|
||||
if data.defaultStages.useDefaults then
|
||||
if #data.defaultStages.enableKeys == 0 and #data.defaultStages.disableKeys == 0 then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" uses Default Stages, but no keys were specified to enable (enableKeys = {}) or disable (disableKeys = {}).')
|
||||
else
|
||||
if #data.defaultStages.enableKeys > 0 then
|
||||
for _, v in pairs(data.defaultStages.enableKeys) do
|
||||
if v > 9 then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" has an invalid key in enableKeys = {}. Value must be 1-9 representing numpad keys.')
|
||||
end
|
||||
end
|
||||
end
|
||||
if #data.defaultStages.disableKeys > 0 then
|
||||
for _, v in pairs(data.defaultStages.disableKeys) do
|
||||
if v > 9 then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' ..
|
||||
resourceName .. '" has an invalid key in disableKeys = {}. Value must be 1-9 representing numpad keys.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Buttons
|
||||
-- check if vehicle uses buttons but hud is disabled
|
||||
if #data.buttons > 0 and Config.hideHud == true then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" uses Stage Buttons, but HUD/UI is globally disabled. This is not recommended for user experience.')
|
||||
end
|
||||
|
||||
local usedButtons = {}
|
||||
local usedExtras = {}
|
||||
for i, b in ipairs(data.buttons) do
|
||||
-- check if key is valid
|
||||
if b.key > 9 or b.key < 1 then
|
||||
TriggerEvent('ulc:error',
|
||||
'Button ' ..
|
||||
i ..
|
||||
' in a config found in the resource: "' ..
|
||||
resourceName .. '" has an invalid key. Key must be 1-9 representing number pad keys.')
|
||||
return false
|
||||
end
|
||||
-- check if label is empty
|
||||
if b.label == '' then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' .. resourceName .. '" has an un-labeled button using extra: ' .. b.extra)
|
||||
return false
|
||||
end
|
||||
if not validateButtonText(b.label) then
|
||||
TriggerEvent("ulc:warn",
|
||||
'A config in "' ..
|
||||
resourceName ..
|
||||
'" has a button with label: "' ..
|
||||
b.label ..
|
||||
'" which is not valid and will result in a poor user experience. Please make sure there are no more than 3 words and each word is a maximum of 5 characters. Use abbreviations where possible. Ex. "Takedowns" -> "TKD".')
|
||||
end
|
||||
if b.color and (b.color ~= 'blue' and b.color ~= 'green' and b.color ~= 'amber' and b.color ~= 'red') then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' ..
|
||||
resourceName .. '" has a button with an invalid color input: "' .. b.color .. '" is not a supported color.')
|
||||
end
|
||||
-- check if any keys are used twice
|
||||
if IsIntInTable(usedButtons, b.key) then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' .. resourceName .. '" uses key: " .. b.key .. " more than once in button config.')
|
||||
return false
|
||||
end
|
||||
-- check if any extras are used twice
|
||||
if IsIntInTable(usedExtras, b.extra) then
|
||||
TriggerEvent("ulc:error",
|
||||
'A config in "' .. resourceName .. '" uses extra: " .. b.extra .. " more than once in button config.')
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
RegisterNetEvent('baseevents:enteredVehicle')
|
||||
AddEventHandler('baseevents:enteredVehicle', function()
|
||||
local src = source
|
||||
TriggerClientEvent("UpdateVehicleConfigs", src, Config.Vehicles)
|
||||
TriggerClientEvent('ulc:checkVehicle', src)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('baseevents:leftVehicle')
|
||||
AddEventHandler('baseevents:leftVehicle', function()
|
||||
local src = source
|
||||
TriggerClientEvent('ulc:cleanup', src)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('ulc:sync:send')
|
||||
AddEventHandler('ulc:sync:send', function(vehicles)
|
||||
print("Player " .. source .. " sent a sync request.")
|
||||
local players = GetPlayers()
|
||||
for i, v in ipairs(players) do
|
||||
if not v == source then
|
||||
--print("Sending veh sync array to player: " .. v)
|
||||
TriggerClientEvent('ulc:sync:receive', vehicles)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
local function LoadExternalVehicleConfig(resourceName)
|
||||
local resourceState = GetResourceState(resourceName)
|
||||
|
||||
if resourceState == "missing" then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Couldn't load external ulc.lua file from resource: \"" ..
|
||||
resourceName ..
|
||||
"\". Resource is missing. You probably entered the model name in config.lua instead of the resource name.^0")
|
||||
return
|
||||
end
|
||||
|
||||
if resourceState == "stopped" then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Couldn't load external ulc.lua file from resource: \"" .. resourceName .. "\". Resource is stopped.^0")
|
||||
return
|
||||
end
|
||||
|
||||
if resourceState == "uninitialized" or resourceState == "unknown" then
|
||||
TriggerEvent("ulc:error",
|
||||
"^1Couldn't load external ulc.lua file from resource: \"" ..
|
||||
resourceName .. "\". Resource could not be loaded. Unknown issue.^0")
|
||||
return
|
||||
end
|
||||
|
||||
local data = LoadResourceFile(resourceName, "data/ulc.lua")
|
||||
if not data then
|
||||
data = LoadResourceFile(resourceName, "ulc.lua")
|
||||
if not data then
|
||||
print("Error loading 'ulc.lua' file. Make sure it is at the root of your resource or in the 'data' folder.")
|
||||
TriggerEvent("ulc:error", '^1Could not load external configuration in: "' .. resourceName .. '"^0')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local f, err = load(data)
|
||||
if err then
|
||||
TriggerEvent("ulc:error",
|
||||
'^1Could not load external configuration in: "' .. resourceName .. '"; error: "' .. err .. '"^0')
|
||||
return
|
||||
end
|
||||
if not f or not f() then
|
||||
TriggerEvent("ulc:error",
|
||||
'^1Could not load external configuration; data loaded from: "' .. resourceName .. '" was nil. ^0')
|
||||
return
|
||||
end
|
||||
|
||||
-- NEW STUFF FOR MULTIPLE CONFIGS
|
||||
local configs = { f() }
|
||||
for _, v in pairs(configs) do
|
||||
if CheckData(v, resourceName) then
|
||||
if v.name then -- if using old single name
|
||||
print('^2[ULC] Loaded external configuration for "' .. v.name .. '"^0')
|
||||
elseif v.names then -- if using new table
|
||||
for _, name in ipairs(v.names) do
|
||||
print('^2[ULC] Loaded external configuration for "' .. name .. '"^0')
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(Config.Vehicles, v)
|
||||
else
|
||||
TriggerEvent("ulc:error", '^1Could not load external configuration in "' .. resourceName .. '"^0')
|
||||
end
|
||||
end
|
||||
|
||||
-- if CheckData(f(), resourceName) then
|
||||
-- print('^2Loaded external configuration for "' .. f().name .. '"^0')
|
||||
-- table.insert(Config.Vehicles, f())
|
||||
-- else
|
||||
-- TriggerEvent("ulc:error", '^1Could not load external configuration for "' .. f().name .. '"^0')
|
||||
-- end
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
Wait(2000)
|
||||
print("[ULC] Checking for external vehicle resources.")
|
||||
for k, v in ipairs(Config.ExternalVehResources) do
|
||||
local resourceState = GetResourceState(v)
|
||||
while resourceState == "starting" do
|
||||
print("^3[ULC] Waiting for resource: " .. resourceName .. " to load.")
|
||||
Wait(100)
|
||||
end
|
||||
LoadExternalVehicleConfig(v)
|
||||
end
|
||||
--TriggerClientEvent('ulc:Loaded', -1)
|
||||
GlobalState.ulcloaded = true
|
||||
TriggerClientEvent("UpdateVehicleConfigs", -1, Config.Vehicles)
|
||||
print("[ULC] Loading complete: " ..
|
||||
#Config.Vehicles .. " external vehicle configurations loaded. State check: " .. tostring(GlobalState.ulcloaded))
|
||||
for _, v in ipairs(Config.Vehicles) do
|
||||
if v.name then -- if using old single name
|
||||
print('[ULC] Loaded: ' .. v.name)
|
||||
elseif v.names then -- if using new table
|
||||
for _, name in ipairs(v.names) do
|
||||
print('[ULC] Loaded: ' .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,110 @@
|
||||
-- Returns: bool (whether vehicle was found), table (vehicle config info)
|
||||
function GetVehicleFromConfig(vehicle)
|
||||
for _, v in pairs(Config.Vehicles) do
|
||||
-- if old method with just a string
|
||||
if v.name then
|
||||
-- find which vehicle matches
|
||||
if GetEntityModel(vehicle) == GetHashKey(v.name) then
|
||||
--print("Vehicle [" .. v.name .. "] was found in Config.")
|
||||
return true, v
|
||||
end
|
||||
elseif v.names then -- if new method with a table
|
||||
-- for each name check if it matches the vehicle
|
||||
for _, n in ipairs(v.names) do
|
||||
if GetEntityModel(vehicle) == GetHashKey(n) then
|
||||
--print("Vehicle [" .. v.name .. "] was found in Config.")
|
||||
return true, v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns whether a vehicle is in a table of vehicle spawn names given a vehicle handle
|
||||
function IsVehicleInTable(vehicle, table)
|
||||
--print(table)
|
||||
for _, v in pairs(table) do
|
||||
--print(v)
|
||||
--print(GetHashKey(v))
|
||||
--print(vehicle)
|
||||
--print(GetEntityModel(vehicle))
|
||||
if GetEntityModel(vehicle) == GetHashKey(v) then
|
||||
return true, v
|
||||
else
|
||||
--print("Vehicle [" .. v .. "] not found in table.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the vehicle speed converted to MPH or KPH based on config value
|
||||
function GetVehicleSpeedConverted(vehicle)
|
||||
if Config.useKPH then
|
||||
return GetEntitySpeed(Entity(vehicle)) * 3.6
|
||||
else
|
||||
return GetEntitySpeed(Entity(vehicle)) * 2.236936
|
||||
end
|
||||
end
|
||||
|
||||
-- returns true when all vehicle doors are fully closed
|
||||
function AreVehicleDoorsClosed(vehicle)
|
||||
local result = true
|
||||
local numberOfDoors = GetNumberOfVehicleDoors(vehicle)
|
||||
for i = 0, numberOfDoors, 1 do
|
||||
if GetVehicleDoorAngleRatio(vehicle, i) > 0.0 then
|
||||
--print("[AreVehicleDoorsClosed()] Door " .. i .. " is open.")
|
||||
result = false
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- returns true when vehicle health is above config threshold
|
||||
function IsVehicleHealthy(vehicle)
|
||||
local vehHealth = GetVehicleBodyHealth(vehicle)
|
||||
|
||||
if vehHealth > 980 then
|
||||
return true
|
||||
else
|
||||
--print("[IsVehicleHealth())] Vehicle is damaged.")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function SortButtonsByKey(arr)
|
||||
table.sort(arr, function(a, b)
|
||||
return a["key"] < b["key"]
|
||||
end)
|
||||
end
|
||||
|
||||
function formatInt(num)
|
||||
local formatted = tostring(num)
|
||||
local length = formatted:len()
|
||||
|
||||
for i = length - 3, 1, -3 do
|
||||
formatted = formatted:sub(1, i) .. ',' .. formatted:sub(i + 1)
|
||||
end
|
||||
|
||||
return formatted
|
||||
end
|
||||
|
||||
function validateButtonText(text)
|
||||
local count = 0
|
||||
for word in text:gmatch("%w+") do
|
||||
count = count + 1
|
||||
if count > 3 or #word > 5 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Function to check if a value exists in a table
|
||||
-- Returns: bool (whether value is contained), int (index of value if contained)
|
||||
function contains(table, val)
|
||||
for i, v in ipairs(table) do
|
||||
if v == val then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||