structura foldere

mutat kq- folders in un singur folder [kq]
This commit is contained in:
2026-03-30 01:55:03 +03:00
parent af1286d583
commit c291b81f26
2319 changed files with 0 additions and 14 deletions

View File

@@ -0,0 +1,19 @@
# KQ_ANIMSUGGEST INSTALLATION GUIDE
This guide will provide step-by-step instructions on how to install and set up the KQ_ANIMSUGGEST script for FiveM.
## Step 1:
After downloading the script, unzip the folder and place it in the `resources` directory on your FiveM server.
## Step 2:
Add the script to your `server.cfg` file.
## Step 3:
Configure the script to your likings. Add your own animations, or customize the keybind tooltip look
## Done
Enjoy the script
https://kuzquality.com/
https://discord.gg/fZsyam7Rvz

View File

@@ -0,0 +1,85 @@
local BLOCKED = false
RegisterNetEvent('kq_animsuggest:client:toggleSuggestions')
AddEventHandler('kq_animsuggest:client:toggleSuggestions', function(allow)
BLOCKED = not allow
end)
function CanUseSuggestions()
return (not BLOCKED and not IsPlayerUnreachable())
end
--- Keybind Hint
function ShowKeybindHint(keybind, label)
SendNUIMessage({
event = 'show',
keybind = keybind,
prefix = L('Press'),
suffix = L('to {action}'):gsub('{action}', label)
})
end
function HideKeybindHint()
SendNUIMessage({
event = 'hide',
})
end
--- Main animation triggering functions
function PlayAnim(ped, dict, anim, flag, duration)
Citizen.CreateThread(function()
RequestAnimDict(dict)
local timeout = 0
while not HasAnimDictLoaded(dict) do
Citizen.Wait(50)
timeout = timeout + 1
if timeout > 100 then
return
end
end
TaskPlayAnim(ped or PlayerPedId(), dict, anim, 1.5, 1.0, duration or -1, flag or 1, 0, false, false, false)
RemoveAnimDict(dict)
end)
end
function PlayAnimAdvanced(ped, dict, anim, flag, coords, rotation)
Citizen.CreateThread(function()
RequestAnimDict(dict)
local timeout = 0
while not HasAnimDictLoaded(dict) do
Citizen.Wait(50)
timeout = timeout + 1
if timeout > 100 then
return
end
end
TaskPlayAnimAdvanced(ped or PlayerPedId(), dict, anim,
coords.x, coords.y, coords.z,
rotation.x, rotation.y, rotation.z,
1.5, 1.0, -1, flag or 1, 0.0, false, false)
RemoveAnimDict(dict)
end)
end
---
function IsPlayerUnreachable()
local playerPed = PlayerPedId()
return IsPedInAnyVehicle(playerPed) or IsPedRagdoll(playerPed) or IsEntityDead(playerPed)
end
function CreateProp(toolData)
local playerPed = PlayerPedId()
local toolModel = toolData.model
local coords = GetEntityCoords(playerPed)
local boneIndex = GetPedBoneIndex(playerPed, toolData.bone or 28422)
DoRequestModel(toolModel)
local object = CreateObject(toolModel, coords, true, true, true)
AttachEntityToEntity(object, playerPed, boneIndex, toolData.pos.x, toolData.pos.y, toolData.pos.z, toolData.rot.x, toolData.rot.y, toolData.rot.z, true, true, false, true, 1, true)
return object
end

View File

@@ -0,0 +1,579 @@
Config = {}
--- Debug mode
---
--- This feature will enable additional debug views as well as some debug prints
--- Should only be used in a development-environment
Config.debug = false
--- Default keybinds & tooltip look
Config.keybinds = {
play = {
key = 'minus', -- Default keybind - After loading the script once. This keybind will be assigned to your game settings
},
style = {
-- Whether to show the suggested animation tooltip
show = true,
-- Positioning of the keybind tooltip (offsets)
top = 'auto',
left = 'auto',
bottom = '16px',
right = '16px',
-- Size of the tooltip text
fontSize = 1.4,
-- RGBA value of the tooltip background
bgColor = { 194, 207, 204, 0.6 },
-- RGBA value of the tooltip text
textColor = { 20, 20, 20, 1 },
-- RGBA value of the keybind background
keybindBgColor = { 40, 40, 40, 0.6 },
-- RGBA value of the keybind text
keybindTextColor = { 255, 255, 255, 1 },
-- Strength of corner rounding
borderRadius = 0.1,
}
}
--- Animation play cooldown in ms
Config.cooldown = 1000
--- Controls which will cancel the animation when pressed
-- https://docs.fivem.net/docs/game-references/controls/
Config.cancelControls = {
22, 23, 25, 263, 264,
}
--- Animation lists
---
--- Here you can create your own lists of animations which you may want to reuse
---
--- Mind that not all pre-configured events use lists. You can also simply input the animations directly into the
--- specific events.
---
--- Animations can also contain tools, noted under a "tool" attribute.
--- these should be a table containing the following values:
--- pos = vector3 of the tool offset position
--- rot = vector3 of the tool offset rotation
--- model = the model name of the tool
--- bone = the numerical bone of attachment
---
--- e.g.
-- tool = {
-- pos = vector3(0.08, -0.1, -0.03),
-- rot = vector3(-75.0, 0.0, 10.0),
-- model = 'prop_tool_pickaxe',
-- bone = 28422,
-- },
---
--- The animations are able to trigger events as well. Noted under an "event" attribute
--- these should contain the following values:
--- event = name of the event
--- type = "client" or "server"
---
---e.g.
-- event = {
-- event = "kq_yourscript:random-event",
-- type = "client"
-- }
---
--- You can see the barbeque prop for an example of the "tool" and "event" usage
Config.animLists = {
['sitting'] = {
{
dict = 'timetable@ron@ig_5_p3',
anim = 'ig_5_p3_base',
flag = 33,
offset = vector3(0.0, 0.55, 0.52),
},
{
dict = 'timetable@reunited@ig_10',
anim = 'base_amanda',
flag = 33,
offset = vector3(0.0, 0.55, 0.52),
},
{
dict = 'timetable@ron@ig_3_couch',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.65, 0.52),
},
{
dict = 'timetable@maid@couch@',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.45, 0.65),
},
},
['dance'] = {
{
dict = 'anim@amb@nightclub@dancers@solomun_entourage@',
anim = 'mi_dance_facedj_17_v1_female^1',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@mini@dance@dance_solo@female@var_a@',
anim = 'high_center',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@mini@dance@dance_solo@female@var_b@',
anim = 'high_center',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@mini@dance@dance_solo@male@var_b@',
anim = 'high_center_down',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@dancers@podium_dancers@',
anim = 'hi_dance_facedj_17_v2_male^5',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@dancers@crowddance_facedj@hi_intensity',
anim = 'hi_dance_facedj_09_v2_female^1',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@mini@dance@dance_solo@female@var_a@',
anim = 'high_center_up',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
}
}
--- Animation suggestions for specific props
---
--- Define specific props along with their co-responding animations
--- Feel free to add or remove these
---
--- label: text displayed in the keybind tooltip
--- align: whether or not to align the player with the prop (make sure to specify the offset when true)
--- offset: offset of the animation from the prop
--- models: models of the props on which this action will be possible
--- animations: an inline table of animations or an `Config.animList` table of animations
Config.propSpecific = {
{
label = 'aseaza-te',
align = true,
offset = vector3(0.0, -1.3, 0.45),
models = {
'prop_bench_01a',
'prop_bench_01c',
'prop_bench_02',
'prop_bench_03',
'prop_bench_04',
'prop_bench_05',
'prop_bench_06',
'prop_bench_07',
'prop_bench_08',
'prop_bench_09',
'prop_bench_10',
'prop_bench_11',
},
animations = Config.animLists['sitting'],
},
{
label = 'cauta in cos',
align = false,
models = {
'prop_bin_01a',
'prop_bin_03a',
'prop_bin_05a',
},
animations = {
{
dict = 'mini@repair',
anim = 'fixing_a_ped',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
},
},
{ -- Complete example with all the options
label = 'gratar',
align = false,
models = {
'prop_bbq_5',
},
animations = {
{
dict = 'amb@prop_human_bbq@male@idle_a',
anim = 'idle_b',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
event = {
event = 'your-event:name',
type = 'client', -- client or server
params = 'bbq-start', -- this could be a table as well. It will be sent as the first attribute of the event
},
tool = {
pos = vector3(0.0, 0.0, 0.0),
rot = vector3(0.0, 0.0, 0.0),
model = 'prop_fish_slice_01',
bone = 28422,
},
},
},
},
}
--- Animation suggestions for specific areas
---
--- Define specific areas along with their co-responding animations
--- Feel free to add or remove these
---
--- label: text displayed in the keybind tooltip
--- coords: coordinates of the area
--- radius: radius of the animation area
--- animations: an inline table of animations or an `Config.animList` table of animations
Config.areaSpecific = {
{ -- vanilla unicorn
label = 'danseaza',
coords = vector3(115.6, -1289.0, 28.2),
radius = 13.0,
animations = Config.animLists['dance'],
},
{ -- tequilalala
label = 'danseaza',
coords = vector3(-557.65, 285.32, 82.2),
radius = 10.0,
animations = Config.animLists['dance'],
},
{ -- bahamas mammas
label = 'danseaza',
coords = vector3(-1386.73, -619.17, 30.8),
radius = 10.0,
animations = Config.animLists['dance'],
},
}
--- Main animation suggestion configuration
---
--- Available events:
--- - lean - Leaning when something is directly behind the player
--- - leanBar - Leaning forward when something is directly in front the player but not higher up than their chest (bar etc.)
--- - sit - Sitting down when something is located behind the player below their waist (walls, stairs, chairs etc.)
--- - idle - May be used anywhere. Active after the player has been stationary for 4 or more seconds
--- - intimidate - General intimidation gestures. Active for few seconds after player has been in melee combat
--- - showPain - Shows that the player is hurt. Active when player has below 60% of their health
--- - inspectCar - Inspects cars engine/trunk. Active when player is looking at an engine bay or trunk which is open
--- - cheerBurnout - Cheering/clapping. Active when player is looking at a car performing a burnout or drifting
--- - greet - Waving hello. Active when a player is looking at another player whom he hasn't greeted before in the last 15 minutes
--- - conversation - Hand motion imitating player talking with others. Active when player is looking at a nearby player
---
--- enabled: whether the specific action type should be enabled
--- label: text displayed in the keybind tooltip
--- animations: an inline table of animations or an `Config.animList` table of animations
Config.animations = {
lean = {
enabled = true,
label = 'sprijina-te',
animations = {
{
dict = 'anim@scripted@freemode_npc@fix_agy_ig4_lamar@',
anim = 'lean_wall_idle_01_lamar',
flag = 33,
offset = vector3(0.0, 0.35, 0.0),
},
{
dict = 'amb@world_human_leaning@male@wall@back@foot_up@idle_a',
anim = 'idle_a',
flag = 33,
offset = vector3(0.0, 0.35, 0.0),
},
{
dict = 'anim@scripted@freemode_npc@fix_agy_ig4_lamar@',
anim = 'lean_wall_idle_01_lamar',
flag = 33,
offset = vector3(0.0, 0.35, 0.0),
},
{
dict = 'amb@world_human_leaning@female@wall@back@holding_elbow@idle_a',
anim = 'idle_a',
flag = 33,
offset = vector3(0.0, 0.35, 0.0),
}
},
},
leanBar = {
enabled = true,
label = 'apleca-te',
animations = {
{
dict = 'anim@amb@nightclub@lazlow@ig1_vip@',
anim = 'clubvip_base_laz',
flag = 33,
offset = vector3(0.0, -0.55, 0.02),
},
{
dict = 'amb@prop_human_bum_shopping_cart@male@idle_a',
anim = 'idle_c',
flag = 33,
offset = vector3(0.0, -0.55, 0.02),
},
{
dict = 'anim@amb@nightclub@lazlow@ig1_vip@',
anim = 'clubvip_dlg_jimmyboston_laz',
flag = 33,
offset = vector3(0.0, -0.45, 0.085),
},
},
},
sit = {
enabled = true,
label = 'aseaza-te',
animations = Config.animLists['sitting'],
},
idle = {
enabled = true,
label = 'relaxeaza-te',
minimumTime = 4, -- Minimum time in seconds it'll take before the suggestion appears
animations = {
{
dict = 'rcmjosh1',
anim = 'idle',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'rcmnigel1a',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'missbigscore2aig_3',
anim = 'wait_for_van_c',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'amb@world_human_hang_out_street@female_arms_crossed@idle_a',
anim = 'idle_a',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@heists@heist_corona@single_team',
anim = 'single_team_loop_boss',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
}
},
intimidate = {
enabled = true,
label = 'intimideaza',
animations = {
{
dict = 'anim@mp_player_intselfiethe_bird',
anim = 'idle_a',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@mp_player_intupperfinger',
anim = 'idle_a_fp',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'mini@triathlon',
anim = 'want_some_of_this',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@mp_player_intcelebrationfemale@knuckle_crunch',
anim = 'knuckle_crunch',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'mp_player_int_uppergrab_crotch',
anim = 'mp_player_int_grab_crotch',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'misscommon@response',
anim = 'bring_it_on',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'misscommon@response',
anim = 'screw_you',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
}
},
showPain = {
enabled = true,
label = 'arata durere',
animations = {
{
dict = 'anim@amb@casino@valet_scenario@pose_d@',
anim = 'scratch_face_a_m_y_vinewood_01',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@machinery@lathe@',
anim = 'scratch_amy_skater_01',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'timetable@gardener@smoking_joint',
anim = 'idle_cough',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
}
},
inspectCar = {
enabled = true,
label = 'inspectare vehicul',
animations = {
{
dict = 'anim@amb@carmeet@checkout_engine@male_a@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_b@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_c@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_d@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_f@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_g@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@carmeet@checkout_engine@male_h@base',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
},
},
cheerBurnout = {
enabled = true,
label = 'aplauze',
animations = {
{
dict = 'amb@world_human_cheering@male_a',
anim = 'base',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'anim@amb@nightclub@peds@',
anim = 'amb_world_human_cheering_female_c',
flag = 33,
offset = vector3(0.0, 0.0, 0.0),
},
},
},
greet = {
enabled = true,
label = 'saluta',
animations = {
{
dict = 'friends@frj@ig_1',
anim = 'wave_e',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'gestures@m@standing@casual',
anim = 'gesture_hello',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
},
},
conversation = {
enabled = true,
label = 'vorbeste',
animations = {
{
dict = 'misscarsteal4@vendor',
anim = 'idle_a_customer1',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'missfbi3_party_d',
anim = 'stand_talk_loop_a_male1',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'missfbi3_party_d',
anim = 'stand_talk_loop_a_male2',
flag = 48,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'missfbi3_party_d',
anim = 'stand_talk_loop_b_male2',
flag = 49,
offset = vector3(0.0, 0.0, 0.0),
},
{
dict = 'missfbi3_party_d',
anim = 'stand_talk_loop_b_male3',
flag = 49,
offset = vector3(0.0, 0.0, 0.0),
},
},
},
}

View File

@@ -0,0 +1,45 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Animation suggestions by KuzQuality'
version '1.2.2'
ui_page 'nui/index.html'
files {
'nui/*.html',
'nui/js/*.js',
}
--
-- Server
--
server_scripts {
}
--
-- Client
--
client_scripts {
'config.lua',
'locale.lua',
'client/constants.lua',
'client/settings.lua',
'client/functions.lua',
'client/cache.lua',
'client/client.lua',
'client/editable/client.lua',
}
escrow_ignore {
'config.lua',
'locale.lua',
'client/editable/*.lua',
}
dependency '/assetpacks'

View File

@@ -0,0 +1,7 @@
--- Only modify the value on the right side. Do not change the original text located between the square brackets!
Locale = {
['Press'] = 'Apasa',
['to {action}'] = 'pentru a {action}',
['Play suggested animation'] = 'Reda animatia sugerata',
}

View File

@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/jquery.js"></script>
</head>
<body>
<div class="keybind-hint">
<label id="text-prefix">Press</label>
<div class="keybind-block">
<label id="text-keybind">-</label>
</div>
<label id="text-suffix">to idle</label>
</div>
</body>
</html>
<script>
$(document).ready(function () {
$keybindHint = $('.keybind-hint');
$keybindHint.hide();
window.addEventListener('message', ({data}) => {
if (data.event === 'setStyle') {
$keybindHint.css('top', data.top);
$keybindHint.css('bottom', data.bottom);
$keybindHint.css('left', data.left);
$keybindHint.css('right', data.right);
$keybindHint.show();
const $body = $('body').get(0).style;
$body.setProperty('--fontSize', data.fontSize + 'vh');
$body.setProperty('--bgColor', data.bgColor);
$body.setProperty('--textColor', data.textColor);
$body.setProperty('--keybindBgColor', data.keybindBgColor);
$body.setProperty('--keybindTextColor', data.keybindTextColor);
$body.setProperty('--borderRadius', data.borderRadius + 'vh');
}
if (data.event === 'hide') {
$('body').fadeOut(300);
}
if (data.event === 'show') {
$('body').fadeIn(300);
$('#text-prefix').html(data.prefix);
$('#text-keybind').html(data.keybind);
$('#text-suffix').html(data.suffix);
}
});
fetch(`https://${GetParentResourceName()}/UILoaded`, {
method: 'POST',
});
});
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400&display=swap');
body {
display: none;
--fontSize: 0.9vh;
--bgColor: rgba(194, 207, 204, 0.6);
--textColor: rgba(20, 20, 20, 1);
--keybindBgColor: rgba(40, 40, 40, 0.6);
--keybindTextColor: rgba(255, 255, 255, 1);
--borderRadius: 0px;
}
.keybind-hint {
position: fixed;
top: auto;
left: auto;
right: 16px;
bottom: 16px;
background-color: var(--bgColor);
border-radius: var(--borderRadius);
height: auto;
width: auto;
padding: 2px 5px;
text-transform: uppercase;
color: var(--textColor);
font-size: var(--fontSize);
font-weight: lighter;
font-family: 'Roboto Condensed', sans-serif;
}
.keybind-block {
padding: 2px;
height: var(--fontSize);
width: var(--fontSize);
background-color: var(--keybindBgColor);
color: var(--keybindTextColor);
border-radius: var(--borderRadius);
display: inline-flex;
align-items: center;
justify-content: center;
}
#text-keybind {
width: var(--fontSize);
text-align: center;
}
</style>

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,33 @@
# KQ_BIKEJUMP INSTALLATION GUIDE
This guide will provide step-by-step instructions on how to install and set up the KQ_BIKEJUMP script for FiveM.
## Step 1:
After downloading the script, unzip the folder and place it in the `resources` directory on your FiveM server.
## Step 2:
Add the script to your `server.cfg` file.
## Step 3:
Configure the script to your likings via the `config.lua` file
## Done
Enjoy the script
# Usage
(Using default config)
While on a moving bike, press `G`. This will enable the "Jump mode".
When the jump mode is enabled you can hold `Left mouse button` or `Right mouse button` to prepare for a jump.
After letting go of the mouse button, you will perform the jump to that direction.
Auto-jump: When in the "Jump mode", look at a vehicle that's travelling at a similar speed and direction.
If the vehicle is within your jump range, you will see a keybind hint allowing you to press `E` to perform a jump onto the vehicle.
This doesn't guarantee the jump to be successful at all times, it simply makes it easier. But the player still needs to think
when to jump. This "Auto-jump" feature can be disabled via the `config.lua` file.
https://kuzquality.com/
https://discord.gg/fZsyam7Rvz

View File

@@ -0,0 +1,96 @@
-- Decides whether the player is able to perform a jump from a vehicle
function CanJumpFromVehicle(vehicle)
local class = GetVehicleClass(vehicle)
local speed = GetEntitySpeed(vehicle) * 3.6
local whitelist = Config.jumpableVehicles
-- Check whether the vehicle class or model is whitelisted
if not Contains(whitelist.classes, class) and not ContainsHashed(whitelist.models, GetEntityModel(vehicle)) then
return false
end
return speed >= (Config.minBikeSpeed or 5.0)
end
function ShouldFallOffVehicle(vehicle, holding)
if IsEntityUpsidedown(vehicle) then
return true
end
local difference = GetSpeedDifference(vehicle)
local falloffForces = Config.roofHolding.falloffForces or 15.0
if holding then
falloffForces = falloffForces * Config.roofHolding.holdingForceMultiplier
end
return difference > falloffForces
end
local LAST_VEHICLE = nil
local LAST_SPEED = nil
function GetSpeedDifference(vehicle)
return UseCache('GetSpeedDifference_' .. vehicle, function()
local speed = GetEntitySpeed(vehicle) * 3.6
local difference = 0
if LAST_VEHICLE == vehicle then
difference = math.abs(speed - LAST_SPEED)
end
LAST_SPEED = speed
LAST_VEHICLE = vehicle
return difference
end, 100)
end
function KeybindTip(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, 200)
end
-- This function is responsible for all the tooltips displayed on top right of the screen, you could
-- replace it with a custom notification etc.
function Notify(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, -1)
end
-- Floating keybind help
function FloatingText(coords, message, arrowSide)
local tag = 'KqBikeJumpHelpNotification'
AddTextEntry(tag, message)
SetFloatingHelpTextWorldPosition(1, coords)
SetFloatingHelpTextStyle(1, 2, 2, 90, arrowSide or 0, 2)
BeginTextCommandDisplayHelp(tag)
EndTextCommandDisplayHelp(2, false, false, -1)
end
--This function is responsible for drawing all the 3d texts
function Draw3DText(coords, textInput, scaleX)
scaleX = scaleX * (Config.textScale or 1.0)
local px, py, pz = table.unpack(GetGameplayCamCoords())
local dist = GetDistanceBetweenCoords(px, py, pz, coords, true)
local scale = (1 / dist) * 20
local fov = (1 / GetGameplayCamFov()) * 100
scale = scale * fov
SetTextScale(scaleX * scale, scaleX * scale)
SetTextFont(Config.textFont or 4)
SetTextProportional(1)
SetTextDropshadow(1, 1, 1, 1, 255)
SetTextEdge(2, 0, 0, 0, 150)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(textInput)
SetDrawOrigin(coords, 0)
DrawText(0.0, 0.0)
ClearDrawOrigin()
end

View File

@@ -0,0 +1,89 @@
Config = {}
Config.debug = false
-- Vehicles from which players can jump
Config.jumpableVehicles = {
classes = { 8, 13 },
models = {
'blazer',
'blazer2',
'blazer3',
'blazer4',
'seashark',
},
}
-- Type of the input hints. '3d-text' or 'floating'
Config.inputType = 'floating'
-- Size of the 3d text. (Only applicable for the 3d-text option)
Config.textScale = 1.0
-- Minimum bike speed in km/h
Config.minBikeSpeed = 10.0
-- Force of a normal jump. (side, front, up)
Config.jumpForce = vector3(8.0, 0.7, 5.0)
-- Settings related to landing and holding onto roofs of cars
Config.roofHolding = {
enabled = true,
-- Minimum force to fall off a roof
falloffForces = 8.0,
-- Multiplier of the minimum force required to fall off when holding onto the roof
holdingForceMultiplier = 2.5,
-- Whether to allow players to enter vehicles from the roof
allowVehicleEntering = true,
}
-- Settings related to "focus" jumping. (Jumping onto specific vehicles, sort of an aimbot for jumping)
Config.focusJump = {
enabled = true,
-- Maximum difference of velocity for focused jump
maxVelocityDifference = 5.0
}
-- Controls which will be disabled when jumping/preparing a jump
Config.jumping = {
disableControls = {
24, 69, 92, 106, 122, 135, 223, 257,
25, 68, 70, 91, 114, 330,
38, 86,
140, 141, 142, 143
}
}
-- Keybinds
-- https://docs.fivem.net/docs/game-references/controls/
Config.keybinds = {
-- Hardcoded keybinds
jumpRight = {
name = 'INPUT_VEH_AIM',
label = 'RMB',
input = 68,
},
jumpLeft = {
name = 'INPUT_VEH_ATTACK',
label = 'LMB',
input = 69,
},
jumpFocus = {
name = 'INPUT_VEH_HORN',
label = 'E',
input = 86,
},
enterVehicleSeat = {
name = 'INPUT_VEH_HORN',
label = 'E',
input = 86,
},
-- FiveM Keybinds. Editable through the in-game keybinds settings
jumpPrepare = {
key = 'G',
}
}

View File

@@ -0,0 +1,32 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Bike jump by KuzQuality'
version '1.0.0'
client_scripts {
'locale.lua',
'config.lua',
'client/editable/editable.lua',
'client/cache.lua',
'client/functions.lua',
'client/client.lua',
'client/jump.lua',
'client/roof.lua',
}
server_scripts {
'config.lua',
'locale.lua',
'server/server.lua',
}
escrow_ignore {
'config.lua',
'locale.lua',
'client/editable/*.lua',
}
dependency '/assetpacks'

View File

@@ -0,0 +1,11 @@
Locale = {
['~g~Jump mode engaged'] = '~g~Modul de saritura activat',
['~r~Jump cancelled'] = '~r~Saritura anulata',
['~r~Jump mode disabled'] = '~r~Modul de saritura dezactivat',
['~r~[~w~{INPUT}~r~]~w~ Jump'] = '~r~[~w~{INPUT}~r~]~w~ Sari',
['~{INPUT}~ Jump'] = '~{INPUT}~ Sari',
['~r~[~w~{INPUT}~r~]~w~ Enter'] = '~r~[~w~{INPUT}~r~]~w~ Intra',
['~{INPUT}~ Enter'] = '~{INPUT}~ Intra',
}

View File

@@ -0,0 +1,57 @@
function GetVehicleClassHeatupMultiplier(vehicle)
local class = GetVehicleClass(vehicle)
return Config.heatUp.classes[class] or 1.0
end
function GetVehicleClassCooldownMultiplier(vehicle)
local class = GetVehicleClass(vehicle)
return Config.cooldown.classes[class] or 1.0
end
function GetVehicleUpgradeHeatupMultiplier(vehicle)
local brakeUpgrade = GetVehicleMod(vehicle, 12)
return Config.heatUp.brakeUpgrade[brakeUpgrade] or 1.0
end
function GetVehicleUpgradeCooldownMultiplier(vehicle)
local brakeUpgrade = GetVehicleMod(vehicle, 12)
return Config.cooldown.brakeUpgrade[brakeUpgrade] or 1.0
end
--This function is responsible for drawing all the 3d texts
function Draw3DText(coords, textInput, scaleX)
scaleX = scaleX * (Config.textScale or 1.0)
local px, py, pz = table.unpack(GetGameplayCamCoords())
local dist = GetDistanceBetweenCoords(px, py, pz, coords, true)
local scale = (1 / dist) * 20
local fov = (1 / GetGameplayCamFov()) * 100
scale = scale * fov
SetTextScale(scaleX * scale, scaleX * scale)
SetTextFont(Config.textFont or 4)
SetTextProportional(1)
SetTextDropshadow(1, 1, 1, 1, 255)
SetTextEdge(2, 0, 0, 0, 150)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(textInput)
SetDrawOrigin(coords, 0)
DrawText(0.0, 0.0)
ClearDrawOrigin()
end
function KeybindTip(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, 200)
end
-- This function is responsible for all the tooltips displayed on top right of the screen, you could
-- replace it with a custom notification etc.
function Notify(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, -1)
end

View File

@@ -0,0 +1,85 @@
Config = {}
Config.debug = false
-- Multiplier | How fast the brakes should heat up and overheat
Config.heatIntensity = 1.0
-- Multiplier | How fast the brakes should cool down
Config.cooldownSpeed = 1.0
-- Multiplier | Amount of the brake loss when brakes are hot
Config.brakeFadeStrength = 1.0
Config.visual = {
-- (This is an additional glow, not the primary brake coloring/heat effect)
-- Makes the visual effect look quite a bit nicer
-- But is quite resource intensive. Adds about 0.06ms when the brakes are glowing
glow = {
enabled = true,
strength = 1.0,
},
-- Adds sparks when braking with hot brakes.
-- Not very resource intensive
sparks = {
enabled = true,
size = 0.6,
},
}
-- Multipliers for the brake heat up speed
Config.heatUp = {
classes = {
[CLASS_COMPACT] = 0.9,
[CLASS_SUV] = 1.1,
[CLASS_COUPES] = 1.0,
[CLASS_MUSCLE] = 1.0,
[CLASS_SPORTS_CLASSICS] = 0.9,
[CLASS_SPORTS] = 0.85,
[CLASS_SUPER] = 0.8,
[CLASS_BIKE] = 0.5,
[CLASS_OFFROAD] = 0.9,
[CLASS_INDUSTRIAL] = 0.7,
[CLASS_UTILITY] = 0.7,
[CLASS_VANS] = 1.0,
[CLASS_SERVICE] = 1.0,
[CLASS_EMERGENCY] = 0.7,
[CLASS_MILITARY] = 0.7,
[CLASS_COMMERCIAL] = 1.0,
},
brakeUpgrade = {
[-1] = 1.0, -- Stock brakes
[0] = 0.8, -- Brake upgrade level 1
[1] = 0.65, -- Brake upgrade level 2
[2] = 0.6, -- Brake upgrade level 3
},
}
-- Multipliers for the brake cooldown speed
Config.cooldown = {
classes = {
[CLASS_COMPACT] = 1.0,
[CLASS_SUV] = 1.0,
[CLASS_COUPES] = 1.0,
[CLASS_MUSCLE] = 1.1,
[CLASS_SPORTS_CLASSICS] = 1.1,
[CLASS_SPORTS] = 1.15,
[CLASS_SUPER] = 1.25,
[CLASS_BIKE] = 1.5,
[CLASS_OFFROAD] = 1.0,
[CLASS_INDUSTRIAL] = 1.0,
[CLASS_UTILITY] = 1.0,
[CLASS_VANS] = 1.0,
[CLASS_SERVICE] = 1.0,
[CLASS_EMERGENCY] = 1.15,
[CLASS_MILITARY] = 1.15,
[CLASS_COMMERCIAL] = 1.0,
},
brakeUpgrade = {
[-1] = 1.0, -- Stock brakes
[0] = 1.1, -- Brake upgrade level 1
[1] = 1.25, -- Brake upgrade level 2
[2] = 1.5, -- Brake upgrade level 3
},
}

View File

@@ -0,0 +1,23 @@
CLASS_COMPACT = 0
CLASS_SEDAN = 1
CLASS_SUV = 2
CLASS_COUPES = 3
CLASS_MUSCLE = 4
CLASS_SPORTS_CLASSICS = 5
CLASS_SPORTS = 6
CLASS_SUPER = 7
CLASS_BIKE = 8
CLASS_OFFROAD = 9
CLASS_INDUSTRIAL = 10
CLASS_UTILITY = 11
CLASS_VANS = 12
CLASS_CYCLES = 13
CLASS_BOATS = 14
CLASS_HELICOPTER = 15
CLASS_PLANE = 16
CLASS_SERVICE = 17
CLASS_EMERGENCY = 18
CLASS_MILITARY = 19
CLASS_COMMERCIAL = 20
CLASS_TRAIN = 21
CLASS_OPEN_WHEEL = 22

View File

@@ -0,0 +1,31 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Brake overheating by KuzQuality'
version '1.0.5'
client_scripts {
'constants.lua',
'config.lua',
'client/editable/editable.lua',
'client/cache.lua',
'client/functions.lua',
'client/client.lua',
'client/visual.lua',
}
server_scripts {
'constants.lua',
'config.lua',
'server/server.lua',
}
escrow_ignore {
'config.lua',
'constants.lua',
'client/editable/*.lua',
}
dependency '/assetpacks'

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1 @@
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES ('kq_angle_grinder', 'Angle grinder', 3, 0, 1);

View File

@@ -0,0 +1 @@
["kq_angle_grinder"] = {["name"] = "kq_angle_grinder", ["label"] = "Angle Grinder", ["weight"] = 1000, ["type"] = "item", ["image"] = "kq_angle_grinder.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Used to cut metals"},

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,130 @@
-- Gang and police check variables
local heistAllowed = true
local gangCheckDone = false
-- Check if the player meets requirements to participate in the heist
function CheckHeistRequirements()
if Config.requireGang then
if not IsInGang() then
ShowTooltip(L('~r~You must be in a gang to participate in this heist'))
return false
end
end
return true
end
function AfterTruckCreated(vehicle)
end
function AfterTrailerCreated(vehicle)
end
function AfterTrailerVehicleCreated(vehicle)
end
function AfterDriverCreated(ped)
end
function AfterPassengerCreated(ped)
end
function AfterSupportVehicleCreated(vehicle)
end
function AfterSupportPedCreated(ped)
end
function OnStartOpeningTrailer()
if not CheckHeistRequirements() then
return false
end
end
function OnTrailerOpened()
end
function OnVehicleDetach(vehicle)
end
function DrawCustomMarker(dropCoords)
DrawMarker(36, dropCoords.x, dropCoords.y, dropCoords.z + 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0, 3.0, 210, 232, 7, 50, 0, 1, 0, 0)
end
RegisterNetEvent('kq_carheist:dropOffCompleted')
AddEventHandler('kq_carheist:dropOffCompleted', function(reward, losses, vehName)
if losses > 0 then
Alert(L('{vehicle} dropped off'):gsub('{vehicle}', vehName), (L('You made ~g~${reward}\n~r~${losses} deducted due to vehicle damage')):gsub('{reward}', reward):gsub('{losses}', losses), 5000)
else
Alert(L('{vehicle} dropped off'):gsub('{vehicle}', vehName), (L('You made ~g~${reward}')):gsub('{reward}', reward), 5000)
end
PlaySoundFrontend(-1, 'PROPERTY_PURCHASE', 'HUD_AWARDS', false)
end)
function SendAnnouncementMessage(message, subtitle, coords)
BeginTextCommandThefeedPost("STRING")
AddTextComponentSubstringPlayerName(message)
-- Set the notification icon, title and subtitle.
local title = L('Martin')
local iconType = 0
local flash = false -- Flash doesn't seem to work no matter what.
EndTextCommandThefeedPostMessagetext("CHAR_MARTIN", "CHAR_MARTIN", flash, iconType, title, subtitle)
-- Draw the notification
local showInBrief = true
local blink = false -- blink doesn't work when using icon notifications.
EndTextCommandThefeedPostTicker(blink, showInBrief)
local blipConf = Config.announcementBlip.primary
CreateTemporaryBlip(coords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Car transport'), blipConf.shortRange, true)
blipConf = Config.announcementBlip.secondary
CreateTemporaryBlip(coords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Car transport'), blipConf.shortRange)
end
-- This function is responsible for creating the text shown on the bottom of the screen
function DrawMissionText(text, time)
SetTextEntry_2("STRING")
AddTextComponentString(text)
DrawSubtitleTimed(time or 30000, 1)
end
-- This function is responsible for all the tooltips displayed on top right of the screen, you could
-- replace it with a custom notification etc.
function ShowTooltip(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, -1)
end
-- This function is responsible for drawing all the 3d texts ('Press [E] to prepare for an engine swap' e.g)
function Draw3DText(x, y, z, textInput, fontId, scaleX, scaleY)
local px, py, pz = table.unpack(GetGameplayCamCoords())
local dist = GetDistanceBetweenCoords(px, py, pz, x, y, z, true)
local scale = (1 / dist) * 20
local fov = (1 / GetGameplayCamFov()) * 100
local scale = scale * fov
SetTextScale(scaleX * scale, scaleY * scale)
SetTextFont(fontId)
SetTextProportional(1)
SetTextDropshadow(1, 1, 1, 1, 255)
SetTextEdge(2, 0, 0, 0, 150)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(textInput)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
ClearDrawOrigin()
end

View File

@@ -0,0 +1,39 @@
if Config.esxSettings.enabled then
ESX = nil
if Config.esxSettings.useNewESXExport then
ESX = exports['es_extended']:getSharedObject()
else
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj)
ESX = obj
end)
Citizen.Wait(0)
end
end)
end
Citizen.CreateThread(function()
while ESX == nil or ESX.GetPlayerData().job == nil do
Citizen.Wait(10)
end
ESX.PlayerData = ESX.GetPlayerData()
TriggerServerEvent('kq_carheist:playerLoaded')
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
ESX.PlayerData.job = job
ClearPoliceBlips()
end)
function IsPolice()
if not ESX.PlayerData.job then
return false
end
return Contains(Config.policeJobNames, ESX.PlayerData.job.name)
end
end

View File

@@ -0,0 +1,135 @@
----------------------
-- BLIPS
----------------------
local policeBlips = {}
RegisterNetEvent('kq_carheist:refreshPoliceAlarm')
AddEventHandler('kq_carheist:refreshPoliceAlarm', function(trailerCoords, vehiclesCoords)
ClearPoliceBlips()
if trailerCoords then
RefreshPoliceTrailerAlarm(trailerCoords)
end
RefreshPoliceVehiclesAlarm(vehiclesCoords, trailerCoords)
end)
function RefreshPoliceTrailerAlarm(trailerCoords)
if trailerBlip ~= nil then
RemoveBlip(trailerBlip)
end
local blipConf = Config.policeBlip.truck.primary
local primBlip = CreatePoliceBlip(trailerCoords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Car transport robbery'), blipConf.shortRange)
SetBlipDisplay(primBlip, 8)
table.insert(policeBlips, primBlip)
blipConf = Config.policeBlip.truck.secondary
local secBlip = CreatePoliceBlip(trailerCoords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Car transport robbery'), blipConf.shortRange)
table.insert(policeBlips, secBlip)
end
function RefreshPoliceVehiclesAlarm(vehiclesCoords, trailerCoords)
for k, veh in pairs(vehiclesCoords) do
if not trailerCoords or GetDistanceBetweenCoords(trailerCoords, veh.coords, false) > 25.0 then
local blipConf = Config.policeBlip.vehicles.primary
local distance = GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId()), veh.coords, true)
local _, z = GetGroundZFor_3dCoord(veh.coords.x, veh.coords.y, 900.0, true)
if z == 0.0 then
z = GetHeightmapTopZForPosition(veh.coords.x, veh.coords.y)
end
z = z - 6.0
if Config.policeBlip.makeTunnelsLowerSignal and distance > 10.0 and (IsInsideATunnel(veh.coords) or (Config.policeBlip.unknownTunnelChecking and z > veh.coords.z)) then
math.randomseed(math.floor((veh.coords.x / 10) + (veh.coords.y / 10)))
local newCoords = vector3(veh.coords.x + math.random(-130, 130), veh.coords.y + math.random(-130, 130), veh.coords.z)
veh.coords = newCoords
math.randomseed(GetGameTimer())
local tunnelBlip = CreateTunnelPoliceBlip(veh.coords, blipConf.color, blipConf.alpha)
table.insert(policeBlips, tunnelBlip)
else
local primBlip = CreatePoliceBlip(veh.coords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Stolen vehicle: ') .. veh.name, blipConf.shortRange)
SetBlipDisplay(primBlip, 8)
table.insert(policeBlips, primBlip)
end
blipConf = Config.policeBlip.vehicles.secondary
local secBlip = CreatePoliceBlip(veh.coords, blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Stolen vehicle: ') .. veh.name, blipConf.shortRange)
table.insert(policeBlips, secBlip)
end
end
end
function ClearPoliceBlips()
for k, blip in pairs(policeBlips) do
RemoveBlip(blip)
end
policeBlips = {}
end
function RemovePoliceTrailerBlip()
if trailerBlip then
RemoveBlip(trailerBlip)
end
end
function CreatePoliceBlip(coords, sprite, color, alpha, scale, message, shortRange)
local blip = AddBlipForCoord(coords)
SetBlipSprite(blip, sprite)
SetBlipHighDetail(blip, true)
SetBlipColour(blip, color)
SetBlipAlpha(blip, alpha)
SetBlipScale(blip, scale)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString(message)
EndTextCommandSetBlipName(blip)
SetBlipAsShortRange(blip, shortRange)
return blip
end
function CreateTunnelPoliceBlip(coords, color, alpha)
local blip = AddBlipForRadius(coords, 300.0)
SetBlipHighDetail(blip, true)
SetBlipColour(blip, color)
SetBlipAlpha(blip, alpha)
SetBlipAsShortRange(blip, true)
return blip
end
----------------------
-- DISPATCH MESSAGES
----------------------
function EndPoliceAlarm()
if trailerBlip ~= nil then
RemovePoliceTrailerBlip()
SendDispatchMessage(L('Our truck has arrived to its destination. Thank you for your assistance'), L('Truck arrived'))
end
end
function SendDispatchMessage(message, subtitle)
BeginTextCommandThefeedPost("STRING")
AddTextComponentSubstringPlayerName(message)
-- Set the notification icon, title and subtitle.
local title = L('Car Transports Inc.')
local iconType = 0
local flash = false -- Flash doesn't seem to work no matter what.
EndTextCommandThefeedPostMessagetext("CHAR_CARSITE", "CHAR_CARSITE", flash, iconType, title, subtitle)
-- Draw the notification
local showInBrief = true
local blink = false -- blink doesn't work when using icon notifications.
EndTextCommandThefeedPostTicker(blink, showInBrief)
end

View File

@@ -0,0 +1,40 @@
if Config.qbSettings.enabled then
if Config.qbSettings.useNewQBExport then
QBCore = exports['qb-core']:GetCoreObject()
end
job = QBCore.Functions.GetPlayerData().job
gang = QBCore.Functions.GetPlayerData().gang
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
job = QBCore.Functions.GetPlayerData().job
gang = QBCore.Functions.GetPlayerData().gang
TriggerServerEvent('kq_carheist:playerLoaded')
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate')
AddEventHandler('QBCore:Client:OnJobUpdate', function(JobInfo)
job = JobInfo
end)
RegisterNetEvent('QBCore:Client:OnGangUpdate')
AddEventHandler('QBCore:Client:OnGangUpdate', function(GangInfo)
gang = GangInfo
end)
function IsPolice()
if not job then
return false
end
return Contains(Config.policeJobNames, job.name)
end
function IsInGang()
if not gang then
return false
end
return gang.name ~= nil and gang.name ~= 'none' and gang.name ~= ''
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,687 @@
Config = {}
-- Enables debug statements which will print in consoles
-- Also enabled a command /cheist which will forcefully spawn a new heist even if one is already happening
-- Do not enable this unless asked to by a KuzQuality staff member or you know what you're doing
Config.debug = false
-- Experimental method of syncing the trucks between players
Config.experimentalSync = false
--------------------------------------------------------
--------------------------------------------------------
--- MAKE SURE THAT THE CORRECT FRAMEWORK IS ENABLED ! --
--------------------------------------------------------
--------------------------------------------------------
--- SETTINGS FOR ESX
Config.esxSettings = {
enabled = false,
-- Whether or not to use the new ESX export method
useNewESXExport = true,
-- Account on which players will receive their money after successfully dropping off their vehicle
moneyAccount = 'black_money',
}
--- SETTINGS FOR QBCORE
Config.qbSettings = {
enabled = true,
-- If you're using an old QBCore version set this to 'false' and uncomment the old export in fxmanifest.lua
useNewQBExport = true,
-- Account on which players will receive their money after successfully dropping off their vehicle
-- Using 'crypto' for dirty money feel; change to 'cash' or 'bank' as needed
moneyAccount = 'cash'
}
-- Minimum police officers that have to be online to allow spawning of the heist truck
Config.minimumOfficers = 3
-- Whether the player must be in a gang to interact with the heist
Config.requireGang = true
-- How often the truck should be spawned (In minutes)
-- If any players are still near the old truck new one won't be spawned
-- Set to 45 minutes for RP pacing - prevents heist spam
Config.heistSpawnTime = 45
-- Whether or not to announce the truck spawning to all players (Besides police officers)
Config.announceTruckDepartureToPlayers = true
-- Announcement blip
Config.announcementBlip = {
-- How long the blip will stay on the map
duration = 15000,
primary = {
sprite = 161,
color = 47,
scale = 2.0,
alpha = 150,
shortRange = true,
},
secondary = {
sprite = 477,
color = 47,
scale = 1.3,
alpha = 255,
shortRange = true,
},
}
-- Whether or not to use audible vehicle alarms
Config.useVehicleAlarm = true
-- Bike jump config
Config.bikeJump = {
enabled = true,
keybind = 'X'
}
-- Whether or not to require a item to open the trailer
Config.requireTool = true
-- item names that will allow players to open the ramp of the trailer
Config.cuttingTools = {
'kq_angle_grinder'
}
-- Amount of key presses required to open the latch/ramp (Set it higher to make it take longer)
Config.latchCuttingDuration = 15
-- Keys used for the angle grinder / cutting the latches
Config.grinderKeys = { 'W', 'A', 'S', 'D', 'G' }
Config.tracker = {
-- How long it will take to search one spot on the vehicle (in ms)
searchDuration = 15000,
-- How many times the player has to press the keys to unscrew the tracker
removalLength = 50,
-- Time that players will need to wait when they misclick "drop the screwdriver" (in ms)
removalMessedUpDuration = 6000,
-- Keys used to unscrew the tracker
removalKeybinds = {
'A',
'W',
'D',
'S'
},
-- For how long the GPS location is going to be visible for police after tracker gets removed (in ms)
stayOnMapAfterRemovalTime = 90000,
}
-- Name of the job(s) which will receive the alerts
Config.policeJobNames = {
'police'
}
Config.policeBlip = {
-- How often the trackers locations should be updated (Don't recommend putting it too low) (in ms)
refreshTime = 5000,
-- Whether or not to allow tunnels and underground areas to lower the accuracy of the tracker
makeTunnelsLowerSignal = true,
-- Check which works better for detection of tunnels but makes all trackers which are far away
-- from the officer display as if the tracker is in a tunnel (Still recommended)
unknownTunnelChecking = true,
truck = {
primary = {
sprite = 161,
color = 47,
scale = 2.0,
alpha = 150,
shortRange = false,
},
secondary = {
sprite = 477,
color = 47,
scale = 1.3,
alpha = 255,
shortRange = false,
}
},
vehicles = {
primary = {
sprite = 161,
color = 49,
scale = 1.0,
alpha = 150,
shortRange = false,
},
secondary = {
sprite = 595,
color = 49,
scale = 1.0,
alpha = 255,
shortRange = false,
}
}
}
-- ADVANCED! If you don't know what this does. Do not change it.
Config.truckDriveStyle = 1074528293
-- Speed the truck will drive at (I don't recommend putting it above 30.0)
Config.truckDriveSpeed = 20.0
-- Color of the heist truck
Config.truckColor = { r = 255, g = 60, b = 10 }
-- All possible routes that the truck can spawn on and take
-- (Be careful when adding new ones. Make sure that the NPC knows how to drive the route (test it))
Config.startLocations = {
{
truck = { x = 1541.56, y = 854.07, z = 77.5, h = 329.0 },
support = { x = 1524.74, y = 822.16, z = 77.5, h = 328.0 },
finish = { x = 138.46, y = 6414.1, z = 26.13, h = 261.80 },
},
{
truck = { x = -2875.27, y = 2188.37, z = 35.23, h = 129.0 },
support = { x = -2841.30, y = 2207.92, z = 31.11, h = 121.19 },
finish = { x = 2506.23, y = -280.09, z = 93.05, h = 91.77 },
},
{
truck = { x = -1947.37, y = -337.79, z = 46.23, h = 280.77 },
support = { x = -1980.10, y = -311.63, z = 43.65, h = 231.09 },
finish = { x = -680.03, y = 5761.55, z = 16.88, h = 304.37 },
},
{
truck = { x = 1156.20, y = -1695.16, z = 35.65, h = 164.31 },
support = { x = 1165.83, y = -1669.85, z = 36.45, h = 150.35 },
finish = { x = 138.46, y = 6414.1, z = 26.13, h = 261.80 },
},
{
truck = { x = 2666.48, y = 3454.13, z = 55.73, h = 247.0 },
support = { x = 2636.36, y = 3462.57, z = 55.37, h = 244.77 },
finish = { x = 1379.78, y = -2068.52, z = 51.99, h = 156.80 },
},
}
-- Whether or not to reduce the drop off reward based on how damaged the vehicle is
Config.reduceRewardByVehicleDamage = true
-- How much percentage to remove off the vehicle price based on damage (0% nothing, 100% cars which have 0 health will pay $0)
-- Set to 80% - forces careful driving for RP; damaged cars are worth much less
Config.reduceByDamagePercentage = 80
Config.dropOff = {
-- Minimum amount of available drop off locations per heist
minLocations = 2,
-- Maximum amount of available drop off locations per heist
maxLocations = 3,
-- Whether or not to (almost) instantly delete the vehicle when dropping it off
instantlyDeleteVehicle = false,
blips = {
primary = {
sprite = 161,
color = 46,
scale = 1.0,
alpha = 150,
shortRange = false,
},
secondary = {
sprite = 524,
color = 46,
scale = 1.0,
alpha = 255,
shortRange = false,
}
},
-- All available drop off locations
locations = {
{ x = 1274.95, y = -3239.77, z = 5.88 },
{ x = -302.86, y = -2723.41, z = 6.01 },
{ x = -371.68, y = -2273.67, z = 7.60 },
{ x = 452.45, y = -2755.19, z = 6.05 },
{ x = -450.44, y = -2442.52, z = 6.00 },
{ x = 489.70, y = -2227.92, z = 5.91 },
{ x = -161.13, y = 928.02, z = 235.65 },
{ x = 2469.17, y = 1589.04, z = 32.72 },
{ x = 363.70, y = 3411.08, z = 36.40 },
{ x = 3803.85, y = 4451.05, z = 4.25 },
{ x = 2150.34, y = 4797.62, z = 41.13 },
{ x = 1905.25, y = 4924.22, z = 48.87 },
{ x = -197.12, y = 6536.59, z = 11.09 },
{ x = -1585.75, y = 5157.74, z = 19.57 },
{ x = 143.53, y = -2445.9, z = 5.99 },
{ x = -38.46, y = -2547.16, z = 6.00 },
{ x = -224.98, y = -2657.44, z = 6.00 },
{ x = -566.59, y = -2341.45, z = 13.83 },
{ x = -853.87, y = -1257.78, z = 4.99 },
{ x = -81.51, y = 361.99, z = 112.46 },
{ x = -1558.67, y = -247,35, z = 48.28 },
},
}
-- Color of the support vehicle
Config.supportColor = { r = 0, g = 0, b = 0 }
-- Possible vehicle models for the support vehicle
Config.supportVehicles = {
'baller2',
'kuruma',
'buffalo2',
'dubsta2',
'stanier',
'tailgater',
}
-- Ped models that the support can have
Config.supportPeds = {
's_m_m_chemsec_01'
}
-- How much health all the npcs will have (normal npc's have 100)
-- Increased for RP difficulty - guards are trained professionals
Config.npcHealth = 250
-- Whether or not all the npcs suffer from critical hits (aka headshots)
-- Enabled for realism - headshots should matter in RP
Config.npcSuffersCriticalHits = true
-- Integer between 0 and 100
-- Below 20 they barely hit, above 80 incredible aim
-- Set to 55 for challenging but fair RP encounters
Config.npcShootingAccuracy = 55
-- Chance of NPC's having a weapon (100% - armed transport convoy)
Config.weaponChance = 100
Config.weapons = {
'weapon_minismg',
'weapon_snspistol',
'weapon_combatpistol'
}
------------------------------------------------------------------------
-- chance = the chance of the event spawning
-- trucks = list of all truck models that can be used
-- npcs = list of all npc models that can be used (driver and passenger)
-- passengerChance = the chance of the truck having a passenger
-- bulletproofTiresChance = the chance of all heist vehicles having bullet proof tires
-- vehicleSlotChance = the chance of a vehicle spawning in a trailer slot (there always is at least 1 vehicle)
-- supportChance = the chance of the support vehicle spawning
-- minimumVehicles = the minimum amount of the vehicles on the trailer (max 3)
-- vehicles = {
-- name = Vehicle name
-- model = Vehicle model
-- price = The max amount of money the players will get for dropping off the vehicle
-- }
---------------------------------------------------------------------------
--- Chances of all events must add up to 100 !
Config.events = {
{
chance = 20,
trucks = {
'phantom3'
},
npcs = {
's_m_m_chemsec_01'
},
passengerChance = 100,
bulletproofTiresChance = 100,
vehicleSlotChance = 70,
supportChance = 100,
minimumVehicles = 1,
vehicles = {
{
name = 'Adder',
model = 'adder',
price = 40000,
},
{
name = 'Entity XF',
model = 'entityxf',
price = 35000,
},
{
name = 'Furia',
model = 'furia',
price = 45000,
},
{
name = 'Nero Custom',
model = 'nero2',
price = 52000,
},
{
name = 'Nero',
model = 'nero',
price = 44000,
},
{
name = 'Cyclone',
model = 'cyclone',
price = 45000,
},
{
name = 'T20',
model = 't20',
price = 40000,
},
{
name = 'Vacca',
model = 'vacca',
price = 29000,
},
{
name = 'Bullet',
model = 'bullet',
price = 28000,
},
{
name = 'Itali GTB',
model = 'italigtb',
price = 33000,
},
{
name = 'Itali GTB Custom',
model = 'italigtb2',
price = 38000,
},
{
name = 'Visione',
model = 'visione',
price = 49000,
},
{
name = 'SC1',
model = 'SC1',
price = 40000,
},
{
name = 'Taipan',
model = 'taipan',
price = 47000,
},
{
name = 'Thrax',
model = 'thrax',
price = 55000,
},
{
name = 'Emerus',
model = 'emerus',
price = 51000,
},
{
name = 'Entity XXR',
model = 'entity2',
price = 54000,
},
{
name = 'Reaper',
model = 'reaper',
price = 41000,
},
{
name = 'Voltic',
model = 'voltic',
price = 30000,
},
{
name = '811',
model = 'pfister811',
price = 39000,
},
{
name = 'Lynx',
model = 'lynx',
price = 32000,
},
{
name = 'Autarch',
model = 'autarch',
price = 44000,
},
{
name = 'XA-21',
model = 'xa21',
price = 40000,
},
}
},
{
chance = 35,
trucks = {
'phantom3',
'phantom',
'hauler',
'packer',
},
npcs = {
's_m_m_chemsec_01'
},
passengerChance = 80,
bulletproofTiresChance = 40,
vehicleSlotChance = 70,
supportChance = 40,
minimumVehicles = 2,
vehicles = {
{
name = 'Sultan RS',
model = 'sultanrs',
price = 25000,
},
{
name = 'Schlagen',
model = 'schlagen',
price = 30000,
},
{
name = 'Jester Classic',
model = 'jester3',
price = 28000,
},
{
name = 'Comet',
model = 'comet2',
price = 22000,
},
{
name = 'Comet Retro',
model = 'comet3',
price = 27000,
},
{
name = 'Verlierer',
model = 'verlierer2',
price = 30000,
},
{
name = 'Omnis',
model = 'omnis',
price = 33000,
},
{
name = 'Kuruma',
model = 'kuruma',
price = 24000,
},
{
name = 'Space Monkey Blista',
model = 'blista3',
price = 25000,
},
{
name = 'Coquette',
model = 'coquette',
price = 25000,
},
{
name = 'Banshee',
model = 'banshee',
price = 26000,
},
{
name = '9F',
model = 'ninef',
price = 26000,
},
{
name = 'Massacro',
model = 'massacro',
price = 26000,
},
{
name = 'Massacro Race car',
model = 'massacro2',
price = 33000,
},
{
name = 'Dominator GTX',
model = 'dominator3',
price = 29000,
},
{
name = 'Brioso R/A',
model = 'brioso',
price = 22000,
},
{
name = 'F620',
model = 'f620',
price = 23000,
},
{
name = 'Elegy Classic',
model = 'elegy',
price = 30000,
},
{
name = 'Ruston',
model = 'ruston',
price = 26000,
},
{
name = 'Flash GT',
model = 'flashgt',
price = 27000,
},
{
name = 'Elegy RH8',
model = 'elegy2',
price = 32000,
},
}
},
{
chance = 25,
trucks = {
'phantom3'
},
npcs = {
's_m_m_chemsec_01'
},
passengerChance = 100,
bulletproofTiresChance = 100,
vehicleSlotChance = 40,
supportChance = 100,
minimumVehicles = 1,
vehicles = {
{
name = 'Turismo Classic',
model = 'turismo2',
price = 60000,
},
{
name = 'JB700W',
model = 'jb7002',
price = 53000,
},
{
name = 'Torero',
model = 'torero',
price = 54000,
},
{
name = 'Cheburek',
model = 'cheburek',
price = 15000,
},
{
name = 'Dynasty',
model = 'dynasty',
price = 42000,
},
{
name = 'Monroe',
model = 'monroe',
price = 40000,
},
{
name = 'Swinger',
model = 'swinger',
price = 44000,
},
{
name = 'Cheetah Classic',
model = 'cheetah2',
price = 62000,
},
{
name = 'Infernus Classic',
model = 'infernus2',
price = 61000,
},
{
name = 'Rapid GT Classic',
model = 'rapidgt3',
price = 26000,
},
{
name = 'Savestra',
model = 'savestra',
price = 27000,
},
}
},
{
chance = 20,
trucks = {
'phantom3'
},
npcs = {
's_m_m_chemsec_01'
},
passengerChance = 100,
bulletproofTiresChance = 100,
vehicleSlotChance = 45,
supportChance = 80,
minimumVehicles = 1,
vehicles = {
{
name = 'Comet Safari',
model = 'comet4',
price = 45000,
},
{
name = 'Drag Tornado',
model = 'tornado6',
price = 47000,
},
{
name = 'Apocalypse Issi',
model = 'issi4',
price = 37000,
},
{
name = 'Drift Yosemite',
model = 'yosemite2',
price = 51000,
},
{
name = 'Lowrider Primo',
model = 'primo2',
price = 42000,
},
{
name = 'JB700',
model = 'jb700',
price = 58000,
},
{
name = 'Raptor',
model = 'raptor',
price = 35000,
},
}
},
}

View File

@@ -0,0 +1,60 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Car Heist by KuzQuality'
version '1.0.14'
-- UNCOMMENT IF YOU'RE USING OLD QB CORE EXPORT
--shared_script '@qb-core/import.lua'
--
-- Server
--
server_scripts {
'locale/locale.lua',
'config.lua',
'shared/settings.lua',
'server/editable/esx.lua',
'server/editable/qb.lua',
'server/server.lua',
'server/functions.lua',
'server/editable/editable.lua',
}
--
-- Client
--
client_scripts {
'locale/locale.lua',
'config.lua',
'shared/settings.lua',
'client/editable/esx.lua',
'client/editable/qb.lua',
'client/functions.lua',
'client/client.lua',
'client/bikeJump.lua',
'client/editable/editable.lua',
'client/editable/policeAlert.lua',
}
escrow_ignore {
'config.lua',
'locale/locale.lua',
'client/editable/editable.lua',
'client/editable/policeAlert.lua',
'client/editable/qb.lua',
'client/editable/esx.lua',
'client/functions.lua',
'server/editable/editable.lua',
'server/editable/esx.lua',
'server/editable/qb.lua',
'server/server.lua',
}
dependency '/assetpacks'

View File

@@ -0,0 +1,41 @@
-- To edit the messages edit the ones on the right side, not the ones inside the square brackets.
-- ~r~ e.g. are colors. ~r~ being red, ~b~ being blue, ~y~ yellow etc.
Locale = {
['Car transport truck is currently departing.\nI\'ll pay top dollar if you can get them'] = 'Un transport de masini tocmai a plecat.\nPlatesc bine daca reusesti sa le aduci',
['Martin'] = 'Martin',
['Car collector'] = 'Colectionar de masini',
['Car transport'] = 'Transport de masini',
['Press ~w~[{keybinds}~w~] to unscrew'] = 'Apasa ~w~[{keybinds}~w~] pentru a desuruba',
['~r~You dropped the screwdriver'] = '~r~Ai scapat surubelnita',
['~w~Press [~r~E~w~] to force the ramp down'] = '~w~Apasa [~r~E~w~] pentru a forta rampa',
['~w~Press [~r~E~w~] to cancel'] = '~w~Apasa [~r~E~w~] pentru a anula',
['Cutting the latches...'] = 'Se taie incuietorile...',
['~w~Press [~r~{keybinds}~w~] to continue cutting'] = '~w~Apasa [~r~{keybinds}~w~] pentru a continua taierea',
['~w~Press [~r~E~w~] to climb up'] = '~w~Apasa [~r~E~w~] pentru a urca',
['~w~Press [~r~{keybind}~w~] to attempt a jump'] = '~w~Apasa [~r~{keybind}~w~] pentru a incerca o saritura',
['~y~! DANGEROUS !'] = '~y~! PERICULOS !',
['Car transport robbery'] = 'Jaf transport de masini',
['~r~You don\'t have anything that could be used to open this'] = '~r~Nu ai nimic cu care sa deschizi asta',
['Our car transport is under attack! Coordinates have been shared!'] = 'Transportul nostru de masini este atacat! Coordonatele au fost distribuite!',
['Car Transports Inc.'] = 'Car Transports Inc.',
['Robbery in progress'] = 'Jaf in desfasurare',
['Truck arrived'] = 'Camionul a ajuns',
['Our truck has arrived to its destination. Thank you for your assistance'] = 'Camionul nostru a ajuns la destinatie. Va multumim pentru asistenta',
['You need to remove the vehicle ~r~tracker ~w~before you sell it'] = 'Trebuie sa scoti ~r~trackerul ~w~de pe vehicul inainte sa il vinzi',
['Stolen vehicle: '] = 'Vehicul furat: ',
['~w~Press [~r~E~w~] to check for a tracker'] = '~w~Apasa [~r~E~w~] pentru a cauta un tracker',
['~w~Searching for a tracking device'] = '~w~Se cauta un dispozitiv de urmarire',
['~g~Tracking device found!'] = '~g~Dispozitiv de urmarire gasit!',
['Deliver the ~g~{vehicle}~w~ to one of the drop off points'] = 'Livreaza ~g~{vehicle}~w~ la unul dintre punctele de predare',
['Stolen vehicle drop off point'] = 'Punct de predare vehicul furat',
['Vehicle dropped off'] = 'Vehicul predat',
['You made ~g~${reward}'] = 'Ai castigat ~g~${reward}',
['You made ~g~${reward}\n~r~${losses} deducted due to vehicle damage'] = 'Ai castigat ~g~${reward}\n~r~${losses} deduse din cauza daunelor vehiculului',
['~w~Press [~r~E~w~] to drop off the vehicle'] = '~w~Apasa [~r~E~w~] pentru a preda vehiculul',
-- Gang & police requirement messages
['~r~You must be in a gang to participate in this heist'] = '~r~Trebuie sa faci parte dintr-un gang pentru a participa la acest jaf',
['~r~Not enough police officers online (minimum: {count})'] = '~r~Nu sunt suficienti politisti online (minim: {count})',
}

View File

@@ -0,0 +1,38 @@
function OnHeistCreated()
end
function OnVehicleStartDroppingOff(source, vehEntity)
-- Server-side gang check: prevent non-gang members from dropping off stolen vehicles
if Config.requireGang and not IsInGang(source) then
TriggerClientEvent('kq_carheist:gangCheckFailed', source)
return false
end
end
function OnVehicleDroppedOff(source, vehicle, reward)
end
function OnTrackerRemoved(source, coords)
end
----------------------
-- TRACKERS
----------------------
RegisterServerEvent('kq_carheist:removeTracker')
AddEventHandler('kq_carheist:removeTracker', function(vehKey, coords)
sellableVehicles[vehKey].tracker = false
sellableVehicles[vehKey].trackerCoords = coords
TriggerClientEvent('kq_carheist:syncSellableVehicles', -1, sellableVehicles)
Citizen.CreateThread(function()
Citizen.Wait(Config.tracker.stayOnMapAfterRemovalTime)
if sellableVehicles[vehKey] then
sellableVehicles[vehKey].trackerCoords = nil
end
end)
OnTrackerRemoved(source, coords)
end)

View File

@@ -0,0 +1,45 @@
if Config.esxSettings.enabled then
ESX = nil
if Config.esxSettings.useNewESXExport then
ESX = exports['es_extended']:getSharedObject()
else
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
end
function HasItem(player, item)
local xPlayer = ESX.GetPlayerFromId(player)
return xPlayer.getInventoryItem(item).count >= 1
end
function IsPolice(player)
local xPlayer = ESX.GetPlayerFromId(player)
if not xPlayer then
return false
end
local job = xPlayer.getJob()
return Contains(Config.policeJobNames, job.name)
end
function GetPoliceCount()
local currentOfficers = 0
for _, playerId in ipairs(GetPlayers()) do
playerId = tonumber(playerId)
if IsPolice(playerId) then
currentOfficers = currentOfficers + 1
end
end
return currentOfficers
end
function AddMoney(player, amount)
local xPlayer = ESX.GetPlayerFromId(player)
if not xPlayer then
return false
end
xPlayer.addAccountMoney(Config.esxSettings.moneyAccount, amount)
end
end

View File

@@ -0,0 +1,57 @@
if Config.qbSettings.enabled then
if Config.qbSettings.useNewQBExport then
QBCore = exports['qb-core']:GetCoreObject()
end
function HasItem(player, item)
local xPlayer = QBCore.Functions.GetPlayer(player)
return xPlayer.Functions.GetItemByName(item)
end
function IsPolice(player)
local xPlayer = QBCore.Functions.GetPlayer(player)
if not xPlayer then
return false
end
local job = xPlayer.PlayerData.job
return Contains(Config.policeJobNames, job.name)
end
function IsInGang(player)
local xPlayer = QBCore.Functions.GetPlayer(player)
if not xPlayer then
return false
end
local gang = xPlayer.PlayerData.gang
if not gang then
return false
end
return gang.name ~= nil and gang.name ~= 'none' and gang.name ~= ''
end
function GetPoliceCount()
local currentOfficers = 0
for _, playerId in ipairs(GetPlayers()) do
playerId = tonumber(playerId)
if IsPolice(playerId) then
currentOfficers = currentOfficers + 1
end
end
return currentOfficers
end
function AddMoney(player, amount)
local xPlayer = QBCore.Functions.GetPlayer(player)
if not xPlayer then
return false
end
xPlayer.Functions.AddMoney(Config.qbSettings.moneyAccount, amount)
end
end

View File

@@ -0,0 +1,252 @@
if Config.esxSettings.enabled and Config.qbSettings.enabled then
print('^1BOTH FRAMEWORKS ENABLED!! MAKE SURE TO ONLY ENABLE ONE FRAMEWORK IN THE CONFIG FILE!')
end
if not Config.esxSettings.enabled and not Config.qbSettings.enabled then
print('^1NO FRAMEWORK ENABLED!! MAKE SURE TO ENABLE ONE FRAMEWORK IN THE CONFIG FILE!')
end
-- Do not remove this!
sellableVehicles = {}
newHeist = {
player = nil,
truck = nil,
trailer = nil,
npc = nil,
passenger = nil,
support = nil,
supportEnabled = nil,
weaponsEnabled = nil,
passengerEnabled = nil,
bulletproofTiresEnabled = nil,
touches = 0,
vehicles = {}
}
heist = {}
function AttemptCreateHeist()
EndHeist()
heist = json.decode(json.encode(newHeist))
heist.hash = math.random(1, 99999)
heist.startLocation = Config.startLocations[math.random(1, #Config.startLocations)]
heist.endLocation = heist.startLocation.finish
local closestPlayer = nil
local closestDistance = 99999.9
for _, playerId in ipairs(GetPlayers()) do
playerId = tonumber(playerId)
local playerCoords = GetEntityCoords(GetPlayerPed(playerId))
local distance = GetDistanceBetweenCoords(playerCoords.x, playerCoords.y, playerCoords.z, heist.startLocation.truck.x, heist.startLocation.truck.y, heist.startLocation.truck.z)
if distance < 120 then
return false
end
if closestDistance > distance then
closestPlayer = playerId
closestDistance = distance
end
end
if not closestPlayer then
return false
end
heist.weaponsEnabled = true
if math.random(0, 100) > Config.weaponChance then
heist.weaponsEnabled = false
end
local odds = 0
local eventKey = nil
local hit = math.random(0, 100)
for k, event in pairs(Config.events) do
if event.chance + odds > hit and not eventKey then
eventKey = k
else
odds = odds + event.chance
end
end
if not eventKey then
eventKey = math.random(1, #Config.events)
end
heist.event = eventKey
local event = Config.events[eventKey]
local empty = 0
for k, slot in pairs(Settings.trailerSlots) do
if math.random(0, 100) <= event.vehicleSlotChance or (empty + event.minimumVehicles == #Settings.trailerSlots) then
local vehicle = event.vehicles[math.random(1, #event.vehicles)]
heist.vehicles[k] = { data = vehicle, vehicle = nil }
else
empty = empty + 1
end
end
heist.passengerEnabled = true
if math.random(0, 100) > event.passengerChance then
heist.passengerEnabled = false
end
heist.bulletproofTiresEnabled = true
if math.random(0, 100) > event.bulletproofTiresChance then
heist.bulletproofTiresEnabled = false
end
heist.supportEnabled = true
if math.random(0, 100) > event.supportChance then
heist.supportEnabled = false
end
heist.player = closestPlayer
Debug('starting heist, initiator: ' .. closestPlayer)
TriggerClientEvent('kq_carheist:createHeist', closestPlayer, heist)
OnHeistCreated()
return true
end
function EndHeist()
DeleteIfExists(heist.truck)
DeleteIfExists(heist.trailer)
DeleteIfExists(heist.npc)
DeleteIfExists(heist.passenger)
if heist.supportEnabled and heist.support then
DeleteIfExists(heist.support.vehicle)
for k, ped in pairs(heist.support.peds) do
DeleteIfExists(ped)
end
end
TriggerClientEvent('kq_carheist:endHeist', -1)
heist = json.decode(json.encode(newHeist))
end
RegisterServerEvent('kq_carheist:heistCreated')
AddEventHandler('kq_carheist:heistCreated', function(syncedHeist)
if source ~= heist.player then
return
end
heist = syncedHeist
TriggerClientEvent('kq_carheist:startDriver', -1)
TriggerClientEvent('kq_carheist:syncHeist', -1, heist)
if Config.announceTruckDepartureToPlayers then
TriggerClientEvent('kq_carheist:announceHeist', -1, vector3(heist.startLocation.truck.x, heist.startLocation.truck.y, heist.startLocation.truck.z))
end
end)
if Config.debug then
RegisterCommand('cheist', function(source, args)
AttemptCreateHeist()
end)
end
Citizen.CreateThread(function()
while true do
local sleep = 20000
if heist.player and heist.truck then
sleep = 4000
local truckCoords = GetEntityCoords(NetworkGetEntityFromNetworkId(heist.truck))
local trailerCoords = GetEntityCoords(NetworkGetEntityFromNetworkId(heist.trailer))
local ended = false
Debug('Truck Owner: ' .. NetworkGetEntityOwner(NetworkGetEntityFromNetworkId(heist.truck)))
Debug(truckCoords)
Debug('Trailer Owner: ' .. NetworkGetEntityOwner(NetworkGetEntityFromNetworkId(heist.trailer)))
Debug(trailerCoords)
if not DoesEntityExist(NetworkGetEntityFromNetworkId(heist.truck)) or not DoesEntityExist(NetworkGetEntityFromNetworkId(heist.trailer)) or not DoesEntityExist(NetworkGetEntityFromNetworkId(heist.npc)) then
Debug('Ending heist')
EndHeist()
ended = true
end
if not ended then
Debug('Remaining distance: ' .. GetDistanceBetweenCoords(truckCoords.x, truckCoords.y, truckCoords.z, heist.endLocation.x, heist.endLocation.y, heist.endLocation.z))
if GetDistanceBetweenCoords(truckCoords.x, truckCoords.y, truckCoords.z, heist.endLocation.x, heist.endLocation.y, heist.endLocation.z) < 18.0 and GetDistanceBetweenCoords(trailerCoords.x, trailerCoords.y, trailerCoords.z, heist.endLocation.x, heist.endLocation.y, heist.endLocation.z) < 25.0 then
Debug('Truck arrived to its destination. Ending heist')
TriggerClientEvent('kq_carheist:truckArrived', -1)
EndHeist()
end
end
end
Citizen.Wait(sleep)
end
end)
Citizen.CreateThread(function()
Citizen.Wait(30000)
while true do
if Config.minimumOfficers > 0 then
local enough = false
while not enough do
local currentOfficers = GetPoliceCount()
if currentOfficers >= Config.minimumOfficers then
enough = true
else
Debug('Couldn\'t start a new heist. Not enough police online')
Citizen.Wait(120000)
end
end
end
if heist.player ~= nil and heist.trailer and DoesEntityExist(NetworkGetEntityFromNetworkId(heist.trailer)) and not Config.ignoreDistances then
Citizen.Wait(20000)
local tooClose = true
while tooClose do
local closestDistance = 99999.9
for _, playerId in ipairs(GetPlayers()) do
playerId = tonumber(playerId)
local playerCoords = GetEntityCoords(GetPlayerPed(playerId))
local trailerCoords = GetEntityCoords(NetworkGetEntityFromNetworkId(heist.trailer))
local distance = GetDistanceBetweenCoords(playerCoords.x, playerCoords.y, playerCoords.z, trailerCoords.x, trailerCoords.y, trailerCoords.z)
Debug('Distance: ' .. distance)
if closestDistance > distance then
closestDistance = distance
end
end
if closestDistance > 100.0 then
tooClose = false
else
Debug('Couldn\'t start a new heist. Someone is too near the old trailer')
Citizen.Wait(60000)
end
end
end
local success = false
while not success do
success = AttemptCreateHeist()
if not success then
Debug('Couldn\'t start a new heist. Someone is too close the spawn location')
Citizen.Wait(60000)
end
end
Citizen.Wait(Config.heistSpawnTime * 60000)
end
end)

View File

@@ -0,0 +1,19 @@
function IsWhitelisted(vehicle)
for index, value in ipairs(Config.whitelist.vehicles) do
if GetHashKey(value) == GetEntityModel(vehicle) then
return true
end
end
return false
end
if Config.toggleCommands then
RegisterCommand('stopsmoke', function(source, args)
smokeActive = false
end)
RegisterCommand('startsmoke', function(source, args)
smokeActive = true
end)
end

View File

@@ -0,0 +1,71 @@
Config = {}
Config.debug = false
----------------------
-- Smoke Settings --
----------------------
-- The threshold of loss of traction at which the smoke will start appearing (6.0 is a good value)
Config.driftThreshold = 6.0
-- Scale multiplier of the smoke, to make all smoke larger increase this value
Config.scaleMultiplier = 1.5
-- Whether or not to use colored smoke, when false cars with custom tire smoke will still produce white smoke
Config.allowColoredSmoke = true
-- Value between 0 and 100 | Defines the density of the smoke
Config.smokeDensity = 90
-- Opacity of the smoke
Config.smokeOpacity = 0.5
----------------------
-- Burnouts --
----------------------
-- Whether or not to enlarge the smoke during a burnout
Config.bigBurnoutSmoke = true
-- Whether or not to keep making the smoke larger as the burnout continues
Config.growBurnoutSmoke = true
-- Maximum size of the burnout
Config.maxBurnoutSmokeMultiplier = 1.6
----------------------
-- Other --
----------------------
-- Whether or not to enable /startsmoke and /stopsmoke commands
Config.toggleCommands = false
-- Whether or not you want smoke to be produced on offroad surfaces like dirt
Config.smokeOffroad = false
-- Surfaces where smoke will always be produced
-- To check the surface you're on you can do /surface with debug mode enabled
Config.roadSurfaces = {
1, 3, 4, 12
}
-- Whether or not only allow certain vehicles to produce the smoke
Config.whitelist = {
useWhitelist = false,
vehicles = {
'silvia',
'brz13',
'zion3',
'tampa2',
'futo',
'yosemite2',
}
}
-- Whether or not to only enable drift smoke for vehicles that have drift tires (KuzQuality.com/(COMING SOON))
Config.onlyWithDriftTires = false

View File

@@ -0,0 +1,34 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Drift Smoke by KuzQuality'
version '1.2.0'
--
-- Server
--
server_scripts {
'config.lua',
'server/server.lua',
}
--
-- Client
--
client_scripts {
'config.lua',
'client/client.lua',
'client/editable.lua',
}
escrow_ignore {
'config.lua',
'client/editable.lua',
}
dependency '/assetpacks'

Binary file not shown.

View File

@@ -0,0 +1,27 @@
# KQ_DYNO INSTALLATION GUIDE
This guide will provide step-by-step instructions on how to install and set up the KQ_DYNO script for FiveM.
## Step 1:
After downloading the script, unzip the folder and place it in the `resources` directory on your FiveM server.
## Step 2:
Open the `config.lua` file in the script folder and make sure that the correct framework is enabled.
## Step 3:
After the config file has been set up, add the script to your `server.cfg` file. Make sure that it's added **after** your framework of choice, so that it loads and starts properly.
## Step 4:
Configure your dyno locations in the `config.lua` file
## Done
Enjoy the script
## Extra info
To restart the script. Use our custom `/kq_dyno_restart` command. Simply restarting or ensuring it will cause you to crash
due to the custom props being unloaded from the memory.
https://kuzquality.com/
https://discord.gg/fZsyam7Rvz

View File

@@ -0,0 +1,9 @@
-- Triggered when player starts a dyno run
function OnDynoStart(dynoKey)
end
-- Triggered when the dyno run is fully finished
function OnDynoFinish(dynoKey)
end

View File

@@ -0,0 +1,448 @@
function GetVehicleStats(veh)
if not Config.dynoFormula then
return GetVehicleStatsVanilla(veh)
end
if Config.dynoFormula == 'highperformance1' then
return GetVehicleStatsAlternative(veh)
end
if Config.dynoFormula == 'highperformance2' then
return GetVehicleStatsAlternative2(veh)
end
if Config.dynoFormula == 'highperformance3' then
return GetVehicleStatsAlternative3(veh)
end
return GetVehicleStatsVanilla(veh)
end
function GetVehicleStatsVanilla(veh)
return UseCache('vehStats' .. veh, function()
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
local drivetrainLoss = 0.1 -- awd
if fDriveBiasFront >= 0.85 then
drivetrainLoss = 0.13 -- fwd
end
if fDriveBiasFront <= 0.15 then
drivetrainLoss = 0.2 -- rwd
end
local wheelPower = GetWheelPower(veh)
if IsVehicleFwd(veh) then
wheelPower = wheelPower * fDriveBiasFront
else
wheelPower = wheelPower * (1 - fDriveBiasFront)
end
local rpm = GetVehicleCurrentRpm(veh)
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
local realRpm = math.floor(rpm * maxRpm)
local torque = math.floor((fInitialDriveForce * fMass) * (realRpm / maxRpm)
+ (wheelPower * 40)
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
)
local hpMultiplier = 0.95
if fInitialDriveMaxFlatVel >= 150 then
hpMultiplier = 1.0
end
if fInitialDriveMaxFlatVel >= 159 then
hpMultiplier = 1.1
torque = math.floor(torque * 1.05)
end
if fInitialDriveMaxFlatVel >= 159.5 then
hpMultiplier = 1.15
torque = math.floor(torque * 1.15)
end
if fInitialDriveMaxFlatVel >= 164.0 then
hpMultiplier = 1.05
torque = math.floor(torque * 1.1)
end
local hp = math.abs(math.floor(DiminishingReturns(
((torque / 1.356) * (rpm * maxRpm) / 5252)
* fDriveInertia
* (math.min(160.0, fInitialDriveMaxFlatVel) / 150)
* wheelPower
* (1 - drivetrainLoss)
* hpMultiplier
* (math.min(2.0, math.max(0.95, fMass / 1400)))
)))
local torqueInUnits = torque
if UsingFtLbs() then
torqueInUnits = torque / 1.356
end
return hp, torqueInUnits, realRpm, rpm
end, 50)
end
function GetVehicleStatsAlternative(veh)
return UseCache('vehStats' .. veh, function()
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
local drivetrainLoss = 0.1 -- awd
if fDriveBiasFront >= 0.85 then
drivetrainLoss = 0.13 -- fwd
end
if fDriveBiasFront <= 0.15 then
drivetrainLoss = 0.2 -- rwd
end
local wheelPower = GetWheelPower(veh)
if IsVehicleFwd(veh) then
wheelPower = wheelPower * fDriveBiasFront
else
wheelPower = wheelPower * (1 - fDriveBiasFront)
end
local rpm = GetVehicleCurrentRpm(veh)
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
local realRpm = math.floor(rpm * maxRpm)
local torque = math.floor((fInitialDriveForce * fMass) * (realRpm / maxRpm)
+ (wheelPower * 40)
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
)
local hpMultiplier = 0.95
if fInitialDriveMaxFlatVel >= 150 then
hpMultiplier = 1.0
end
if fInitialDriveMaxFlatVel >= 159 then
hpMultiplier = 1.1
torque = math.floor(torque * 1.05)
end
if fInitialDriveMaxFlatVel >= 159.5 then
hpMultiplier = 1.15
torque = math.floor(torque * 1.15)
end
if fInitialDriveMaxFlatVel >= 164.0 then
hpMultiplier = 1.05
torque = math.floor(torque * 1.1)
end
local hp = math.abs(math.floor(DiminishingReturns(
((torque / 1.356) * (rpm * maxRpm) / 5252)
* fDriveInertia
* math.min(1.1, wheelPower)
* (1 - drivetrainLoss)
* hpMultiplier
* (math.min(2.0, math.max(0.95, fMass / 1400)))
)))
local torqueInUnits = torque
if UsingFtLbs() then
torqueInUnits = torque / 1.356
end
return hp, torqueInUnits, realRpm, rpm
end, 50)
end
function GetVehicleStatsAlternative2(veh)
return UseCache('vehStats' .. veh, function()
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
local drivetrainLoss = 0.1 -- awd
if fDriveBiasFront >= 0.85 then
drivetrainLoss = 0.13 -- fwd
end
if fDriveBiasFront <= 0.15 then
drivetrainLoss = 0.2 -- rwd
end
local wheelPower = GetWheelPower(veh)
if IsVehicleFwd(veh) then
wheelPower = wheelPower * fDriveBiasFront
else
wheelPower = wheelPower * (1 - fDriveBiasFront)
end
local rpm = GetVehicleCurrentRpm(veh)
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
local realRpm = math.floor(rpm * maxRpm)
local torque = math.floor(((fInitialDriveForce * 0.5) * fMass) * (realRpm / maxRpm)
+ (math.min(3.0, wheelPower))
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
)
local hpMultiplier = 0.95
if fInitialDriveMaxFlatVel >= 150 then
hpMultiplier = 1.0
end
if fInitialDriveMaxFlatVel >= 159 then
hpMultiplier = 1.1
torque = math.floor(torque * 1.05)
end
if fInitialDriveMaxFlatVel >= 159.5 then
hpMultiplier = 1.15
torque = math.floor(torque * 1.15)
end
if fInitialDriveMaxFlatVel >= 164.0 then
hpMultiplier = 1.05
torque = math.floor(torque * 1.1)
end
local hp = math.abs(math.floor(DiminishingReturns(
((torque / 1.356) * (rpm * maxRpm) / 5252)
* fDriveInertia
* (math.min(160.0, fInitialDriveMaxFlatVel) / 250)
* math.min(2.0, wheelPower)
* (1 - drivetrainLoss)
* hpMultiplier
* (math.min(2.0, math.max(0.95, fMass / 1400)))
)))
local torqueInUnits = torque
if UsingFtLbs() then
torqueInUnits = torque / 1.356
end
return hp, torqueInUnits, realRpm, rpm
end, 50)
end
function GetVehicleStatsAlternative3(veh)
return UseCache('vehStats' .. veh, function()
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
local drivetrainLoss = 0.1 -- awd
if fDriveBiasFront >= 0.85 then
drivetrainLoss = 0.13 -- fwd
end
if fDriveBiasFront <= 0.15 then
drivetrainLoss = 0.2 -- rwd
end
local wheelPower = GetWheelPower(veh)
if IsVehicleFwd(veh) then
wheelPower = wheelPower * fDriveBiasFront
else
wheelPower = wheelPower * (1 - fDriveBiasFront)
end
local rpm = GetVehicleCurrentRpm(veh)
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 35) * 8500) * 0.95
local realRpm = math.floor(rpm * maxRpm)
local torque = math.floor(((fInitialDriveForce * 0.4) * fMass) * (realRpm / maxRpm)
+ (math.min(2.0, wheelPower / 2))
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
)
local hpMultiplier = 0.95
if fInitialDriveMaxFlatVel >= 150 then
hpMultiplier = 1.0
end
if fInitialDriveMaxFlatVel >= 159 then
hpMultiplier = 1.1
torque = math.floor(torque * 1.05)
end
if fInitialDriveMaxFlatVel >= 159.5 then
hpMultiplier = 1.15
torque = math.floor(torque * 1.15)
end
if fInitialDriveMaxFlatVel >= 164.0 then
hpMultiplier = 1.05
torque = math.floor(torque * 1.1)
end
local hp = math.abs(math.floor(DiminishingReturns(
((torque / 1.356) * (rpm * maxRpm) / 5252)
* fDriveInertia
* math.min(2.0, wheelPower / 2)
* (1 - drivetrainLoss)
* hpMultiplier
* (math.min(2.0, math.max(0.95, fMass / 1400)))
)))
local torqueInUnits = torque
if UsingFtLbs() then
torqueInUnits = torque / 1.356
end
return hp, torqueInUnits, realRpm, rpm
end, 50)
end
function GetWheelPower(veh)
local power = 0
for i = 0 , GetVehicleNumberOfWheels(veh) - 1 do
power = power + GetVehicleWheelPower(veh, i) * (GetVehicleWheelTireColliderSize(veh, i) * 2 + 0.15)
end
return power
end
function DiminishingReturns(x)
return x * (1 - (math.min(0.3, (x + 100) / 2400) - 0.05))
end
function UsingFtLbs()
return Config.torqueUnits == 'lb-ft' or Config.torqueUnits == 'lbs' or Config.torqueUnits == 'ft-lb'
end
function GetTorqueUnit()
if UsingFtLbs() then
return L('lb-ft')
end
return L('nm')
end
function IsPlayerUnreachable()
local playerPed = PlayerPedId()
return IsPedRagdoll(playerPed) or IsEntityDead(playerPed)
end
function KeybindTip(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, 200)
end
-- This function is responsible for all the tooltips displayed on top right of the screen, you could
-- replace it with a custom notification etc.
function Notify(message)
SetTextComponentFormat("STRING")
AddTextComponentString(message)
EndTextCommandDisplayHelp(0, 0, 0, -1)
end
RegisterNetEvent('kq_dyno:client:notify')
AddEventHandler('kq_dyno:client:notify', function(message)
Notify(message)
end)
function PlayAnim(dict, anim, flag, duration)
Citizen.CreateThread(function()
RequestAnimDict(dict)
local timeout = 0
while not HasAnimDictLoaded(dict) do
Citizen.Wait(50)
timeout = timeout + 1
if timeout > 100 then
return
end
end
TaskPlayAnim(PlayerPedId(), dict, anim, 1.5, 1.0, duration or -1, flag or 1, 0, false, false, false)
RemoveAnimDict(dict)
end)
end
function DrawDynoMarker(dyno)
DrawMarker(43, dyno.coords + vector3(0.0, 0.0, -1.0), 0.0, 0.0, 0.0, 0.0, 0.0, dyno.heading, 2.5, 1.0, 0.5, 40, 110, 250, 30, 0, 0, 0, 0)
end
function CanPerformDynoTests(dynoKey)
return UseCache('CanPerformDynoTests' .. dynoKey, function()
local dyno = Config.dynos[dynoKey]
return (not Config.jobWhitelist.enabled or (not PLAYER_JOB or not dyno.jobs or Contains(dyno.jobs, PLAYER_JOB)))
end, 5000)
end
-- Keybinds display
buttons = nil
keybinds = {}
function AddKeybindDisplay(key, label)
buttons = nil
table.insert(keybinds, {
key = '~' .. key .. '~',
label = label,
})
buttons = RequestScaleformMovie("INSTRUCTIONAL_BUTTONS")
while not HasScaleformMovieLoaded(buttons) do
Wait(0)
end
BeginScaleformMovieMethod(buttons, "CLEAR_ALL")
EndScaleformMovieMethod()
for k, keybind in pairs(keybinds) do
BeginScaleformMovieMethod(buttons, "SET_DATA_SLOT")
ScaleformMovieMethodAddParamInt(k - 1)
ScaleformMovieMethodAddParamPlayerNameString(keybind.key)
PushScaleformMovieMethodParameterString(keybind.label)
EndScaleformMovieMethod()
end
BeginScaleformMovieMethod(buttons, "DRAW_INSTRUCTIONAL_BUTTONS")
EndScaleformMovieMethod()
end
function ClearKeybinds()
buttons = nil
keybinds = {}
end
Citizen.CreateThread(function()
while true do
local sleep = 500
if buttons ~= nil then
sleep = 1
DrawScaleformMovieFullscreen(buttons, 255, 255, 255, 255, 0)
end
Citizen.Wait(sleep)
end
end)

View File

@@ -0,0 +1,31 @@
if Config.esxSettings.enabled then
ESX = nil
if Config.esxSettings.useNewESXExport then
ESX = exports['es_extended']:getSharedObject()
else
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj)
ESX = obj
end)
Citizen.Wait(0)
end
end)
end
Citizen.CreateThread(function()
while ESX == nil or ESX.GetPlayerData().job == nil do
Citizen.Wait(10)
end
ESX.PlayerData = ESX.GetPlayerData()
PLAYER_JOB = ESX.PlayerData.job.name
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
ESX.PlayerData.job = job
PLAYER_JOB = job.name
end)
end

View File

@@ -0,0 +1,18 @@
if Config.qbSettings.enabled then
QBCore = exports['qb-core']:GetCoreObject()
if QBCore.Functions.GetPlayerData() and QBCore.Functions.GetPlayerData().job then
PLAYER_JOB = QBCore.Functions.GetPlayerData().job.name
end
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
PLAYER_JOB = QBCore.Functions.GetPlayerData().job.name
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate')
AddEventHandler('QBCore:Client:OnJobUpdate', function(JobInfo)
PLAYER_JOB = JobInfo.name
end)
end

View File

@@ -0,0 +1,315 @@
Config = {}
Config.debug = false
--- If you're testing the script and editing the values DO NOT simply restart the script. As this script is using custom models (dynos)
--- it will crash if you just restart it. Instead use the `/kq_dyno_restart` command. It will safely restart the script without causing you to crash
--- SETTINGS FOR ESX
Config.esxSettings = {
enabled = false,
-- Whether or not to use the new ESX export method
useNewESXExport = true,
}
--- SETTINGS FOR QBCORE
Config.qbSettings = {
enabled = true,
}
--- BASIC
-- Torque units | 'nm' or 'lb-ft'
Config.torqueUnits = 'nm'
--- Horsepower and torque calculation formula
-- If you're not using vanilla or vanilla-like handling:
-- Try out different formulas and see what works best for your server.
-- 'vanilla' = Perfect setup for vanilla handling as well as handling files obeying the principles of vanilla GTA
-- 'highperformance1' = Good for servers using handling files which result in faster vehicles
-- 'highperformance2' = Good for servers using handling files which result in faster vehicles (extra)
-- 'highperformance3' = Good for servers using handling files which result in faster vehicles (extra)
---------------------------------------------
Config.dynoFormula = 'vanilla'
--- FRAMEWORK OPTIONS (MAKE SURE TO ENABLE YOUR FRAMEWORK IF USING ONE) <!>
Config.jobWhitelist = {
enabled = true,
-- To configure the jobs, set them on each dyno individually
}
-- Time it takes for the screens to turn off after a dyno run (in seconds)
Config.screenTimeout = 30
-- Whether to display the dyno sheet on the screen as UI
Config.displaySheetOnScreen = true
-- Determines the location of the dyno sheet
Config.screenSheetOffset = {
x = 0.84,
y = 0.833,
}
-- Dynos setup
-- coords = vector3 of the dyno location
-- heading = heading of the dyno
-- model = model defined in Config.dynoModels (By leaving this out, you will create a dyno without a model. Useful for MLOs with built-in dynos)
-- displays = table of displays
-- displayCoords = vector3 of the display location
-- displayTilt = angle of the display tilt,
-- displayHeading = heading of the display
-- displayType = display defined in Config.displayTypes
-- jobs = Table of jobs which are allowed to use the dyno (false or nil to allow everyone to use it)
Config.dynos = {
['bennys'] = {
coords = vector3(-214.28, -1318.14, 30.9),
heading = 180.0,
model = 'default_purple',
displays = {
{
displayCoords = vector3(-217.4, -1318.92, 32.55),
displayHeading = 90.0,
displayTilt = 3.0,
displayType = 'wall_tv_2',
},
{
displayCoords = vector3(-211.5, -1320.6, 30.89),
displayHeading = 250.0,
displayType = 'stand',
}
},
jobs = { 'mechanic' },
},
['lsc_harmony'] = {
coords = vector3(1182.66, 2636.5, 37.78),
heading = 0.0,
model = 'default_blue',
displays = {
{
displayCoords = vector3(1182.66, 2634.6, 39.3),
displayHeading = 180.0,
displayType = 'wall_tv',
},
},
jobs = { 'mechanic' },
},
['lsc_airport'] = {
coords = vector3(-1164.45, -2018.8, 13.18),
heading = 315.0,
model = 'default_red',
displays = {
{
displayCoords = vector3(-1164.3, -2014.53, 14.13),
displayHeading = 45.0,
displayType = 'wall_tv',
},
},
jobs = { 'mechanic' },
},
['import_export_garage'] = {
coords = vector3(980.2, -3002.11, -39.65),
heading = 90.0,
model = 'default_blue',
displays = {
{
displayCoords = vector3(978.5, -2999.35, -39.62),
displayHeading = 0.0,
displayType = 'stand',
},
},
jobs = { 'mechanic' },
},
--['no_model_liberty_walk_mlo'] = {
-- coords = vector3(1148.40, -792.69, 57.5),
-- heading = 90.0,
--
-- displays = {
-- {
-- displayCoords = vector3(1148.29, -795.0, 58.35),
-- displayHeading = 190.0,
-- displayType = 'monitor',
-- },
-- },
--
-- jobs = nil,
--},
}
-- This is just used to fill the default dynos with their rollers
Config.baseRollers = {
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(0.18, 0.6, -0.08),
direction = -1,
side = 1,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(-0.18, 0.6, -0.08),
direction = -1,
side = 1,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(0.18, -1.18, -0.08),
direction = -1,
side = 2,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(-0.18, -1.18, -0.08),
direction = -1,
side = 2,
},
}
-- Dyno models
Config.dynoModels = {
['default_yellow'] = {
base = 'kq_dyno2_yellow',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['default_red'] = {
base = 'kq_dyno2_red',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['default_purple'] = {
base = 'kq_dyno2_purple',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['default_green'] = {
base = 'kq_dyno2_green',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['default_gray'] = {
base = 'kq_dyno2_gray',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['default_blue'] = {
base = 'kq_dyno2_blue',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, -0.04),
rollers = Config.baseRollers,
},
['basic'] = {
base = 'kq_dyno',
textureVariation = 0,
heading = -90.0,
offset = vector3(0.0, 0.0, 0.0),
rollers = {
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(0.18, 0.9, -0.08),
direction = -1,
side = 1,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(-0.18, 0.9, -0.08),
direction = -1,
side = 1,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(0.18, -0.9, -0.08),
direction = -1,
side = 2,
},
{
prop = 'kq_dyno_roller',
rotation = vector3(0.0, 90.0, 0.0),
offset = vector3(-0.18, -0.9, -0.08),
direction = -1,
side = 2,
},
}
},
}
-- Display types
-- prop = prop of the display
-- offset = offset of the display (texture, not the prop)
-- heading = heading of the display (texture, not the prop)
-- size = size of the display
Config.displayTypes = {
['stand'] = {
prop = 'prop_cs_tv_stand',
offset = vector3(0.529, -0.08, 1.01),
heading = 180.0,
size = vector2(1.098, 0.54),
},
['monitor'] = {
prop = 'prop_tv_flat_03',
offset = vector3(0.35, -0.01, 0.025),
heading = 180.0,
size = vector2(0.7, 0.4),
},
['wall_tv'] = {
prop = 'prop_tv_flat_01',
offset = vector3(1.07, -0.06, -0.12),
heading = 180.0,
size = vector2(2.14, 1.2),
},
['wall_tv_2'] = {
prop = 'xm_prop_x17_tv_flat_01',
offset = vector3(0.798, -0.046, 0.152),
heading = 180.0,
size = vector2(1.5, 0.832),
},
}
-- https://docs.fivem.net/docs/game-references/controls/
-- Use the input index for the "input" value
Config.keybinds = {
start = {
label = 'E',
name = 'INPUT_PICKUP',
input = 38,
},
}

View File

@@ -0,0 +1,22 @@
-- Discord webhook options
Config.webhook = {
enabled = false, -- Whether to send the dyno sheets to the discord webhook
-- To get the Discord webhook link, right click on a channel > Edit channel > Integrations > Webhooks > View webhooks > New webhook
url = 'YOUR_WEBHOOK_URL_HERE',
-- Here you can add webhooks for specific dynos. Based on the dyno key/index name (same as in config.lua)
dynoSpecific = {
['bennys'] = 'DYNO_SPECIFIC_WEBHOOK_URL_HERE', -- remove this line if you don't want to use a dyno specific webhooks
},
-- Replace this with the name of your server or a title you want on your dyno sheets
title = 'Red Valley - DynoTech',
-- Whether to include certain parts of the users info in the webhook messages
includeUserName = true,
includeSteamId = true,
color = 16723456,
}

View File

@@ -0,0 +1,59 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Car dyno by KuzQuality'
version '1.4.0'
ui_page 'html/blank.html'
data_file 'DLC_ITYP_REQUEST' 'stream/kq_dyno_props.ytyp'
files {
'html/js/jquery.js',
'html/js/chart.js',
'html/js/chartjs-annotation.js',
'html/js/html2canvas.js',
'html/blank.html',
'html/index.html',
}
--
-- Server
--
server_scripts {
'config.lua',
'config_server.lua',
'locale.lua',
'server/server.lua',
'server/editable/editable.lua',
}
--
-- Client
--
client_scripts {
'config.lua',
'locale.lua',
'client/editable/api.lua',
'client/functions.lua',
'client/cache.lua',
'client/client.lua',
'client/spawning.lua',
'client/display.lua',
'client/editable/client.lua',
'client/editable/esx.lua',
'client/editable/qb.lua',
}
escrow_ignore {
'config.lua',
'config_server.lua',
'locale.lua',
'client/editable/*.lua',
'server/editable/*.lua',
}
dependency '/assetpacks'

View File

@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<body style="background-color: transparent;">
</body>
</html>

View File

@@ -0,0 +1,228 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/jquery.js"></script>
<script src="js/chart.js"></script>
<script src="js/chartjs-annotation.js"></script>
<script src="js/html2canvas.js"></script>
</head>
<body>
<div class="chart">
<canvas id="chart"></canvas>
<span class="watermark">Dyno Technology by KuzQuality.com</span>
<span class="title" id="title"></span>
</div>
</body>
</html>
<script>
$(document).ready(() => {
let times = [];
let localeSet = false;
let title = '';
let peakHp = 'Peak HP';
let peakTorque = 'Peak Torque';
let torqueUnit = 'nm';
window.addEventListener('message', ({data}) => {
if (data.event === 'update') {
if (times.length > 600) {
times.shift();
}
times.push({
rpm: event.data.rpm,
hp: event.data.hp,
torque: event.data.torque,
});
setChart();
if (!localeSet) {
setLocale(data);
}
}
if (data.event === 'capture-image') {
captureImage(data.dynoKey);
}
});
function setLocale(data) {
localeSet = true;
title = data.title;
peakHp = data.peakHp;
peakTorque = data.peakTorque;
torqueUnit = data.torqueUnit;
$('#title').html(title);
}
function captureImage(dynoKey) {
$('.chart').addClass('screenshot');
$('.watermark').addClass('screenshot');
$('.title').addClass('screenshot');
html2canvas(document.querySelector(".chart")).then(canvas => {
const base64 = canvas.toDataURL();
fetch(`https://kq_dyno/SaveDynoImage`, {
method: 'POST',
body: JSON.stringify({img: base64, dynoKey}),
});
$('.chart').removeClass('screenshot');
$('.watermark').removeClass('screenshot');
$('.title').removeClass('screenshot');
});
}
function setChart() {
const chart = Chart.getChart("chart");
// If the chart exists, destroy it
if (chart) {
chart.destroy();
}
const xValues = times.map(({ rpm, hp, torque }) => rpm);
const hpValues = times.map(({ rpm, hp, torque }) => parseInt(hp));
const torqueValues = times.map(({ rpm, hp, torque }) => parseInt(torque));
const ctx = document.getElementById('chart').getContext('2d');
Chart.defaults.font.size = 33;
new Chart(ctx, {
type: 'line',
data: {
labels: xValues,
datasets: [
{
data: hpValues,
label: 'Horsepower',
borderColor: 'red',
fill: false
},
{
data: torqueValues,
label: 'Torque',
borderColor: 'blue',
fill: false
},
],
},
options: {
animation: false,
elements: {
point: {
radius: 1
},
},
scales: {
y: {
display: true,
min: 0,
max: Math.ceil(Math.max(Math.max(...torqueValues), Math.max(...hpValues)) * 1.1),
gridLines: {
color: 'rgba(255,255,255,0.3)'
},
},
x: {
type: 'category',
title: 'RPM',
display: true,
clip: true,
ticks: {
stepSize: 500, // Set the step size to 500
}
}
},
plugins: {
legend: {
display: false,
},
annotation: {
annotations: [
{
type: 'line',
mode: 'horizontal',
scaleID: 'y',
value: Math.max(...hpValues), // Set the value to where you want the line
borderColor: 'red', // Color of the line
borderWidth: 2, // Width of the line
borderDash: [20],
label: {
display: true,
content: peakHp + ' ' + Math.max(...hpValues), // Set the label content
enabled: true, // Show the label
position: '45%', // Position of the label ('start', 'center', or 'end')
}
},
{
type: 'line',
mode: 'horizontal',
scaleID: 'y',
value: Math.max(...torqueValues), // Set the value to where you want the line
borderColor: 'blue', // Color of the line
borderWidth: 2, // Width of the line
borderDash: [20],
label: {
display: true,
content: peakTorque + ' ' + Math.max(...torqueValues) + ' ' + torqueUnit, // Set the label content
enabled: true, // Show the label
position: '15%', // Position of the label ('start', 'center', or 'end')
}
}
]
}
}
},
});
}
});
</script>
<style>
html {
background-color: rgb(240, 240, 240);
}
.chart {
padding: 12px;
}
.chart.screenshot {
padding-top: 600px;
height: 1280px;
width: 1280px;
}
.watermark.screenshot {
bottom: -550px !important;
}
.watermark {
color: rgba(0, 0, 0, 0.2);
font-size: 22px;
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
font-family: Tahoma, sans-serif;
margin: 0;
}
.title {
color: rgba(148, 19, 19, 1);
font-size: 30px;
position: absolute;
bottom: 45px;
left: 50%;
transform: translateX(-50%);
font-family: Tahoma, sans-serif;
margin: 0;
}
.title.screenshot {
bottom: 130px !important;
font-size: 64px !important;
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,22 @@
Locale = {
['lb-ft'] = 'lb-ft',
['nm'] = 'nm',
['Press ~{INPUT}~ to start the dyno test'] = 'Apasa ~{INPUT}~ pentru a incepe testul dyno',
['~r~This vehicle is FWD biased. Turn it around'] = '~r~Acest vehicul este cu tractiune fata. Intoarce-l',
['~r~This vehicle is RWD biased. Turn it around'] = '~r~Acest vehicul este cu tractiune spate. Intoarce-l',
['~r~The vehicle isn\'t aligned correctly'] = '~r~Vehiculul nu este aliniat corect',
['~r~You are not allowed to perform dyno tests'] = '~r~Nu ai permisiunea sa efectuezi teste dyno',
['Peak HP'] = 'HP Maxim',
['Peak torque'] = 'Cuplu Maxim',
-- Webhooks
['Vehicle'] = 'Vehicul',
['License plate'] = 'Numar de inmatriculare',
['Date'] = 'Data',
['User'] = 'Utilizator',
['Dyno performance report'] = 'Raport de performanta dyno',
-- Display
['KuzQuality - DynoTech'] = 'Red Valley - DynoTech',
}

View File

@@ -0,0 +1,31 @@
function GetDiscordDescription(model, license, player)
local description = '- **' .. L('Vehicle') .. '**: ' .. model ..
'\n- **' .. L('License plate') .. '**: ' .. license ..
'\n- **' .. L('Date') .. '**: '.. os.date("%A, %m %B %Y - %H:%M")
if Config.webhook.includeUserName then
description = description .. '\n\n'.. L('User') .. ': ' .. GetPlayerName(player)
end
if Config.webhook.includeSteamId then
if not Config.webhook.includeUserName then
description = description .. '\n'
end
description = description .. '\n*' .. GetIdentifier(player) .. '*'
end
return description
end
function GetIdentifier(player)
for k, v in ipairs(GetPlayerIdentifiers(player)) do
if string.match(v, 'license:') then
return v:gsub('license:', '')
end
end
return ''
end
RegisterCommand('kq_dyno_restart', function(source)
TriggerClientEvent('kq_dyno:client:prepareRestart', -1, source)
end, true)

View File

@@ -0,0 +1,56 @@
-- Wheel indexes:
-- 0 = Front left
-- 1 = Front right
-- 2 = Rear left
-- 3 = Rear right
-- Damages a specific wheel (wheels have max 1000.0 hp)
RegisterNetEvent('kq_wheeldamage:damageWheel')
AddEventHandler('kq_wheeldamage:damageWheel', function(veh, wheel, damage)
ApplyWheelDamage(veh, wheel, damage, indexToBone[wheel])
end)
-- Removes the wheel without dropping it
RegisterNetEvent('kq_wheeldamage:removeWheel')
AddEventHandler('kq_wheeldamage:removeWheel', function(veh, wheel)
SetVehicleWheelHealth(veh, wheel, 0.0)
TriggerServerEvent('kq_wheeldamage:setState', NetworkGetNetworkIdFromEntity(veh), true)
TriggerServerEvent('kq_wheeldamage:setBroken', NetworkGetNetworkIdFromEntity(veh), wheel, true)
end)
-- Fully repairs/reattaches a wheel
RegisterNetEvent('kq_wheeldamage:fixWheel')
AddEventHandler('kq_wheeldamage:fixWheel', function(veh, wheel)
SetVehicleTyreFixed(veh, wheel)
SetVehicleWheelHealth(veh, wheel, 1000.0)
TriggerServerEvent('kq_wheeldamage:setBroken', NetworkGetNetworkIdFromEntity(veh), wheel, false)
end)
-- Fully repairs all wheels of a vehicle
RegisterNetEvent('kq_wheeldamage:fixCar')
AddEventHandler('kq_wheeldamage:fixCar', function(veh)
for wheel, bone in pairs(indexToBone) do
if wheel <= GetVehicleNumberOfWheels(veh) -1 then
SetVehicleTyreFixed(veh, wheel)
SetVehicleWheelHealth(veh, wheel, 1000.0)
TriggerServerEvent('kq_wheeldamage:setBroken', NetworkGetNetworkIdFromEntity(veh), wheel, false)
end
end
end)
function IsBlacklisted(veh)
if Contains(Config.blacklist.classes, GetVehicleClass(veh)) then
return true
end
for k, model in pairs(Config.blacklist.models) do
if GetEntityModel(veh) == GetHashKey(model) then
return true
end
end
return false
end

View File

@@ -0,0 +1,184 @@
Config = {}
Config.debug = false
-- Precise wheel rendering (This can fix the issue with broken wheels flashing in and out) If it doesn't happen on your server
-- I wouldn't recommend enabling this as it will slightly increase the script resource usage (resmon)
Config.increaseWheelRenderTiming = false
-- Alternative method of the wheel breaking. This will make the actual model of the wheel fall off (same rim, tire etc.)
-- Although it does look better it isn't properly synced (not possible at this moment)
-- That's why it's disabled by default. Enable it if you don't care about the loose wheel prop not being synced and want it
-- to look better for the driver
Config.alternativeWheelBreak = false
-- The amount of damage the wheels will take on collisions (10-30 seems reasonable to me, for more realistic experience I'd recommend values between 50-100)
Config.collisionDamageAmount = 20
-- If you define a model specific multiplier it will be used instead of the class multiplier
-- Vehicle classes https://docs.fivem.net/natives/?_0x29439776AAA00A62
Config.collisionDamageMultiplier = {
models = {
kuruma2 = 0.5
},
classes = {
[0] = 1.2, -- Compacts
[1] = 1, -- Sedans
[2] = 0.8, -- SUVs
[3] = 1, -- Coupes
[4] = 1, -- Muscle
[5] = 1.25, -- Sports Classics
[6] = 1.2, -- Sports
[7] = 1.2, -- Super
[8] = 1.1, -- Motorcycles
[9] = 0.5, -- Off-road
[10] = 0.5, -- Industrial
[11] = 0.5, -- Utility
[12] = 1, -- Vans
[13] = 0.5, -- Cycles
[14] = 0, -- Boats
[15] = 0, -- Helicopters
[16] = 0, -- Planes
[17] = 0.9, -- Service
[18] = 0.7, -- Emergency
[19] = 0.5, -- Military
[20] = 0.5, -- Commercial
[21] = 0, -- Trains
}
}
-- The amount of damage the wheels will take on falls (10-30 seems reasonable to me, for more realistic experience I'd recommend values between 50-100)
Config.fallDamageAmount = 25
-- Multiplier for the fall damage for vehicles that are using off-road tires/wheels
Config.offroadTireFallDamageMultiplier = 0.7
-- Threshold of the fall speed required to deal wheel damage (3.8 by default. If you don't want smaller jumps to deal damage set it higher)
Config.fallThreshold = 3.8
-- Minimum fall airtime (in seconds) for the wheels to get damaged. This only counts for the duration the car was falling (going downwards)
Config.minimumAirTime = 0.5
-- If you define a model specific multiplier it will be used instead of the class multiplier
-- Vehicle classes https://docs.fivem.net/natives/?_0x29439776AAA00A62
Config.fallDamageMultiplier = {
models = {
bf400 = 0.4,
sanchez = 0.4,
sanchez2 = 0.4,
manchez = 0.4,
},
classes = {
[0] = 1, -- Compacts
[1] = 1, -- Sedans
[2] = 0.3, -- SUVs
[3] = 1, -- Coupes
[4] = 0.7, -- Muscle
[5] = 1.3, -- Sports Classics
[6] = 1.2, -- Sports
[7] = 1.5, -- Super
[8] = 0.6, -- Motorcycles
[9] = 0.3, -- Off-road
[10] = 0.7, -- Industrial
[11] = 0.7, -- Utility
[12] = 1.3, -- Vans
[13] = 0.6, -- Cycles
[14] = 0, -- Boats
[15] = 0, -- Helicopters
[16] = 0, -- Planes
[17] = 0.9, -- Service
[18] = 0.5, -- Emergency
[19] = 0.2, -- Military
[20] = 0.7, -- Commercial
[21] = 0, -- Trains
}
}
-- Chance of the wheel falling off when it reaches critical damage (0 - 100)
Config.fallOffChance = 35
-- Chance of the tire bursting when it reaches critical damage (0 - 100)
Config.tireBurstChance = 100
-- Whether or not to respect bulletproof tires for popping (wheels will still fall off)
Config.respectBulletproofTires = true
-- Makes the car undriveable when at least one wheel falls off
Config.setVehicleUndriveable = true
-- Some vehicles become really fast when a wheel falls off (blame Rockstar)
-- To prevent abuse you can limit the vehicle speed when the wheels fall off
Config.limitVehicleSpeed = true
-- Speed limit in kmh
Config.speedLimit = 40.0
-- There's a few decent wheel models to choose from https://gtahash.ru/?s=wheel
-- the 'prop_wheel_01' might fit more popular rims but the 'prop_tornado_wheel' has bouncy physics
Config.wheelModel = 'prop_wheel_01'
Config.wheelRim = 'prop_wheel_rim_03'
-- Vehicle classes https://docs.fivem.net/natives/?_0x29439776AAA00A62
Config.blacklist = {
models = {
'blazer',
'blazer2',
'blazer3',
'blazer4',
'blazer5',
'monster',
'monster3',
'monster4',
'monster5',
},
classes = {
14, 15, 16, 21
}
}
-- Fall damage based on the ground type the vehicle lands on
-- Surfaces which are counted as road (https://docs.fivem.net/natives/?_0xA7F04022)
Config.roadSurfaces = {
1, 3, 4, 12
}
-- If you define a model specific multiplier it will be used instead of the class multiplier
-- Multiplier that will be used for falls that land on dirt / non road(road like) material
Config.offroadFallDamageMultiplier = {
models = {
bf400 = 0.3,
sanchez = 0.3,
sanchez2 = 0.3,
manchez = 0.3,
buggy = 0.7,
},
classes = {
[0] = 1.0, -- Compacts
[1] = 1.0, -- Sedans
[2] = 0.9, -- SUVs
[3] = 1, -- Coupes
[4] = 0.9, -- Muscle
[5] = 1.3, -- Sports Classics
[6] = 1.3, -- Sports
[7] = 1.3, -- Super
[8] = 1.0, -- Motorcycles
[9] = 0.7, -- Off-road
[10] = 0.9, -- Industrial
[11] = 1, -- Utility
[12] = 1.2, -- Vans
[13] = 0.6, -- Cycles
[14] = 0, -- Boats
[15] = 0, -- Helicopters
[16] = 0, -- Planes
[17] = 0.9, -- Service
[18] = 0.5, -- Emergency
[19] = 0.2, -- Military
[20] = 0.7, -- Commercial
[21] = 0, -- Trains
}
}

View File

@@ -0,0 +1,34 @@
fx_version 'cerulean'
games { 'gta5' }
lua54 'yes'
author 'KuzQuality | Kuzkay'
description 'Realistic wheel damage by KuzQuality'
version '1.4.2'
--
-- Server
--
server_scripts {
'config.lua',
'server/server.lua',
}
--
-- Client
--
client_scripts {
'config.lua',
'client/client.lua',
'client/editable/editable.lua',
}
escrow_ignore {
'config.lua',
'client/editable/*.lua',
}
dependency '/assetpacks'

Some files were not shown because too many files have changed in this diff Show More