forked from Simnation/Main
Merge branch 'master' of https://git.evolution-state-life.de/Evolution-State-Life/Main
This commit is contained in:
commit
58945d1610
55 changed files with 0 additions and 2731 deletions
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
-- Dispatch alerts are handled on the server for core-dispatch
|
|
@ -1,22 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
-- NOTE: This has NOT been tested, may need to be fixed. Please let me know if this doesn't work!
|
||||
exports['core_dispatch']:addCall(
|
||||
'10-66',
|
||||
GetLocalization('dispatch_label'),
|
||||
{
|
||||
{ icon = 'fa-car', info = GetVehicleNumberPlateText(vehicle) }
|
||||
},
|
||||
{
|
||||
coords.x, coords.y, coords.z
|
||||
},
|
||||
'police',
|
||||
3000,
|
||||
432,
|
||||
2,
|
||||
false
|
||||
)
|
||||
end
|
|
@ -1 +0,0 @@
|
|||
-- Dispatch alerts are handled on the server for ND_MDT
|
|
@ -1,11 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
-- NOTE: This has NOT been tested, may need to be fixed. Please let me know if this doesn't work!
|
||||
exports['ND_MDT']:createDispatch({
|
||||
callDescription = GetLocalization('dispatch_label'),
|
||||
coords = coords
|
||||
})
|
||||
end
|
|
@ -1 +0,0 @@
|
|||
-- Dispatch alerts are handled on the server for ox_mdt
|
|
@ -1,17 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
-- NOTE: This has NOT been tested, may need to be fixed. Please let me know if this doesn't work!
|
||||
exports.ox_mdt:createCall({
|
||||
offense = GetLocalization('dispatch_label'),
|
||||
code = '10-66',
|
||||
blip = 432,
|
||||
coords = { coords.x, coords.y },
|
||||
isEmergency = true,
|
||||
info = {
|
||||
{ label = GetVehicleNumberPlateText(vehicle), icon = 'badge-tm' }
|
||||
}
|
||||
})
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
---@param vehicle integer
|
||||
---@return table
|
||||
local function getVehicleData(vehicle)
|
||||
return {
|
||||
name = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))),
|
||||
plate = GetVehicleNumberPlateText(vehicle)
|
||||
}
|
||||
end
|
||||
|
||||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param coords vector3
|
||||
---@param vehicleNetId integer
|
||||
local function sendDispatchAlert(coords, vehicleNetId)
|
||||
local vehicle = NetToVeh(vehicleNetId)
|
||||
local vehicleData = getVehicleData(vehicle)
|
||||
|
||||
exports['ps-dispatch']:CustomAlert({
|
||||
message = GetLocalization('dispatch_label'), -- Title of the alert
|
||||
codeName = "NONE", -- Unique name for each alert
|
||||
code = "10-66", -- Code that is displayed before the title
|
||||
icon = 'fas fa-car', -- Icon that is displaed after the title
|
||||
coords = coords, -- Coords of the player
|
||||
priority = 2, -- Changes color of the alert ( 1 = red, 2 = default )
|
||||
vehicle = vehicleData.name, -- Vehicle name
|
||||
plate = vehicleData.plate, -- Vehicle plate
|
||||
automaticGunfire = false, -- Automatic Gun or not
|
||||
radius = 0, -- Radius around the blip
|
||||
sprite = 432, -- Sprite of the blip
|
||||
color = 2, -- Color of the blip
|
||||
scale = 1.0, -- Scale of the blip
|
||||
length = 2, -- How long it stays on the map
|
||||
sound = 'Lose_1st', -- Alert sound
|
||||
sound2 = 'GTAO_FM_Events_Soundset', -- Alert sound
|
||||
offset = 'false', -- Blip / radius offset
|
||||
flash = 'false', -- Blip flash
|
||||
jobs = { 'leo' },
|
||||
})
|
||||
end
|
||||
|
||||
RegisterNetEvent('slashtires:sendDispatchAlert', sendDispatchAlert)
|
|
@ -1,7 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
TriggerClientEvent('slashtires:sendDispatchAlert', source, coords, NetworkGetNetworkIdFromEntity(vehicle))
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
-- NOTE: This has NOT been tested, may need to be fixed. Please let me know if this doesn't work!
|
||||
|
||||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param coords vector3
|
||||
---@param vehicleNetId integer
|
||||
local function sendDispatchAlert(coords, vehicleNetId)
|
||||
local vehicle = NetToVeh(vehicleNetId)
|
||||
local playerData = exports['qs-dispatch']:GetPlayerInfo()
|
||||
local vehicleLabel = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)))
|
||||
local vehiclePlate = GetVehicleNumberPlateText(vehicle)
|
||||
|
||||
TriggerServerEvent('qs-dispatch:server:CreateDispatchCall', {
|
||||
job = { 'police', 'sheriff', 'traffic', 'patrol' },
|
||||
callLocation = coords,
|
||||
callCode = { code = GetLocalization('dispatch_label'), snippet = "10-66" },
|
||||
message = string.format("Street: %s Crossing Street: %s Sex: %s Vehicle: %s Vehicle Plate %s", playerData.street_1, playerData.street_2, playerData.sex, vehicleLabel, vehiclePlate),
|
||||
flashes = false,
|
||||
image = nil,
|
||||
blip = {
|
||||
sprite = 432,
|
||||
scale = 1.0,
|
||||
colour = 2,
|
||||
flashes = false,
|
||||
text = GetLocalization('dispatch_label'),
|
||||
time = (60 * 1000), -- 60 seconds
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
RegisterNetEvent('slashtires:sendDispatchAlert', sendDispatchAlert)
|
|
@ -1,7 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
TriggerClientEvent('slashtires:sendDispatchAlert', source, coords, NetworkGetNetworkIdFromEntity(vehicle))
|
||||
end
|
|
@ -1 +0,0 @@
|
|||
-- Dispatch alerts are handled on the server for rcore_dispatch
|
|
@ -1,25 +0,0 @@
|
|||
---Sends a dispatch alert about the slashing of tires
|
||||
---@param source string
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
function SendDispatchAlert(source, coords, vehicle)
|
||||
-- NOTE: This has NOT been tested, may need to be fixed. Please let me know if this doesn't work!
|
||||
local data = {
|
||||
code = '10-66', -- string -> The alert code, can be for example '10-64' or a little bit longer sentence like '10-64 - Shop robbery'
|
||||
default_priority = 'low', -- 'low' | 'medium' | 'high' -> The alert priority
|
||||
coords = coords, -- vector3 -> The coords of the alert
|
||||
job = 'police', -- string | table -> The job, for example 'police' or a table {'police', 'ambulance'}
|
||||
text = GetLocalization('dispatch_label'), -- string -> The alert text
|
||||
type = 'alerts', -- alerts | shop_robbery | car_robbery | bank_robbery -> The alert type to track stats
|
||||
blip_time = 5, -- number (optional) -> The time until the blip fades
|
||||
blip = { -- Blip table (optional)
|
||||
sprite = 432, -- number -> The blip sprite: Find them here (https://docs.fivem.net/docs/game-references/blips/#blips)
|
||||
colour = 2, -- number -> The blip colour: Find them here (https://docs.fivem.net/docs/game-references/blips/#blip-colors)
|
||||
scale = 1.0, -- number -> The blip scale
|
||||
text = GetLocalization('dispatch_label'), -- number (optional) -> The blip text
|
||||
flashes = false, -- boolean (optional) -> Make the blip flash
|
||||
radius = 0, -- number (optional) -> Create a radius blip instead of a normal one
|
||||
}
|
||||
}
|
||||
TriggerEvent('rcore_dispatch:server:sendAlert', data)
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
if not ESX then
|
||||
local exportExists, obj = pcall(function()
|
||||
return exports.es_extended:getSharedObject()
|
||||
end)
|
||||
|
||||
if exportExists then
|
||||
ESX = obj
|
||||
else
|
||||
TriggerEvent('esx:getSharedObject', function(esx)
|
||||
ESX = esx
|
||||
end)
|
||||
|
||||
while not ESX do
|
||||
Wait(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CanPlayerSlashTires()
|
||||
local playerData = ESX.GetPlayerData()
|
||||
if playerData.dead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
-- You may need to edit this to check for a metadata variable, but defualt esx does not have any handcuffed variable by default, so I'll just add an anim check here instead
|
||||
-- Checks if the ped has the CPED_CONFIG_FLAG_IsHandCuffed flag or is playing a cuffed anim
|
||||
local playerPed = PlayerPedId()
|
||||
if GetPedConfigFlag(playerPed, 120, true) or IsEntityPlayingAnim(playerPed, 'mp_arresting', 'idle', 3) then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
if not ESX then
|
||||
local exportExists, obj = pcall(function()
|
||||
return exports.es_extended:getSharedObject()
|
||||
end)
|
||||
|
||||
if exportExists then
|
||||
ESX = obj
|
||||
else
|
||||
TriggerEvent('esx:getSharedObject', function(esx)
|
||||
ESX = esx
|
||||
end)
|
||||
|
||||
while not ESX do
|
||||
Wait(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Logger function
|
||||
---@param source string
|
||||
---@param event string
|
||||
---@param message string
|
||||
---@param data table
|
||||
function Log(source, event, message, data)
|
||||
ESX.DiscordLog('default', "Slashtire", 'default', string.format("%s (%s) %s. data: %s", GetPlayerName(source), source, message, json.encode(data, {indent = true})))
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@param source string
|
||||
---@param playerPed integer
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires(source, playerPed)
|
||||
if Player(source).state.isDead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if IsPedHandcuffed(playerPed) then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
---Checks if the player can slash tires
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires()
|
||||
local playerState = LocalPlayer.state
|
||||
if playerState.dead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if playerState.gettingCuffed or playerState.isCuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
if playerState.invBusy or playerState.handsUp or playerState.isCuffing then
|
||||
return false, 'generic_fail_reason'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
if not lib then
|
||||
error("ox_lib was not included or did not load before this file! Please make sure to add '@ox_lib/init.lua' before shared/bridge.lua inside the fxmanifest!")
|
||||
end
|
||||
|
||||
---Logger function
|
||||
---@param source string
|
||||
---@param event string
|
||||
---@param message string
|
||||
---@param data table
|
||||
function Log(source, event, message, data)
|
||||
lib.logger(source, event, string.format("%s %s. data: %s", GetPlayerName(source), message, json.encode(data, {indent = true})))
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@param source string
|
||||
---@param playerPed integer
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires(source, playerPed)
|
||||
local playerState = Player(source).state
|
||||
if playerState.dead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if playerState.gettingCuffed or playerState.isCuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
if playerState.invBusy or playerState.handsUp or playerState.isCuffing then
|
||||
return false, 'generic_fail_reason'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
---Checks if the player can slash tires
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires()
|
||||
local playerState = LocalPlayer.state
|
||||
if playerState.isDead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if playerState.isCuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
if playerState.invBusy or playerState.isEscorted then
|
||||
return false, 'generic_fail_reason'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
if not lib then
|
||||
error("ox_lib was not included or did not load before this file! Please make sure to add '@ox_lib/init.lua' before shared/bridge.lua inside the fxmanifest!")
|
||||
end
|
||||
|
||||
---Logger function
|
||||
---@param source string
|
||||
---@param event string
|
||||
---@param message string
|
||||
---@param data table
|
||||
function Log(source, event, message, data)
|
||||
lib.logger(source, event, string.format("%s %s. data: %s", GetPlayerName(source), message, json.encode(data, {indent = true})))
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@param source string
|
||||
---@param playerPed integer
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires(source, playerPed)
|
||||
local playerState = Player(source).state
|
||||
if playerState.isDead then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if playerState.isCuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
if playerState.invBusy or playerState.isEscorted then
|
||||
return false, 'generic_fail_reason'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
if not QBCore then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires()
|
||||
local PlayerData = QBCore.Functions.GetPlayerData()
|
||||
local metadata = PlayerData?.metadata
|
||||
|
||||
if metadata?.isdead or metadata?.inlaststand then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if metadata?.ishandcuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
if not QBCore then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
end
|
||||
|
||||
---Logger function
|
||||
---@param source string
|
||||
---@param event string
|
||||
---@param message string
|
||||
---@param data table
|
||||
function Log(source, event, message, data)
|
||||
TriggerEvent('qb-log:server:CreateLog', 'default', "Slashtire", 'default', string.format("%s (%s) %s. data: %s", GetPlayerName(source), source, message, json.encode(data, {indent = true})))
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@param source string
|
||||
---@param playerPed integer
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires(source, playerPed)
|
||||
local QBPlayer = QBCore.Functions.GetPlayer(source)
|
||||
local metadata = QBPlayer?.PlayerData?.metadata
|
||||
|
||||
if metadata?.isdead or metadata?.inlaststand then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if metadata?.ishandcuffed then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
---Checks if the player can slash tires
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires()
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if IsPedDeadOrDying(playerPed, true) then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
-- Checks if the ped has the CPED_CONFIG_FLAG_IsHandCuffed flag or is playing a cuffed anim
|
||||
if GetPedConfigFlag(playerPed, 120, true) or IsEntityPlayingAnim(playerPed, 'mp_arresting', 'idle', 3) then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
---Logger function
|
||||
---@param source string
|
||||
---@param event string
|
||||
---@param message string
|
||||
---@param data table
|
||||
function Log(source, event, message, data)
|
||||
print(source, event, string.format("[Slashtire] %s (%s) %s", GetPlayerName(source), source, message), json.encode(data, {indent = true}))
|
||||
end
|
||||
|
||||
---Checks if the player can slash tires
|
||||
---@param source string
|
||||
---@param playerPed integer
|
||||
---@return boolean canPlayerSlash
|
||||
---@return string|nil reason nil if canPlayerSlash is true
|
||||
function CanPlayerSlashTires(source, playerPed)
|
||||
if GetEntityHealth(playerPed) == 0 then
|
||||
return false, 'is_dead'
|
||||
end
|
||||
|
||||
if IsPedHandcuffed(playerPed) then
|
||||
return false, 'is_handcuffed'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,54 +0,0 @@
|
|||
if not ESX then
|
||||
local exportExists, obj = pcall(function()
|
||||
return exports.es_extended:getSharedObject()
|
||||
end)
|
||||
|
||||
if exportExists then
|
||||
ESX = obj
|
||||
else
|
||||
TriggerEvent('esx:getSharedObject', function(esx)
|
||||
ESX = esx
|
||||
end)
|
||||
|
||||
while not ESX do
|
||||
Wait(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local HELP_TEXT <const> = {
|
||||
keyboard = GetLocalization('help_text_keyboard', '~INPUT_89560A13~'),
|
||||
controller = GetLocalization('help_text_controller', '~INPUT_5FCAA612~')
|
||||
}
|
||||
|
||||
local isShowingHelpText = false
|
||||
|
||||
---Displays the slash tire help text for the next 25 ticks
|
||||
local function showHelpText()
|
||||
local isUsingKeyboard = IsUsingKeyboard(1)
|
||||
local message = (isUsingKeyboard and HELP_TEXT.keyboard) or HELP_TEXT.controller
|
||||
|
||||
for _tick = 1, 25 do
|
||||
ESX.ShowHelpNotification(message, true)
|
||||
Wait(0)
|
||||
end
|
||||
end
|
||||
|
||||
---Runs a thread to show the help text
|
||||
local function helpTextThread()
|
||||
while isShowingHelpText do
|
||||
showHelpText()
|
||||
Wait(0)
|
||||
end
|
||||
end
|
||||
|
||||
---Starts showing the help text
|
||||
function StartHelpText()
|
||||
isShowingHelpText = true
|
||||
CreateThread(helpTextThread)
|
||||
end
|
||||
|
||||
---Stops showing the help text
|
||||
function StopHelpText()
|
||||
isShowingHelpText = false
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
if not lib then
|
||||
error("ox_lib was not included or did not load before this file! Please make sure to add '@ox_lib/init.lua' before shared/bridge.lua inside the fxmanifest!")
|
||||
end
|
||||
|
||||
---Starts showing the help text
|
||||
function StartHelpText()
|
||||
local keyCommand = IsUsingKeyboard(1) and `+slashtire` or `stc`
|
||||
local keyLabel = GetLocalization('help_text_keyboard', GetKeyMappingKey(keyCommand))
|
||||
|
||||
lib.showTextUI(keyLabel, {
|
||||
position = 'right-center',
|
||||
icon = 'hand-scissors'
|
||||
})
|
||||
end
|
||||
|
||||
---Stops showing the help text
|
||||
function StopHelpText()
|
||||
lib.hideTextUI()
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
---Starts showing the help text
|
||||
function StartHelpText()
|
||||
local keyCommand = IsUsingKeyboard(1) and `+slashtire` or `stc`
|
||||
local keyLabel = GetLocalization('help_text_keyboard', GetKeyMappingKey(keyCommand))
|
||||
exports['qb-core']:DrawText(keyLabel, 'left')
|
||||
end
|
||||
|
||||
---Stops showing the help text
|
||||
function StopHelpText()
|
||||
exports['qb-core']:HideText()
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
local showHelpText = false
|
||||
|
||||
AddTextEntry('slashtire_help_text_keyboard', GetLocalization('help_text_keyboard', '~INPUT_89560A13~'))
|
||||
AddTextEntry('slashtire_help_text_controller', GetLocalization('help_text_controller', '~INPUT_5FCAA612~'))
|
||||
|
||||
---Displays the help text for as long showHelpText is true
|
||||
local function helpTextThread()
|
||||
while showHelpText do
|
||||
local textLabel = IsUsingKeyboard(1) and 'slashtire_help_text_keyboard' or 'slashtire_help_text_controller'
|
||||
DisplayHelpTextThisFrame(textLabel, false)
|
||||
Wait(0)
|
||||
end
|
||||
end
|
||||
|
||||
---Starts showing the help text
|
||||
function StartHelpText()
|
||||
showHelpText = true
|
||||
CreateThread(helpTextThread)
|
||||
end
|
||||
|
||||
---Stops showing the help text
|
||||
function StopHelpText()
|
||||
showHelpText = false
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
if not Config.HelpText then
|
||||
return
|
||||
end
|
||||
|
||||
local GetSelectedPedWeapon = GetSelectedPedWeapon
|
||||
local equippedWeapon = `weapon_unarmed`
|
||||
|
||||
local function onWeaponEquipped(weaponHash)
|
||||
equippedWeapon = weaponHash
|
||||
TriggerEvent('slashtires:slashWeaponEquipped', Config.AllowedWeapons[weaponHash] ~= nil)
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(500)
|
||||
|
||||
local currentWeapon = GetSelectedPedWeapon(PlayerPedId())
|
||||
if currentWeapon ~= equippedWeapon then
|
||||
onWeaponEquipped(currentWeapon)
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -1,69 +0,0 @@
|
|||
if not ESX then
|
||||
local exportExists, obj = pcall(function()
|
||||
return exports.es_extended:getSharedObject()
|
||||
end)
|
||||
|
||||
if exportExists then
|
||||
ESX = obj
|
||||
else
|
||||
TriggerEvent('esx:getSharedObject', function(esx)
|
||||
ESX = esx
|
||||
end)
|
||||
|
||||
while not ESX do
|
||||
Wait(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Checks if the player has the weapon item specified
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@return boolean hasWeapon
|
||||
function HasWeapon(source, weaponHash)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
warn("Could not get player data checking for weapon item")
|
||||
return false
|
||||
end
|
||||
|
||||
local itemName = Config.AllowedWeapons[weaponHash].name
|
||||
local _loadoutNum, weapon = xPlayer.getWeapon(string.upper(itemName))
|
||||
|
||||
return weapon ~= nil
|
||||
end
|
||||
|
||||
---Removes the weapon from the player
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean success
|
||||
function RemoveWeapon(source, weaponHash, playerPed)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
warn("Could not get player data when removing a weapon")
|
||||
return false
|
||||
end
|
||||
|
||||
local weaponName = Config.AllowedWeapons[weaponHash]?.name
|
||||
weaponName = weaponName and string.upper(weaponName) or nil
|
||||
|
||||
if not weaponName then
|
||||
warn(string.format("Could not get weapon name when removing a weapon with hash %s", weaponHash))
|
||||
return false
|
||||
end
|
||||
|
||||
xPlayer.removeWeapon(weaponName)
|
||||
return true
|
||||
end
|
||||
|
||||
---Reduces durability for the weapon
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean removedWeapon If the weapon was removed due to durability going below 0
|
||||
function ReduceDurabilityForWeapon(source, weaponHash, playerPed)
|
||||
-- This is just a void function that does nothing, I don't believe esx has any support for item durability.
|
||||
|
||||
return false
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
if not Config.HelpText then
|
||||
return
|
||||
end
|
||||
|
||||
if not lib then
|
||||
error("ox_lib was not included or did not load before this file! Please make sure to add '@ox_lib/init.lua' before shared/bridge.lua inside the fxmanifest!")
|
||||
end
|
||||
|
||||
local function onWeaponEquipped(weaponHash)
|
||||
TriggerEvent('slashtires:slashWeaponEquipped', Config.AllowedWeapons[weaponHash] ~= nil)
|
||||
end
|
||||
|
||||
AddEventHandler('ox_inventory:currentWeapon', function(weapon)
|
||||
local hash = weapon?.hash or `weapon_unarmed`
|
||||
onWeaponEquipped(hash)
|
||||
end)
|
||||
|
||||
-- For debugging
|
||||
SetTimeout(0, function()
|
||||
if cache.weapon then
|
||||
onWeaponEquipped(cache.weapon)
|
||||
end
|
||||
end)
|
|
@ -1,48 +0,0 @@
|
|||
---Checks if the player has the weapon item specified
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@return boolean hasWeapon
|
||||
function HasWeapon(source, weaponHash)
|
||||
local itemName = Config.AllowedWeapons[weaponHash].name
|
||||
local count = exports.ox_inventory:GetItemCount(source, itemName)
|
||||
|
||||
return count > 0
|
||||
end
|
||||
|
||||
---Removes the weapon from the player
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean success
|
||||
function RemoveWeapon(source, weaponHash, playerPed)
|
||||
local weapon = exports.ox_inventory:GetCurrentWeapon(source)
|
||||
if not weapon then
|
||||
return false
|
||||
end
|
||||
|
||||
exports.ox_inventory:RemoveItem(source, weapon.name, 1, weapon.metadata, weapon.slot)
|
||||
return true
|
||||
end
|
||||
|
||||
---Reduces durability for the weapon
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean removedWeapon If the weapon was removed due to durability going below 0
|
||||
function ReduceDurabilityForWeapon(source, weaponHash, playerPed)
|
||||
local durabilityToReduce = Config.AllowedWeapons[weaponHash]?.durability
|
||||
if not durabilityToReduce then
|
||||
return false
|
||||
end
|
||||
|
||||
local weapon = exports.ox_inventory:GetCurrentWeapon(source)
|
||||
local durability = (weapon.metadata?.durability or 100) - durabilityToReduce
|
||||
|
||||
if durability <= 0.0 then
|
||||
return RemoveWeapon(source, weaponHash, playerPed)
|
||||
else
|
||||
exports.ox_inventory:SetDurability(source, weapon.slot, durability)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
local function onWeaponEquipped(weaponHash)
|
||||
TriggerEvent('slashtires:slashWeaponEquipped', Config.AllowedWeapons[weaponHash] ~= nil)
|
||||
end
|
||||
|
||||
AddEventHandler('qb-weapons:client:SetCurrentWeapon', function(weaponData)
|
||||
local hash = weaponData?.name and joaat(weaponData.name) or `weapon_unarmed`
|
||||
onWeaponEquipped(hash)
|
||||
end)
|
||||
|
||||
-- For older versions of qb-inventory
|
||||
AddEventHandler('weapons:client:SetCurrentWeapon', function(weaponData)
|
||||
local hash = weaponData?.name and joaat(weaponData.name) or `weapon_unarmed`
|
||||
onWeaponEquipped(hash)
|
||||
end)
|
||||
|
||||
-- For debugging
|
||||
SetTimeout(0, function()
|
||||
local currentWeapon = GetSelectedPedWeapon(PlayerPedId())
|
||||
if currentWeapon ~= `weapon_unarmed` then
|
||||
onWeaponEquipped(currentWeapon)
|
||||
end
|
||||
end)
|
|
@ -1,81 +0,0 @@
|
|||
if not QBCore then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
end
|
||||
|
||||
---Checks if the player has the weapon item specified
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@return boolean hasWeapon
|
||||
function HasWeapon(source, weaponHash)
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then
|
||||
warn("Could not get player data checking for weapon item")
|
||||
return false
|
||||
end
|
||||
|
||||
local itemName = Config.AllowedWeapons[weaponHash].name
|
||||
local itemCount = Player.Functions.GetItemByName(itemName)?.amount or 0
|
||||
|
||||
return itemCount > 0
|
||||
end
|
||||
|
||||
---Removes the weapon from the player
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean success
|
||||
function RemoveWeapon(source, weaponHash, playerPed)
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then
|
||||
warn("Could not get player data when removing a weapon")
|
||||
return false
|
||||
end
|
||||
|
||||
local itemName = Config.AllowedWeapons[weaponHash]?.name
|
||||
if not itemName then
|
||||
warn(string.format("Could not get weapon name when removing a weapon with hash %s", weaponHash))
|
||||
return false
|
||||
end
|
||||
|
||||
local removedWeapon = Player.Functions.RemoveItem(itemName, 1)
|
||||
if not removedWeapon then
|
||||
warn(string.format("QBCore could not remove weapon item %s from the players inventory", itemName))
|
||||
return false
|
||||
end
|
||||
|
||||
TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items[itemName], 'remove')
|
||||
RemoveWeaponFromPed(playerPed, weaponHash) -- qb-inventory does not remove the current weapon when it's associated item is removed, so we just force remove it
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Reduces durability for the weapon
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean removedWeapon If the weapon was removed due to durability going below 0
|
||||
function ReduceDurabilityForWeapon(source, weaponHash, playerPed)
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then
|
||||
warn("Could not get player data when reducing weapon durability")
|
||||
return false
|
||||
end
|
||||
|
||||
local weapon = Config.AllowedWeapons[weaponHash]
|
||||
if not weapon?.durability then
|
||||
return false
|
||||
end
|
||||
|
||||
local slot = QBCore.Player.GetFirstSlotByItem(Player.PlayerData.items, weapon.name)
|
||||
local weaponSlot = Player.PlayerData.items[slot]
|
||||
local durability = (weaponSlot.info.quality or 100) - weapon.durability
|
||||
|
||||
if durability <= 0.0 then
|
||||
return RemoveWeapon(source, weaponHash, playerPed)
|
||||
else
|
||||
weaponSlot.info.quality = durability
|
||||
Player.Functions.SetInventory(Player.PlayerData.items, true)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
if not Config.HelpText then
|
||||
return
|
||||
end
|
||||
|
||||
local GetSelectedPedWeapon = GetSelectedPedWeapon
|
||||
local equippedWeapon = `weapon_unarmed`
|
||||
|
||||
local function onWeaponEquipped(weaponHash)
|
||||
equippedWeapon = weaponHash
|
||||
TriggerEvent('slashtires:slashWeaponEquipped', Config.AllowedWeapons[weaponHash] ~= nil)
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(500)
|
||||
|
||||
local currentWeapon = GetSelectedPedWeapon(PlayerPedId())
|
||||
if currentWeapon ~= equippedWeapon then
|
||||
onWeaponEquipped(currentWeapon)
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -1,29 +0,0 @@
|
|||
---Checks if the player has the weapon item specified
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@return boolean hasWeapon
|
||||
function HasWeapon(source, weaponHash)
|
||||
-- Always return true, as we already know the player has the weapon
|
||||
return true
|
||||
end
|
||||
|
||||
---Removes the weapon from the player
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean success
|
||||
function RemoveWeapon(source, weaponHash, playerPed)
|
||||
RemoveWeaponFromPed(playerPed, weaponHash)
|
||||
return true
|
||||
end
|
||||
|
||||
---Reduces durability for the weapon
|
||||
---@param source string
|
||||
---@param weaponHash integer
|
||||
---@param playerPed integer
|
||||
---@return boolean removedWeapon If the weapon was removed due to durability going below 0
|
||||
function ReduceDurabilityForWeapon(source, weaponHash, playerPed)
|
||||
-- This is just a void function that does nothing, add some code below if you use an inventory that isn't already supported or change Config.Framework!
|
||||
|
||||
return false
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
if not ESX then
|
||||
local exportExists, obj = pcall(function()
|
||||
return exports.es_extended:getSharedObject()
|
||||
end)
|
||||
|
||||
if exportExists then
|
||||
ESX = obj
|
||||
else
|
||||
TriggerEvent('esx:getSharedObject', function(esx)
|
||||
ESX = esx
|
||||
end)
|
||||
|
||||
while not ESX do
|
||||
Wait(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Displays a notification to the player
|
||||
---@param message string
|
||||
function DisplayNotification(message)
|
||||
ESX.ShowNotification(message, 'error')
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
---Displays a notification to the player
|
||||
---@param message string
|
||||
function DisplayNotification(message)
|
||||
TriggerEvent('ox_lib:notify', {
|
||||
description = message,
|
||||
type = 'error'
|
||||
})
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
---Displays a notification to the player
|
||||
---@param message string
|
||||
function DisplayNotification(message)
|
||||
TriggerEvent('QBCore:Notify', message, 'error')
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
---Displays a notification to the player
|
||||
---@param message string
|
||||
function DisplayNotification(message)
|
||||
BeginTextCommandThefeedPost('STRING')
|
||||
AddTextComponentSubstringPlayerName(message)
|
||||
EndTextCommandThefeedPostTicker(false, false)
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
-- You should really consider using another script, bt-target is really old at this point.
|
||||
|
||||
AddEventHandler('slashtires:bt-target:slashTire', function()
|
||||
-- Fuck it, this is the easiest way.
|
||||
ExecuteCommand('slashtire')
|
||||
end)
|
||||
|
||||
local vehicles = {}
|
||||
local modelList = GetAllVehicleModels()
|
||||
|
||||
for i = 1, #modelList do
|
||||
vehicles[i] = joaat(modelList[i])
|
||||
end
|
||||
|
||||
exports['bt-target']:AddTargetModel(vehicles, {
|
||||
options = {
|
||||
{
|
||||
event = 'slashtires:bt-target:slashTire',
|
||||
icon = Config.TargetIcon,
|
||||
label = GetLocalization('target_label'),
|
||||
}
|
||||
},
|
||||
job = { 'all' },
|
||||
distance = Config.MaxTireInteractionDist
|
||||
})
|
|
@ -1,24 +0,0 @@
|
|||
local bones = {}
|
||||
for boneName, _index in pairs(WHEEL_BONES) do
|
||||
bones[#bones+1] = boneName
|
||||
end
|
||||
|
||||
exports.ox_target:addGlobalVehicle({
|
||||
{
|
||||
label = GetLocalization('target_label'),
|
||||
icon = Config.TargetIcon,
|
||||
distance = Config.MaxTireInteractionDist,
|
||||
bones = bones,
|
||||
canInteract = function(entity)
|
||||
return TargetCanInteract(entity)
|
||||
end,
|
||||
onSelect = function(data)
|
||||
local tire = exports[CURRENT_RESOURCE]:getClosestVehicleTire(data.entity, data.coords)
|
||||
if tire.index == nil then
|
||||
return
|
||||
end
|
||||
|
||||
exports[CURRENT_RESOURCE]:attemptToSlashTire(tire)
|
||||
end
|
||||
}
|
||||
})
|
|
@ -1,22 +0,0 @@
|
|||
for boneName, _index in pairs(WHEEL_BONES) do
|
||||
exports['qb-target']:AddTargetBone(boneName, {
|
||||
options = {
|
||||
{
|
||||
icon = Config.TargetIcon,
|
||||
label = GetLocalization('target_label'),
|
||||
canInteract = function(entity)
|
||||
return TargetCanInteract(entity)
|
||||
end,
|
||||
action = function(entity)
|
||||
local tire = exports[CURRENT_RESOURCE]:getVehicleTireByBone(entity, boneName)
|
||||
if tire.index == nil then
|
||||
return
|
||||
end
|
||||
|
||||
exports[CURRENT_RESOURCE]:attemptToSlashTire(tire)
|
||||
end
|
||||
}
|
||||
},
|
||||
distance = Config.MaxTireInteractionDist
|
||||
})
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
for boneName, _index in pairs(WHEEL_BONES) do
|
||||
exports.qtarget:AddTargetBone(boneName, {
|
||||
options = {
|
||||
{
|
||||
icon = Config.TargetIcon,
|
||||
label = GetLocalization('target_label'),
|
||||
canInteract = function(entity)
|
||||
return TargetCanInteract(entity)
|
||||
end,
|
||||
action = function(entity)
|
||||
local tire = exports[CURRENT_RESOURCE]:getVehicleTireByBone(entity, boneName)
|
||||
if tire.index == nil then
|
||||
return
|
||||
end
|
||||
|
||||
exports[CURRENT_RESOURCE]:attemptToSlashTire(tire)
|
||||
end
|
||||
}
|
||||
},
|
||||
distance = Config.MaxTireInteractionDist
|
||||
})
|
||||
end
|
|
@ -1,546 +0,0 @@
|
|||
---@alias tire { index: integer, distance: number, coords: vector3, name: string, vehicle: integer }
|
||||
|
||||
-- Variables --
|
||||
local isSlashing = false
|
||||
|
||||
|
||||
-- Functions --
|
||||
|
||||
---Requests and waits for a animation dictionary to be loaded
|
||||
---@param dict string
|
||||
local function loadAnimDict(dict)
|
||||
RequestAnimDict(dict)
|
||||
while not HasAnimDictLoaded(dict) do
|
||||
Wait(0)
|
||||
end
|
||||
end
|
||||
|
||||
---Async function that waits until anim is played or timeout is passed
|
||||
---@param ped integer
|
||||
---@param animDict string
|
||||
---@param animName string
|
||||
---@param timeout integer|nil Deciseconds, defualts to 30 (3000ms)
|
||||
---@return boolean playedAnim
|
||||
local function waitUntilPedIsPlayingAnim(ped, animDict, animName, timeout)
|
||||
if not timeout then
|
||||
timeout = 30
|
||||
end
|
||||
|
||||
while not IsEntityPlayingAnim(ped, animDict, animName, 3) do
|
||||
timeout = timeout - 1
|
||||
if timeout <= 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
Wait(100)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Returns if the vehicle's model is blacklisted from getting slashed
|
||||
---@param vehicle integer
|
||||
---@return boolean isBlacklisted
|
||||
---@return string|nil blacklistReason
|
||||
local function isVehicleModelBlacklisted(vehicle)
|
||||
local blacklistReason = Config.VehicleBlacklist[GetEntityModel(vehicle)]
|
||||
if blacklistReason == nil then
|
||||
if not Config.CanSlashEmergencyVehicles and GetVehicleClass(vehicle) == 18 then
|
||||
blacklistReason = 3
|
||||
end
|
||||
end
|
||||
|
||||
return blacklistReason ~= nil, VEHICLE_BLACKLIST_REASONS[blacklistReason]
|
||||
end
|
||||
|
||||
---Returns if the weapon can slash a tire
|
||||
---@return boolean canSlash
|
||||
local function canWeaponSlashTires(weaponHash)
|
||||
return Config.AllowedWeapons[weaponHash] ~= nil
|
||||
end
|
||||
|
||||
---Returns if the current player weapon can slash a tire
|
||||
---@return boolean canSlash
|
||||
local function canCurrentWeaponSlashTires()
|
||||
local weaponHash = GetSelectedPedWeapon(PlayerPedId())
|
||||
return canWeaponSlashTires(weaponHash)
|
||||
end
|
||||
|
||||
---Gets the heading from coords A to coords B
|
||||
---@param initialCoords vector2
|
||||
---@param targetCoords vector2
|
||||
---@return number heading
|
||||
local function getHeadingBetweenCoords(initialCoords, targetCoords)
|
||||
local x = targetCoords.x - initialCoords.x
|
||||
local y = targetCoords.y - initialCoords.y
|
||||
|
||||
local heading = GetHeadingFromVector_2d(x, y)
|
||||
return heading
|
||||
end
|
||||
|
||||
---Burst a vehicles tire
|
||||
---@param vehicle integer
|
||||
---@param tireIndex integer
|
||||
local function burstVehicleTire(vehicle, tireIndex)
|
||||
local bulletproof = not GetVehicleTyresCanBurst(vehicle)
|
||||
if bulletproof then
|
||||
SetVehicleTyresCanBurst(vehicle, true)
|
||||
end
|
||||
|
||||
-- This is to give it a sound effect
|
||||
SetVehicleTyreBurst(vehicle, tireIndex, true, 1000.0)
|
||||
SetVehicleTyreFixed(vehicle, tireIndex)
|
||||
|
||||
-- Actuall tire deflation
|
||||
SetVehicleTyreBurst(vehicle, tireIndex, false, 100.0)
|
||||
|
||||
if bulletproof then
|
||||
SetVehicleTyresCanBurst(vehicle, false)
|
||||
end
|
||||
end
|
||||
|
||||
---Gets data for the vehicle tire
|
||||
---@param vehicle integer
|
||||
---@param boneName string
|
||||
---@param coords vector3|nil
|
||||
---@return tire tire
|
||||
local function getVehicleTireByBone(vehicle, boneName, coords)
|
||||
local boneIndex = GetEntityBoneIndexByName(vehicle, boneName)
|
||||
if boneIndex == -1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local boneCoords = GetWorldPositionOfEntityBone(vehicle, boneIndex)
|
||||
if not coords then
|
||||
coords = GetEntityCoords(PlayerPedId())
|
||||
end
|
||||
|
||||
return {
|
||||
index = WHEEL_BONES[boneName],
|
||||
distance = #(coords - boneCoords),
|
||||
coords = boneCoords,
|
||||
name = boneName,
|
||||
vehicle = vehicle
|
||||
}
|
||||
end
|
||||
|
||||
---Returns the closest tire of a vehicle
|
||||
---@param vehicle integer
|
||||
---@param coords vector3|nil|false
|
||||
---@return table closestVehicle
|
||||
local function getClosestVehicleTire(vehicle, coords)
|
||||
local closest = {
|
||||
distance = Config.MaxTireDetectionDist,
|
||||
}
|
||||
|
||||
if not coords then
|
||||
coords = GetEntityCoords(PlayerPedId())
|
||||
end
|
||||
|
||||
for boneName, _index in pairs(WHEEL_BONES) do
|
||||
local tire = getVehicleTireByBone(vehicle, boneName, coords)
|
||||
|
||||
if tire.index ~= nil and tire.distance < closest.distance then
|
||||
closest = tire
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
---Makes the ped face the spesifed coords
|
||||
---@param ped integer
|
||||
---@param coords vector3
|
||||
local function makePedFaceCoords(ped, coords)
|
||||
local headingDifference = math.abs(GetEntityHeading(ped) - getHeadingBetweenCoords(GetEntityCoords(ped), coords))
|
||||
if headingDifference < 40.0 then
|
||||
return
|
||||
end
|
||||
|
||||
local duration = math.min(math.floor(headingDifference*6), 1000)
|
||||
TaskTurnPedToFaceCoord(ped, coords.x, coords.y, coords.z, duration)
|
||||
Wait(duration)
|
||||
end
|
||||
|
||||
---Checks if the ped should be given the flee task from the spesifed coords
|
||||
---@param ped integer
|
||||
---@param coords vector3
|
||||
---@param vehicle integer
|
||||
---@param playerPed integer
|
||||
---@return boolean canFleePed
|
||||
local function canGivePedFleeTask(ped, coords, vehicle, playerPed)
|
||||
local dist = #(coords - GetEntityCoords(ped))
|
||||
if dist > Config.AIReactionDistance then
|
||||
return false
|
||||
end
|
||||
|
||||
if IsPedAPlayer(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Frozen peds can't flee anyway, and they are most likley a script handled ped (for stores and robberies for example)
|
||||
if IsEntityPositionFrozen(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- If the ped has the CPED_CONFIG_FLAG_DisableShockingEvents flag
|
||||
if GetPedConfigFlag(ped, 294, true) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Ignore dead peds
|
||||
if IsPedDeadOrDying(ped, true) then
|
||||
return false
|
||||
end
|
||||
|
||||
if not IsEntityVisible(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
if not IsPedHuman(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- This is cpu demanding, so it should be left as the last check
|
||||
if GetVehiclePedIsIn(ped, false) ~= vehicle and not HasEntityClearLosToEntityInFront(ped, playerPed) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Gets the peds that we want to react and flee after we have slashed a tire
|
||||
---@param coords vector3
|
||||
---@param vehicle integer The vehicle of the tire getting slashed
|
||||
---@return table <integer, integer>
|
||||
local function getPedsToFlee(coords, vehicle, playerPed)
|
||||
local peds = {}
|
||||
local pedPool = GetGamePool('CPed')
|
||||
|
||||
for i = 1, #pedPool do
|
||||
local ped = pedPool[i]
|
||||
if canGivePedFleeTask(ped, coords, vehicle, playerPed) then
|
||||
peds[#peds+1] = PedToNet(ped)
|
||||
end
|
||||
end
|
||||
|
||||
return peds
|
||||
end
|
||||
|
||||
---Displays a message and sets isSlashing to false
|
||||
---@param notifMessage string
|
||||
local function slashTireEnded(notifMessage)
|
||||
DisplayNotification(notifMessage)
|
||||
isSlashing = false
|
||||
end
|
||||
|
||||
---Slashes a vehicles tire
|
||||
---@param tire tire
|
||||
local function slashTire(tire)
|
||||
isSlashing = true
|
||||
local playerPed = PlayerPedId()
|
||||
local vehicle = tire.vehicle
|
||||
|
||||
if Config.DoFaceCoordTask then
|
||||
makePedFaceCoords(playerPed, tire.coords)
|
||||
end
|
||||
|
||||
loadAnimDict(Config.SlashTireAnimation.Dict)
|
||||
TaskPlayAnim(playerPed, Config.SlashTireAnimation.Dict, Config.SlashTireAnimation.Name, 2.0, 1.0, 700, 0, 0, false, false, false)
|
||||
RemoveAnimDict(Config.SlashTireAnimation.Dict)
|
||||
|
||||
if Config.DoAnimationCheckLoop then
|
||||
local playedAnim = waitUntilPedIsPlayingAnim(playerPed, Config.SlashTireAnimation.Dict, Config.SlashTireAnimation.Name, 30)
|
||||
if not playedAnim then
|
||||
slashTireEnded(GetLocalization('slash_timeout'))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
Wait(450)
|
||||
|
||||
local weaponHash = GetSelectedPedWeapon(playerPed)
|
||||
local canSlash = canWeaponSlashTires(weaponHash)
|
||||
if not canSlash then
|
||||
slashTireEnded(GetLocalization('invalid_weapon'))
|
||||
return
|
||||
end
|
||||
|
||||
-- Get the data for the same tire again and check the new distance in case it has changed
|
||||
local updatedTire = getVehicleTireByBone(vehicle, tire.name)
|
||||
if updatedTire.distance > Config.MaxTireDetectionDist then
|
||||
slashTireEnded(GetLocalization('slash_timeout'))
|
||||
return
|
||||
end
|
||||
|
||||
local isBulletproof = not GetVehicleTyresCanBurst(vehicle)
|
||||
if isBulletproof and (Config.BulletproofSetting == 'proof' or Config.BulletproofSetting == 'limit' and not Config.AllowedWeapons[weaponHash]?.canSlashBulletProof) then
|
||||
slashTireEnded(GetLocalization('tire_is_bulletproof'))
|
||||
return
|
||||
end
|
||||
|
||||
-- If we have network control over the vehicle then just burst the tire, if not we send the event to the server
|
||||
local hasNetworkControlOverVehicle = NetworkHasControlOfEntity(vehicle)
|
||||
if hasNetworkControlOverVehicle then
|
||||
burstVehicleTire(vehicle, tire.index)
|
||||
end
|
||||
|
||||
local peds = getPedsToFlee(tire.coords, tire.vehicle, playerPed)
|
||||
|
||||
-- Send event to server (for logging + tire burst if we did not have network control)
|
||||
TriggerServerEvent('slashtires:slashTire', NetworkGetNetworkIdFromEntity(vehicle), tire.index, peds, hasNetworkControlOverVehicle)
|
||||
|
||||
-- Event for other scripts to listen to
|
||||
TriggerEvent('slashtires:slashedTire', vehicle, tire.index)
|
||||
|
||||
Wait(1000)
|
||||
isSlashing = false
|
||||
end
|
||||
|
||||
---Does a raycast check to get the current target vehicle
|
||||
---@return integer|nil
|
||||
local function getTargetVehicle()
|
||||
local playerPed = PlayerPedId()
|
||||
local coords = GetEntityCoords(playerPed)
|
||||
local coordTo = GetOffsetFromEntityInWorldCoords(playerPed, 0.0, 2.0, 0.0)
|
||||
|
||||
local rayHandle = StartShapeTestCapsule(coords.x, coords.y, coords.z, coordTo.x, coordTo.y, coordTo.z, 1.0, 6, playerPed, 7)
|
||||
local _retval, hit, _endCoords, _surfaceNormal, entityHit = GetShapeTestResult(rayHandle)
|
||||
|
||||
if hit and IsEntityAVehicle(entityHit) then
|
||||
return entityHit
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
---Returns if the player can slash the vehicle tire
|
||||
---@param tire tire
|
||||
---@return boolean canSlash
|
||||
---@return string|nil reason
|
||||
local function canSlashVehicleTire(tire)
|
||||
if isSlashing then
|
||||
return false, 'is_slashing'
|
||||
end
|
||||
|
||||
local canSlash, reason = CanPlayerSlashTires()
|
||||
if not canSlash then
|
||||
return false, reason
|
||||
end
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
if IsPedRagdoll(playerPed) then
|
||||
return false, 'in_ragdoll'
|
||||
end
|
||||
|
||||
if not canCurrentWeaponSlashTires() then
|
||||
return false, 'invalid_weapon'
|
||||
end
|
||||
|
||||
local isBlacklisted, blacklistReason = isVehicleModelBlacklisted(tire.vehicle)
|
||||
if isBlacklisted then
|
||||
return false, blacklistReason
|
||||
end
|
||||
|
||||
if tire.distance > Config.MaxTireInteractionDist then
|
||||
return false, 'too_far_away'
|
||||
end
|
||||
|
||||
if IsVehicleTyreBurst(tire.vehicle, tire.index, false) then
|
||||
return false, 'tire_is_punctured'
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Attempts to slash the vehicles tire
|
||||
---@param tire tire
|
||||
local function attemptToSlashTire(tire)
|
||||
local canSlash, reason = canSlashVehicleTire(tire)
|
||||
if not canSlash and reason then
|
||||
DisplayNotification(GetLocalization(reason))
|
||||
return
|
||||
end
|
||||
|
||||
slashTire(tire)
|
||||
end
|
||||
|
||||
---Returns if we can interact with the tires of a vehicle
|
||||
---@param vehicle integer
|
||||
---@return boolean canInteract
|
||||
local function canInteractWithVehicleTires(vehicle)
|
||||
local isBlacklisted, blacklistReason = isVehicleModelBlacklisted(vehicle)
|
||||
if not isBlacklisted then
|
||||
return true
|
||||
end
|
||||
|
||||
if blacklistReason == 'vehicle_is_blacklisted' or blacklistReason == 'tire_is_indestructible' or blacklistReason == 'vehicle_is_emergency' then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---Gets the closest vehicle and tire and calls the attemptToSlashTire function
|
||||
local function slashTireCommand()
|
||||
if IsPedInAnyVehicle(PlayerPedId(), false) then
|
||||
DisplayNotification(GetLocalization('in_a_vehicle'))
|
||||
return
|
||||
end
|
||||
|
||||
local vehicle = getTargetVehicle()
|
||||
if vehicle == nil then
|
||||
DisplayNotification(GetLocalization('no_vehicle_nearby'))
|
||||
return
|
||||
end
|
||||
|
||||
local tire = getClosestVehicleTire(vehicle)
|
||||
if tire.index == nil then
|
||||
DisplayNotification(GetLocalization('no_tire_nearby'))
|
||||
return
|
||||
end
|
||||
|
||||
attemptToSlashTire(tire)
|
||||
end
|
||||
|
||||
|
||||
-- Targeting / 3rd Eye --
|
||||
---Returns if a target script should show the slash tire option
|
||||
---@param vehicle integer
|
||||
---@return boolean canInteract
|
||||
function TargetCanInteract(vehicle)
|
||||
if not canCurrentWeaponSlashTires() then
|
||||
return false
|
||||
end
|
||||
|
||||
if not canInteractWithVehicleTires(vehicle) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Commands, Key Mapping & Threads --
|
||||
if Config.HelpText then
|
||||
local isShowingHelpText = false
|
||||
|
||||
---If the slashtire key mapping press should be blocked
|
||||
---@return boolean block
|
||||
local function shouldSlashKeyPressBeBlocked()
|
||||
return not isShowingHelpText or IsPauseMenuActive()
|
||||
end
|
||||
|
||||
RegisterKeyMapping('+slashtire', GetLocalization('keymapping_desc_keyboard'), 'keyboard', Config.DefaultKey)
|
||||
RegisterCommand('+slashtire', function()
|
||||
if not shouldSlashKeyPressBeBlocked() then
|
||||
slashTireCommand()
|
||||
end
|
||||
end, false)
|
||||
RegisterCommand('-slashtire', function()
|
||||
-- Do nothing
|
||||
end, false)
|
||||
|
||||
-- For controller users
|
||||
RegisterKeyMapping('stc', GetLocalization('keymapping_desc_controller'), 'PAD_ANALOGBUTTON', Config.DefaultPadAnalogButton)
|
||||
RegisterCommand('stc', function()
|
||||
if not shouldSlashKeyPressBeBlocked() then
|
||||
slashTireCommand()
|
||||
end
|
||||
end, false)
|
||||
|
||||
---Does all the prompt checks and shows the help text if successful, returns the time that the script should wait until next check
|
||||
---@return integer waitMs
|
||||
---@return boolean showHelpText
|
||||
local function promptTick()
|
||||
if isSlashing or IsPedInAnyVehicle(PlayerPedId(), false) then
|
||||
return 1000, false
|
||||
end
|
||||
|
||||
local vehicle = getTargetVehicle()
|
||||
if vehicle == nil or not canInteractWithVehicleTires(vehicle) then
|
||||
return 500, false
|
||||
end
|
||||
|
||||
local tire = getClosestVehicleTire(vehicle)
|
||||
if tire.index == nil or tire.distance > Config.MaxTireInteractionDist or IsVehicleTyreBurst(vehicle, tire.index, false) then
|
||||
return 250, false
|
||||
end
|
||||
|
||||
return 100, true
|
||||
end
|
||||
|
||||
local threadIsActive = false
|
||||
local slashWeaponEquipped = false
|
||||
|
||||
local function weaponEquippedThread()
|
||||
threadIsActive = true
|
||||
|
||||
while slashWeaponEquipped do
|
||||
local wait, showHelpText = promptTick()
|
||||
if showHelpText then
|
||||
if not isShowingHelpText then
|
||||
StartHelpText()
|
||||
isShowingHelpText = true
|
||||
end
|
||||
elseif isShowingHelpText then
|
||||
StopHelpText()
|
||||
isShowingHelpText = false
|
||||
end
|
||||
|
||||
Wait(wait)
|
||||
end
|
||||
|
||||
-- Hide the help text if the weapon was de-equipped
|
||||
if isShowingHelpText then
|
||||
StopHelpText()
|
||||
isShowingHelpText = false
|
||||
end
|
||||
|
||||
threadIsActive = false
|
||||
end
|
||||
|
||||
AddEventHandler('slashtires:slashWeaponEquipped', function(state)
|
||||
slashWeaponEquipped = state
|
||||
|
||||
if not state or threadIsActive then
|
||||
return
|
||||
end
|
||||
|
||||
CreateThread(weaponEquippedThread)
|
||||
end)
|
||||
end
|
||||
|
||||
RegisterCommand('slashtire', function()
|
||||
slashTireCommand()
|
||||
end, false)
|
||||
|
||||
if Config.AddChatSuggestion then
|
||||
TriggerEvent('chat:addSuggestion', '/slashtire', GetLocalization('chat_suggestion'))
|
||||
end
|
||||
|
||||
|
||||
-- Events --
|
||||
RegisterNetEvent('slashtires:burstTire', function(netId, tireIndex)
|
||||
local vehicle = NetworkGetEntityFromNetworkId(netId)
|
||||
burstVehicleTire(vehicle, tireIndex)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('slashtires:displayNotification', function(message)
|
||||
DisplayNotification(message)
|
||||
end)
|
||||
|
||||
|
||||
-- Exports --
|
||||
local function getIsSlashing()
|
||||
return isSlashing
|
||||
end
|
||||
|
||||
exports('isSlashing', getIsSlashing)
|
||||
exports('canCurrentWeaponSlashTires', canCurrentWeaponSlashTires)
|
||||
exports('burstVehicleTire', burstVehicleTire)
|
||||
exports('getVehicleTireByBone', getVehicleTireByBone)
|
||||
exports('getClosestVehicleTire', getClosestVehicleTire)
|
||||
exports('slashTire', slashTire)
|
||||
exports('canSlashVehicleTire', canSlashVehicleTire)
|
||||
exports('attemptToSlashTire', attemptToSlashTire)
|
|
@ -1,234 +0,0 @@
|
|||
-- Partially based on this snippet: https://gist.github.com/DemmyDemon/69d53b78b005a7c1a6fdb9036e401f4c
|
||||
local KEY_CODES <const> = {
|
||||
-- b_0 = "",
|
||||
-- b_1 = "",
|
||||
-- b_2 = "",
|
||||
-- b_3 = "",
|
||||
b_4 = "D-pad Up", -- LUP_INDEX - D-pad Up
|
||||
b_5 = "D-pad Down", -- LDOWN_INDEX - D-pad Down
|
||||
b_6 = "D-pad Left", -- LLEFT_INDEX - D-pad Left
|
||||
b_7 = "D-pad Right", -- LRIGHT_INDEX - D-pad Right
|
||||
-- b_8 = "",
|
||||
-- b_9 = "",
|
||||
-- b_10 = "",
|
||||
-- b_11 = "",
|
||||
-- b_12 = "",
|
||||
-- b_13 = "",
|
||||
-- b_14 = "",
|
||||
-- b_15 = "",
|
||||
b_16 = "Left Stick Press", -- L3_INDEX - Left Stick Press
|
||||
-- b_17 = "",
|
||||
b_18 = "Left Stick Up/Down", -- FIXME: Up and down on left stick on controller (but only triggers on down?)
|
||||
b_19 = "Left Stick Left/Right", -- FIXME: Left and right on left stick on controller (but only triggers on right?)
|
||||
-- b_20 = "",
|
||||
-- b_21 = "",
|
||||
-- b_22 = "",
|
||||
-- b_23 = "",
|
||||
-- b_24 = "",
|
||||
b_25 = "Right Stick Press", -- R3_INDEX - Right Stick Press
|
||||
-- b_26 = "",
|
||||
b_27 = "Right Stick Up/Down", -- FIXME: Up and down on right stick on controller (but only triggers on down?)
|
||||
b_28 = "Right Stick Left/Right", -- FIXME: Left and right on right stick on controller (but only triggers on right?)
|
||||
-- b_29 = "",
|
||||
b_30 = "A", -- RDOWN_INDEX - A / Cross
|
||||
b_31 = "B", -- RRIGHT_INDEX - B / Circle
|
||||
b_32 = "X", -- RLEFT_INDEX - X / Square
|
||||
b_33 = "Y", -- RUP_INDEX - Y / Triangle
|
||||
b_34 = "LB", -- L1_INDEX - Left Shoulder Button
|
||||
b_35 = "LT", -- L2_INDEX - Left Trigger
|
||||
b_36 = "RB", -- R1_INDEX - Right Shoulder Button
|
||||
b_37 = "RT", -- R2_INDEX - Right Trigger
|
||||
b_38 = "Start", -- FIXME: "Start" on my xbox controller
|
||||
b_39 = "Back", -- FIXME: "Back" on my xbox controller
|
||||
-- b_40 = "",
|
||||
-- b_41 = "",
|
||||
-- b_42 = "",
|
||||
-- b_43 = "",
|
||||
-- b_44 = "",
|
||||
-- b_45 = "",
|
||||
-- b_46 = "",
|
||||
-- b_47 = "",
|
||||
b_100 = "LMB", -- MOUSE_LEFT - Mouse Button 0 (Left Click)
|
||||
b_101 = "RMB", -- MOUSE_RIGHT - Mouse Button 1 (Right Click)
|
||||
b_102 = "MMB", -- MOUSE_MIDDLE - Mouse Button 2 (Middle Click)
|
||||
b_103 = "Mouse 4",
|
||||
b_104 = "Mouse 5",
|
||||
b_105 = "Mouse 6",
|
||||
b_106 = "Mouse 7",
|
||||
b_107 = "Mouse 8",
|
||||
b_108 = "Mouse Left",
|
||||
b_109 = "Mouse Right",
|
||||
b_110 = "Mouse Up",
|
||||
b_111 = "Mouse Down",
|
||||
b_112 = "Mouse Left/Right",
|
||||
b_113 = "Mouse Up/Down",
|
||||
b_114 = "Mouse",
|
||||
b_115 = "Scroll Up",
|
||||
b_116 = "Scroll Down",
|
||||
b_117 = "Scroll Wheel",
|
||||
b_130 = "Num -",
|
||||
b_131 = "Num +",
|
||||
b_134 = "Num *",
|
||||
b_135 = "Num Enter", -- FIXME: This may be wrong
|
||||
b_136 = "Num 0",
|
||||
b_137 = "Num 1",
|
||||
b_138 = "Num 2",
|
||||
b_139 = "Num 3",
|
||||
b_140 = "Num 4",
|
||||
b_141 = "Num 5",
|
||||
b_142 = "Num 6",
|
||||
b_143 = "Num 7",
|
||||
b_144 = "Num 8",
|
||||
b_145 = "Num 9",
|
||||
b_146 = "Num =",
|
||||
b_147 = "Num ,",
|
||||
b_148 = "Num ÷", -- FIXME: Do the fonts have ÷ in them?
|
||||
b_149 = "Num x",
|
||||
b_150 = "Intro",
|
||||
b_151 = "???",-- FIXME some sort of upper line?!
|
||||
b_170 = "F1",
|
||||
b_171 = "F2",
|
||||
b_172 = "F3",
|
||||
b_173 = "F4",
|
||||
b_174 = "F5",
|
||||
b_175 = "F6",
|
||||
b_176 = "F7",
|
||||
b_177 = "F8",
|
||||
b_178 = "F9",
|
||||
b_179 = "F10",
|
||||
b_180 = "F11",
|
||||
b_181 = "F12",
|
||||
b_182 = "F13",
|
||||
b_183 = "F14",
|
||||
b_184 = "F15",
|
||||
b_185 = "F16",
|
||||
b_186 = "F17",
|
||||
b_187 = "F18",
|
||||
b_188 = "F19",
|
||||
b_189 = "F20",
|
||||
b_190 = "F21",
|
||||
b_191 = "F22",
|
||||
b_192 = "F23",
|
||||
b_193 = "F24",
|
||||
b_194 = "Up Arrow",
|
||||
b_195 = "Down Arrow",
|
||||
b_196 = "Left Arrow",
|
||||
b_197 = "Right Arrow",
|
||||
b_198 = "Del",
|
||||
b_199 = "Esc",
|
||||
b_200 = "Ins",
|
||||
b_201 = "End",
|
||||
b_202 = "Suppr",
|
||||
b_203 = "Échap",
|
||||
b_204 = "Fin",
|
||||
b_205 = "Entf",
|
||||
b_206 = "Einfg",
|
||||
b_207 = "Ende",
|
||||
b_208 = "Canc",
|
||||
b_209 = "Fine",
|
||||
b_210 = "Delete",
|
||||
b_211 = "Insert",
|
||||
b_212 = "End",
|
||||
b_213 = "Supr",
|
||||
b_214 = "Insertar",
|
||||
b_215 = "Fin",
|
||||
b_216 = "¨",
|
||||
b_217 = "`",
|
||||
b_995 = "???", -- Literally says so on the sprite. In red. (Button shown when a key has been removed from the keymapping)
|
||||
-- b_996 = "", -- Button outline sprite
|
||||
-- b_997 = "", -- Button outline sprite
|
||||
b_998 = "+", -- The + in things like Ctrl+A?
|
||||
-- b_999 = "", -- Button outline sprite
|
||||
b_1000 = "L Shift", -- Left Shift - FIXME Fonts do not have ⇑ in them. What can be used for Shift?
|
||||
b_1001 = "R Shift", -- Right Shift - FIXME Same problem as above
|
||||
b_1002 = "Tab",
|
||||
b_1003 = "Enter", -- FIXME Common key, undrawable glyph. Fonts to not have ↲ in them.
|
||||
b_1004 = "Backspace", -- FIXME ← is easily confused with left arrow...
|
||||
b_1005 = "Print Screen",
|
||||
b_1006 = "Scroll Lock",
|
||||
b_1007 = "Pause",
|
||||
b_1008 = "Home",
|
||||
b_1009 = "Page Up",
|
||||
b_1010 = "Page Down",
|
||||
b_1011 = "Num Lock",
|
||||
b_1012 = "Caps Lock",
|
||||
b_1013 = "L Ctrl", -- Left Control
|
||||
b_1014 = "R Ctrl", -- Right Control
|
||||
b_1015 = "L Alt",
|
||||
b_1016 = "R Alt",
|
||||
b_1017 = "Menu",
|
||||
b_1018 = "L Win",
|
||||
b_1019 = "R Win",
|
||||
b_1020 = "Imppr écran",
|
||||
b_1021 = "Arrèt défil",
|
||||
b_1022 = "↖", -- FIXME: Check if the fonts have this symbol.
|
||||
b_1023 = "⇞", -- FIXME: Do the fonts even have this symbol? What *is* this?
|
||||
b_1024 = "⇟", -- FIXME: Do the fonts even have this symbol? What *is* this?
|
||||
b_1025 = "Verr Numm",
|
||||
b_1026 = "Verr Maj",
|
||||
b_1027 = "Ctrl G",
|
||||
b_1028 = "Ctrl D",
|
||||
b_1029 = "Druck",
|
||||
b_1030 = "Rollen ↓",
|
||||
b_1031 = "Pos 1",
|
||||
b_1032 = "Bild ↑",
|
||||
b_1033 = "Bild ↓",
|
||||
b_1034 = "Num ↓",
|
||||
b_1035 = "⇓", -- FIXME: Probably an invisible glyph again. WTF even is this?
|
||||
b_1036 = "Strg L",
|
||||
b_1037 = "Strg R",
|
||||
b_1038 = "Maiusc sx",
|
||||
b_1039 = "Maiusc dx",
|
||||
b_1040 = "Invio",
|
||||
b_1041 = "Stampa",
|
||||
b_1042 = "Bloc Scorr",
|
||||
b_1043 = "Pausa",
|
||||
b_1044 = "↖", -- FIXME: Do the fonts even have this symbol? What *is* this?
|
||||
b_1045 = "Pag ↑",
|
||||
b_1046 = "Pag ↓",
|
||||
b_1047 = "Bloc Num",
|
||||
b_1048 = "Bloc Maiusc",
|
||||
b_1049 = "Ctrl sx",
|
||||
b_1050 = "Ctrl dx",
|
||||
b_1051 = "Alt gr",
|
||||
b_1052 = "Impr Pant",
|
||||
b_1053 = "Bloq Despl",
|
||||
b_1054 = "Pausa",
|
||||
b_1055 = "Home",
|
||||
b_1056 = "Page Up",
|
||||
b_1057 = "Av Pág",
|
||||
b_1058 = "Bloq Num",
|
||||
b_1059 = "Bloq Mayús",
|
||||
b_1060 = "Ctrl I",
|
||||
b_1061 = "Ctrl D",
|
||||
b_1062 = "Menú",
|
||||
b_1063 = "Impr Pant",
|
||||
b_1064 = "Bloq Despl",
|
||||
b_1065 = "Pausa",
|
||||
b_1066 = "Inicio",
|
||||
b_1067 = "Re Pág",
|
||||
b_1068 = "Av Pág",
|
||||
b_1069 = "Bloq Num",
|
||||
b_1070 = "Mayús",
|
||||
b_1071 = "Opsciones",
|
||||
b_1072 = "Maj G",
|
||||
b_1073 = "Maj D",
|
||||
b_1074 = "Alt",
|
||||
b_1075 = "Alt D",
|
||||
b_1076 = "I Shift",
|
||||
b_1077 = "D Shift",
|
||||
b_2000 = "Space"
|
||||
}
|
||||
|
||||
---Get's the label of a key mapped command
|
||||
---@param commandHash any
|
||||
---@return string
|
||||
function GetKeyMappingKey(commandHash)
|
||||
local key = GetControlInstructionalButton(0, commandHash | 0x80000000, true)
|
||||
if string.find(key, "t_") then
|
||||
local label, _count = string.gsub(key, "t_", "")
|
||||
return label
|
||||
else
|
||||
return KEY_CODES[key] or string.format("unknown (%s)", key)
|
||||
end
|
||||
end
|
|
@ -1,284 +0,0 @@
|
|||
Config = {}
|
||||
-- If you have a cool suggestion or if anything is unclear please leave a comment on the forum post :D
|
||||
|
||||
-- The targeting solution (3rd eye) to use (if you don't want to use any then either just use the /slashtire command or set Config.HelpText to 'auto'/whatever system you use)
|
||||
-- false : Don't use any targeting solution.
|
||||
-- 'ox_target' : ox_target by the overextended team and its many other contributors. (https://github.com/overextended/ox_target)
|
||||
-- 'qb-target' : qb-target by BerkieBb and its many other contributors. (https://github.com/BerkieBb/qb-target)
|
||||
-- 'qtarget' : qtarget by Linden (thelindat), Noms (OfficialNoms) and its many other contributors. (https://github.com/overextended/qtarget)
|
||||
-- 'bt-target' : bt-target by brentN5 (https://github.com/brentN5/bt-target). I advise against using this option due to how old it is.
|
||||
-- 'auto' : auto detect a target system, defaults to false if no supported scripts was found
|
||||
Config.Target = 'auto'
|
||||
|
||||
-- The icon that will be shown beside the text when using the 3rd eye. Only used if any of the targeting solutions are enabled.
|
||||
Config.TargetIcon = 'fas fa-hand-scissors'
|
||||
|
||||
-- The system we should use for the help text/prompt system if wanted
|
||||
-- false : Don't use any help text/prompt system.
|
||||
-- 'ox' : ox_lib's text ui module (make sure to include '@ox_lib/init.lua' in the fxmanifest)
|
||||
-- 'qb' : QBCore's DrawText export
|
||||
-- 'esx' : ESX's ShowHelpNotification (basically the same same as standalone but trough esx)
|
||||
-- 'standalone' : Using gta natives to show a help text in the top right
|
||||
-- 'auto' : auto detect a supported help text system, defaults to standalone if no supported scripts was found
|
||||
Config.HelpText = 'qb'
|
||||
|
||||
-- The default keybind for keyboard, leave it empty ('') for no default.
|
||||
Config.DefaultKey = 'E'
|
||||
|
||||
-- The default button for controllers, see possible controls here: https://github.com/citizenfx/fivem-docs/blob/master/content/docs/game-references/input-mapper-parameter-ids/pad_analogbutton.md
|
||||
Config.DefaultPadAnalogButton = 'L2_INDEX' -- Left Trigger
|
||||
|
||||
-- What framework to use. Supported "frameworks" and what they are used for:
|
||||
-- 'ox' : Uses OX oriented player states (client/server) and ox_lib's logger function (server) (make sure to include '@ox_lib/init.lua' in the fxmanifest)
|
||||
-- 'qb' : Uses QB player metadata (client/server) and qb-log event (server)
|
||||
-- 'esx' : Uses ESX player data (client), ESX oriented player states (server) and ESX discord log (server)
|
||||
-- 'nd' : ND_core, uses lib.logger (ox_lib) and player states (not tested)
|
||||
-- 'standalone' : Uses gta natives as checks and prints the log to the server console
|
||||
-- 'auto' : Attempts to auto detect a framework, defaults to standalone if no supported scripts was found
|
||||
Config.Framework = 'qb'
|
||||
|
||||
-- 'ox' : ox_inventory or any that can provide for it
|
||||
-- 'qb' : qb-inventory or a framework that supports qbcore inventory related functions
|
||||
-- 'esx' : ESX core inventory
|
||||
-- 'standalone' : Standalone checking, uses gta 5 natives where possible
|
||||
-- 'auto' : Attempts to auto detect a supported inventory script, defaults to standalone if no supported scripts was found
|
||||
Config.Inventory = 'qb'
|
||||
|
||||
-- 'ox' : ox_lib's notifications
|
||||
-- 'qb' : QB notifications (event)
|
||||
-- 'esx' : ESX notifications
|
||||
-- 'standalone' : GTA natives (shows notif above the minimap)
|
||||
-- 'auto' : Attempts to auto detect a notification script, defaults to standalone if no supported scripts was found
|
||||
Config.Notification = 'qb'
|
||||
|
||||
-- false : No dispatch alerts
|
||||
-- 'ps' : ps-dispatch by Project Sloth
|
||||
-- 'nd' : Dispatch alerts for ND_MDT for ND_core
|
||||
-- 'ox' : Bridge for ox_mdt
|
||||
-- 'core' : Bridge for core_dispatch
|
||||
-- 'rcore' : Bridge for rcore_dispatch
|
||||
-- 'quasar' : Bridge for qs-dispatch (This has not been tested)
|
||||
-- 'auto' : Attempts to auto detect a supported dispatch/mdt script. Defaults to false if none was found.
|
||||
Config.Dispatch = 'auto'
|
||||
|
||||
-- The % chance to give an alert if there is a NPC nearby that observes the slashing
|
||||
Config.DispatchAlertChance = 25.0 -- 25%
|
||||
|
||||
-- The language localization to load, add your own to the locales folder if needed!
|
||||
-- Avalible ones per now is: 'en' (english) and 'no' (norwegian bokmål)
|
||||
Config.Language = 'de'
|
||||
|
||||
-- The maximum distance from the player you want it to detect tires, this allows for the Config.Lang.TooFar message to be shown between this and Config.MaxTireInteractionDist.
|
||||
Config.MaxTireDetectionDist = 2.0
|
||||
|
||||
-- The maximum distance from the tire the player can be for it to allow them to interact with it.
|
||||
Config.MaxTireInteractionDist = 1.2
|
||||
|
||||
-- The animtion used when slashing a tire
|
||||
Config.SlashTireAnimation = {
|
||||
Dict = 'melee@knife@streamed_core_fps',
|
||||
Name = 'ground_attack_on_spot'
|
||||
}
|
||||
|
||||
-- How the script should handle bulletproof tires.
|
||||
-- Options:
|
||||
-- ignore: Ignores whether or not the tire is bulletproof. However, bulletproof tires will never go down to the rim, and only ever be "deflated".
|
||||
-- limit: Allows the weapons with the canSlashBulletProof parameter set to true to puncture bulletproof tires.
|
||||
-- proof: Makes the bulletproof tires slash proof.
|
||||
Config.BulletproofSetting = 'limit'
|
||||
|
||||
-- If the script should attempt to make the player ped face the tire or not.
|
||||
Config.DoFaceCoordTask = true
|
||||
|
||||
-- Check if the player is doing the animation before slashing the tire, times out (stops the slashing attempt) after 3 seconds.
|
||||
-- This is supposed to make the animation and burst of the tire to be more synchronous.
|
||||
Config.DoAnimationCheckLoop = true
|
||||
|
||||
-- If true it makes all the npc's close by react and flee from the player when they slash a tire.
|
||||
Config.AIReactAndFlee = true
|
||||
|
||||
-- All AI peds within this distance will react and flee from the player when he/she slashes a tire. (if Config.AIReactAndFlee is set to true)
|
||||
Config.AIReactionDistance = 10.0
|
||||
|
||||
-- If enabled, adds help text to the /slashtire command. This is designed to work with fivem's default chat resource.
|
||||
Config.AddChatSuggestion = true
|
||||
|
||||
-- Toggle whether or not to have a chance of weapons breaking.
|
||||
-- You may need to add some code yourself (trigger an event or export) if you are using this in combination with an inventory script that has weapons as items. See the removeWeapon function in server.lua
|
||||
Config.CanWeaponsBreak = true
|
||||
|
||||
-- If the item (weapon) used to slash a tire should get reduced durability
|
||||
Config.ReducedItemDurability = true
|
||||
|
||||
-- A list of the hashes of the weapons that can be used to slash tires.
|
||||
Config.AllowedWeapons = {
|
||||
['weapon_knife'] = {
|
||||
name = 'weapon_knife', -- The name of the weapon, only used if you want to setup stuff for inventory scripts
|
||||
breakChance = 8, -- The % chance for the weapon to break, this is only used if Config.CanWeaponsBreak is set to true. Values must be between 0 and 100, 0 = never break. 100 = always break.
|
||||
durability = 10.0, -- The amount of durability to remove when the weapon is used to slash a tire (for this to work Config.ReducedItemDurability needs to be set to true and the framework/inventory script needs to support durability!)
|
||||
canSlashBulletProof = false -- If this weapon can slash bulletproof tires when Config.BulletproofSetting is set to 'limit'
|
||||
},
|
||||
['weapon_hammer'] = {
|
||||
name = 'weapon_hammer',
|
||||
durability = 10.0,
|
||||
breakChance = 15
|
||||
},
|
||||
['weapon_crowbar'] = {
|
||||
name = 'weapon_crowbar',
|
||||
durability = 10.0,
|
||||
breakChance = 10
|
||||
},
|
||||
['weapon_bottle'] = {
|
||||
name = 'weapon_bottle',
|
||||
durability = 25.0,
|
||||
breakChance = 20
|
||||
},
|
||||
['weapon_dagger'] = {
|
||||
name = 'weapon_dagger',
|
||||
durability = 5.0,
|
||||
breakChance = 2,
|
||||
canSlashBulletProof = true
|
||||
},
|
||||
['weapon_hatchet'] = {
|
||||
name = 'weapon_hatchet',
|
||||
durability = 10.0,
|
||||
breakChance = 7
|
||||
},
|
||||
['weapon_machete'] = {
|
||||
name = 'weapon_machete',
|
||||
durability = 10.0,
|
||||
breakChance = 8
|
||||
},
|
||||
['weapon_switchblade'] = {
|
||||
name = 'weapon_switchblade',
|
||||
durability = 8.0,
|
||||
breakChance = 5
|
||||
},
|
||||
['weapon_battleaxe'] = {
|
||||
name = 'weapon_battleaxe',
|
||||
durability = 10.0,
|
||||
breakChance = 6
|
||||
},
|
||||
['weapon_stone_hatchet'] = {
|
||||
name = 'weapon_stone_hatchet',
|
||||
durability = 10.0,
|
||||
breakChance = 8
|
||||
}
|
||||
}
|
||||
|
||||
-- Whether or not to allow people to slash emergency vehicles.
|
||||
Config.CanSlashEmergencyVehicles = true
|
||||
|
||||
-- Vehicles that can't have their tires slashed.
|
||||
-- 1 = vehicle_is_blacklisted; block slashing, give generic message to player
|
||||
-- 2 = tire_is_indestructible; block slashing, tell player that the tire seems indestructible
|
||||
-- 3 = vehicle_is_emergency; block slashing, tell player they can't slash the tires of emergency vehicles (setting Config.CanSlashEmergencyVehicles will make all emergancy class vehicles return this reason)
|
||||
-- 4 = tire_is_track; hide slashing option, tell player (if done trough command) that they can't slash tracks
|
||||
-- 5 = tire_is_train_wheel; hide slashing option, tell player (if done trough command) that they can't train wheels
|
||||
-- 6 = tire_is_invisible; hide slashing option, tell player (if done trough command) that there are no nearby tires to slash
|
||||
Config.VehicleBlacklist = {
|
||||
-- Indestructible tires (planes and helicopters)
|
||||
['akula'] = 2,
|
||||
['alkonost'] = 2,
|
||||
['annihilator'] = 2,
|
||||
['annihilator2'] = 2,
|
||||
['avenger'] = 2,
|
||||
['avenger2'] = 2,
|
||||
['avenger3'] = 2,
|
||||
['avenger4'] = 2,
|
||||
['blimp'] = 2,
|
||||
['blimp2'] = 2,
|
||||
['blimp3'] = 2,
|
||||
['bombushka'] = 2,
|
||||
['buzzard'] = 2,
|
||||
['buzzard2'] = 2,
|
||||
['cargobob'] = 2,
|
||||
['cargobob2'] = 2,
|
||||
['cargobob3'] = 2,
|
||||
['cargobob4'] = 2,
|
||||
['frogger'] = 2,
|
||||
['frogger2'] = 2,
|
||||
['howard'] = 2,
|
||||
['hunter'] = 2,
|
||||
['maverick'] = 2,
|
||||
['microlight'] = 2,
|
||||
['pyro'] = 2,
|
||||
['savage'] = 2,
|
||||
['seabreeze'] = 2,
|
||||
['skylift'] = 2,
|
||||
['swift'] = 2,
|
||||
['swift2'] = 2,
|
||||
['tula'] = 2,
|
||||
['volatol'] = 2,
|
||||
['volatus'] = 2,
|
||||
|
||||
-- Indestructible tires (other vehicles)
|
||||
['apc'] = 2,
|
||||
['blazer4'] = 2,
|
||||
['cerberus'] = 2,
|
||||
['cerberus2'] = 2,
|
||||
['cerberus3'] = 2,
|
||||
['deathbike2'] = 2,
|
||||
['dukes2'] = 2,
|
||||
['halftrack'] = 2,
|
||||
['insurgent'] = 2,
|
||||
['insurgent2'] = 2,
|
||||
['insurgent3'] = 2,
|
||||
['kuruma2'] = 2,
|
||||
['marshall'] = 2,
|
||||
['menacer'] = 2,
|
||||
['monster'] = 2,
|
||||
['monster3'] = 2,
|
||||
['monster4'] = 2,
|
||||
['monster5'] = 2,
|
||||
['nightshark'] = 2,
|
||||
['paragon2'] = 2,
|
||||
['pounder2'] = 2,
|
||||
['rcbandito'] = 2,
|
||||
['scramjet'] = 2,
|
||||
['tractor'] = 2,
|
||||
['trailersmall2'] = 2,
|
||||
['veto'] = 2,
|
||||
['veto2'] = 2,
|
||||
['vigilante'] = 2,
|
||||
['zhaba'] = 2,
|
||||
|
||||
-- Tracked vehicles
|
||||
['bulldozer'] = 4,
|
||||
['khanjali'] = 4,
|
||||
['minitank'] = 4,
|
||||
['rhino'] = 4,
|
||||
['scarab'] = 4,
|
||||
['scarab2'] = 4,
|
||||
['scarab3'] = 4,
|
||||
|
||||
-- Train wheels
|
||||
['freight'] = 5,
|
||||
['freight2'] = 5,
|
||||
['freightcar'] = 5,
|
||||
['freightcar2'] = 5,
|
||||
['freightcont1'] = 5,
|
||||
['freightcont2'] = 5,
|
||||
['freightgrain'] = 5,
|
||||
['metrotrain'] = 5,
|
||||
['tankercar'] = 5,
|
||||
|
||||
-- Fake/invisible tires
|
||||
['conada'] = 6,
|
||||
['conada2'] = 6,
|
||||
['havok'] = 6,
|
||||
['oppressor2'] = 6,
|
||||
['polmav'] = 6,
|
||||
['raketrailer'] = 6,
|
||||
['seasparrow'] = 6,
|
||||
['seasparrow2'] = 6,
|
||||
['seasparrow3'] = 6,
|
||||
['supervolito'] = 6,
|
||||
['supervolito2'] = 6,
|
||||
['thruster'] = 6,
|
||||
['valkyrie'] = 6,
|
||||
['valkyrie2'] = 6,
|
||||
|
||||
-- Custom
|
||||
-- ['myfancycar'] = 1, -- This is an example
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
lua54 'yes'
|
||||
use_experimental_fxv2_oal 'yes'
|
||||
|
||||
name 'slashtires'
|
||||
author 'Mads'
|
||||
description 'A script that allows people to slash tires'
|
||||
version '2.0.1'
|
||||
|
||||
shared_scripts {
|
||||
-- '@ox_lib/init.lua', -- Please uncomment this if you want to use ox_core or ox_lib's TextUI with this script
|
||||
'config.lua',
|
||||
'shared/variables.lua',
|
||||
'shared/localization.lua',
|
||||
'shared/bridge.lua'
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'client/client.lua',
|
||||
'client/keylabels.lua'
|
||||
}
|
||||
|
||||
server_script 'server/server.lua'
|
||||
|
||||
files {
|
||||
'locales/*.json',
|
||||
'bridge/**/*.lua'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
'/server:5181', -- Required due to the escrow system. You should probably be using a much newer version then this anyway.
|
||||
}
|
||||
|
||||
escrow_ignore {
|
||||
'config.lua',
|
||||
'shared/variables.lua',
|
||||
'shared/localization.lua',
|
||||
'shared/bridge.lua',
|
||||
'client/client.lua',
|
||||
'client/keylabels.lua',
|
||||
'server/server.lua',
|
||||
'bridge/**/*.lua'
|
||||
}
|
||||
|
||||
dependency '/assetpacks'
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"target_label": "Reifen-Aufschlitzen",
|
||||
"chat_suggestion": "Den nächstgelegenen Reifen eines Fahrzeugs aufschlitzen",
|
||||
"dispatch_label": "Möglicherweise Reifen aufschlitzen",
|
||||
|
||||
"help_text_keyboard": "Zum Aufschlitzen des Reifens %s drücken",
|
||||
"help_text_controller": "Zum Aufschlitzen des Reifens %s drücken",
|
||||
|
||||
"keymapping_desc_keyboard": "Reifen Aufschlitzen",
|
||||
"keymapping_desc_controller": "Reifen Aufschlitzen - Controller",
|
||||
|
||||
"no_vehicle_nearby": "Man muss sich in der Nähe eines Fahrzeugs befinden, um einen Reifen aufzuschlitzen!",
|
||||
"no_tire_nearby": "Man muss nahe an einem Reifen sein, um ihn aufzuschlitzen!",
|
||||
"in_a_vehicle": "Man kann einen Reifen nicht aufschlitzen, während man sich in einem Fahrzeug befindet!",
|
||||
"is_slashing": "Du hast bereits einen Reifen aufgeschlitzt!",
|
||||
"is_dead": "Man kann einen Reifen nicht aufschlitzen, wenn man tot ist!",
|
||||
"is_handcuffed": "Man kann keinen Reifen aufschlitzen, wenn man Handschellen trägt!",
|
||||
"in_ragdoll": "Du kannst keinen Reifen aufschlitzen, wenn du in Ragdoll bist!",
|
||||
"invalid_weapon": "Du brauchst etwas Scharfes, um den Reifen aufzuschlitzen!",
|
||||
"too_far_away": "Du musst näher am Reifen sein, um ihn aufzuschlitzen!",
|
||||
"generic_fail_reason": "Du kannst jetzt keine Reifen aufschlitzen!",
|
||||
|
||||
"vehicle_is_blacklisted": "Du kannst die Reifen dieses Fahrzeugs nicht aufschlitzen!",
|
||||
"vehicle_is_emergency": "Du kannst die Reifen eines Einsatzfahrzeugs nicht aufschlitzen!",
|
||||
"tire_is_indestructible": "Dieser Reifen scheint unzerstörbar zu sein... Besser nicht einmal versuchen, diese zu zerschneiden!",
|
||||
"tire_is_track": "Du kannst keine Spuren zerschneiden, nur Reifen!",
|
||||
"tire_is_train_wheel": "Man kann keine Zugräder zerschneiden, nur die Reifen!",
|
||||
"tire_is_invisible": "In der Nähe gibt es keine Reifen zum Aufschlitzen!",
|
||||
"tire_is_punctured": "Dieser Reifen scheint bereits durchstochen zu sein!",
|
||||
"tire_is_bulletproof": "Dieser Reifen scheint schnittfest zu sein...",
|
||||
|
||||
"slash_timeout": "Das scheint dir nicht ganz gelungen zu sein!",
|
||||
"way_too_far": "Hmm ... Du scheinst den Reifen zu vermissen...",
|
||||
"weapon_broke": "Deine Waffe zerbrach, als du versucht hast, den Reifen aufzuschlitzen!"
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"target_label": "Slash Tire",
|
||||
"chat_suggestion": "Slash the closest tire of a vehicle",
|
||||
"dispatch_label": "Possible Tire Slashing",
|
||||
|
||||
"help_text_keyboard": "Press %s to Slash Tire",
|
||||
"help_text_controller": "Press %s to Slash Tire",
|
||||
|
||||
"keymapping_desc_keyboard": "Slash Tire",
|
||||
"keymapping_desc_controller": "Slash Tire - Controller",
|
||||
|
||||
"no_vehicle_nearby": "You need to be close to a vehicle to slash a tire!",
|
||||
"no_tire_nearby": "You need to be close to a tire to slash!",
|
||||
"in_a_vehicle": "You can't slash a tire while in a vehicle!",
|
||||
"is_slashing": "You are already slashing a tire!",
|
||||
"is_dead": "You can't slash a tire while dead!",
|
||||
"is_handcuffed": "You can't slash a tire while being in handcuffs!",
|
||||
"in_ragdoll": "You can't slash a tire while in ragdoll!",
|
||||
"invalid_weapon": "You need something sharp to slash the tire!",
|
||||
"too_far_away": "You need to be closer to the tire to slash it!",
|
||||
"generic_fail_reason": "You can't slash any tires right now!",
|
||||
|
||||
"vehicle_is_blacklisted": "You can't slash the tires of this vehicle!",
|
||||
"vehicle_is_emergency": "You can't slash the tires of an emergency vehicle!",
|
||||
"tire_is_indestructible": "This tire seems indestructible... Better not even attempt to slash these!",
|
||||
"tire_is_track": "You can't slash tracks, only tires!",
|
||||
"tire_is_train_wheel": "You can't slash train wheels, only tires!",
|
||||
"tire_is_invisible": "There aren't any tires nearby to slash!",
|
||||
"tire_is_punctured": "This tire seems to already be punctured!",
|
||||
"tire_is_bulletproof": "This tire seems to be slash-proof...",
|
||||
|
||||
"slash_timeout": "You didn't seem to quite hit that!",
|
||||
"way_too_far": "Hmm... You seemed to miss the tire...",
|
||||
"weapon_broke": "Your weapon broke while you attempted to slash the tire!"
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"target_label": "Kutt Dekket",
|
||||
"chat_suggestion": "Kutt det nærmeste dekket på et kjøretøy",
|
||||
"dispatch_label": "Mistenkelig Aktivitet",
|
||||
|
||||
"help_text_keyboard": "Trykk %s for å kutte dekket",
|
||||
"help_text_controller": "Trykk %s for å kutte dekket",
|
||||
|
||||
"keymapping_desc_keyboard": "Kutte Dekk",
|
||||
"keymapping_desc_controller": "Kutte Dekk - Kontroller",
|
||||
|
||||
"no_vehicle_nearby": "Du må være i nærheten av et kjøretøy for å kutte et dekk!",
|
||||
"no_tire_nearby": "Du må være i nærheten av et dekk for å kutte!",
|
||||
"in_a_vehicle": "Du kan ikke kutte et dekk menst du er inne i et kjøretøy!",
|
||||
"is_slashing": "Du kutter allerede et dekk!",
|
||||
"is_dead": "Du kan ikke kutte et dekk menst du er dø eller bevistløs!",
|
||||
"is_handcuffed": "Du kan ikke kutte et dekk menst du har hådnjern på deg!",
|
||||
"in_ragdoll": "Du kan ikke kutte et dekk menst du er i ragdoll!",
|
||||
"invalid_weapon": "Du trenger noe skarpere for å kutte dekket!",
|
||||
"too_far_away": "Du må være nærmere hjulet for å kutte dekket!",
|
||||
"generic_fail_reason": "Du kna ikke kutte dekk akkurat nå!",
|
||||
|
||||
"vehicle_is_blacklisted": "Du kan ikke kutte dekket på dette kjøretøyet!",
|
||||
"vehicle_is_emergency": "Du kan ikke kutte dekk på utrykningskjøretøy!",
|
||||
"tire_is_indestructible": "Dette dekket ser ut til å være meget solid...",
|
||||
"tire_is_track": "Du kan ikke kutte belter, kun dekk!",
|
||||
"tire_is_train_wheel": "Du kan ikke kutte toghjul, kun dekk!",
|
||||
"tire_is_invisible": "Det er ikke noen dekk i nærheten og kutte!",
|
||||
"tire_is_punctured": "Dette dekket ser ut til å være punktert!",
|
||||
"tire_is_bulletproof": "Dette dekket ser ut til å være motstandsdyktig mot kutting...",
|
||||
|
||||
"slash_timeout": "Det så ikke ut som du klarte å treffe den der!",
|
||||
"way_too_far": "Hmm... Du klarte ikke helt å treffe dekket...",
|
||||
"weapon_broke": "Våpenet ditt ser ut til å ha blitt ødelagt mens du kuttet dekket!"
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
Wow! You actually clicked on the read-me file! You are awesome!
|
||||
To start off I would like to thank you for buying the script! I really do appreciate it!
|
||||
|
||||
# Slash Tire
|
||||
|
||||
## About
|
||||
Slash Tires is a standalone script that allows players to slash the tires of vehicles.
|
||||
It is highly configurable which allows you to configure it to your needs and wants, including the disabled slashing of tires on emergency and/or specified vehicle models.
|
||||
Additionally, it uses fivem's inbuilt key mapping system to allow players to customize their key binds, both for keyboard and controllers.
|
||||
Furthermore, it supports both qTarget and qb-target if enabled in the config file. It also has server-sided checks to prevent abuse (because fuck cheaters),
|
||||
and can easily be translated to other languages if you so desire. On top of all of this, you can freely edit the source code to your heart's content.
|
||||
|
||||
I have been testing the script for quite a while, so there shouldn't be any bugs or problems. However, if you find any bugs, report them and I'll fix them ASAP!
|
||||
|
||||
## Key Features
|
||||
- Highly configurable (See Configuration)
|
||||
- Keymapping (custom key binds) for both keyboard and controllers
|
||||
- Supports both qTarget, qb-target and ox_target
|
||||
- Optimized (0.00-0.03ms)
|
||||
- Localization: You can easily translate or change the text in the config file!
|
||||
- Server-side checks to prevent abuse. (because again, fuck cheaters)
|
||||
|
||||
## Configuration
|
||||
- Look in the config.lua file.
|
||||
|
||||
## How to install
|
||||
1. Drag and drop the slashtires folder into your resources folder on your server.
|
||||
2. Add it to your start-up file (server.cfg or resources.cfg)
|
||||
3. Go into the config.lua file and change the diffrent config options to your liking (remeber to add ox_lib to the fxmanifest if you use ox)
|
||||
4. Wolla! You should now be good to go!
|
|
@ -1,237 +0,0 @@
|
|||
local TIRE_LABLES <const> = {
|
||||
[0] = "front left",
|
||||
[1] = "front right",
|
||||
[2] = "left middle",
|
||||
[3] = "right middle",
|
||||
[4] = "left rear",
|
||||
[5] = "right rear",
|
||||
[45] = "left middle #2",
|
||||
[46] = "left middle #3",
|
||||
[47] = "right middle #2",
|
||||
[48] = "right middle #3",
|
||||
}
|
||||
|
||||
---Displays a notification to the player
|
||||
---@param message string
|
||||
function DisplayNotification(serverId, message)
|
||||
TriggerClientEvent('slashtires:displayNotification', serverId, message)
|
||||
end
|
||||
|
||||
---Gets the label string for the spesifed tire index
|
||||
---@param tireIndex integer
|
||||
---@return string
|
||||
local function getTireLabel(tireIndex)
|
||||
return TIRE_LABLES[tireIndex] or string.format("unknown (%s)", tireIndex)
|
||||
end
|
||||
|
||||
---Returns if the current player weapon can slash a tire
|
||||
---@param playerPed integer
|
||||
---@return boolean canSlash
|
||||
---@return integer weaponHash
|
||||
local function canCurrentWeaponSlashTires(playerPed)
|
||||
local weaponHash = GetSelectedPedWeapon(playerPed)
|
||||
return Config.AllowedWeapons[weaponHash] ~= nil, weaponHash
|
||||
end
|
||||
|
||||
---Returns if the vehicle's model is blacklisted from getting slashed
|
||||
---@param vehicleModel integer
|
||||
---@return boolean isBlacklisted
|
||||
---@return string blacklistReason
|
||||
local function isVehicleModelBlacklisted(vehicleModel)
|
||||
local blacklistReason = Config.VehicleBlacklist[vehicleModel]
|
||||
-- NOTE: It is not possible to get the vehicle class server side, so emergency vehicles are sadly not blocked by the server :/ (but the amount of cheaters trying abusing this event is probably so low that i doesn't matter)
|
||||
return blacklistReason ~= nil, VEHICLE_BLACKLIST_REASONS[blacklistReason] or 'vehicle_is_blacklisted'
|
||||
end
|
||||
|
||||
---Checks if the ped should be given the flee task from the spesifed coords
|
||||
---@param ped integer
|
||||
---@param coords vector3
|
||||
---@return boolean canFleePed
|
||||
local function canGivePedFleeTask(ped, coords)
|
||||
local dist = #(coords - GetEntityCoords(ped))
|
||||
if dist > Config.AIReactionDistance then
|
||||
return false
|
||||
end
|
||||
|
||||
if IsPedAPlayer(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Frozen peds can't flee anyway, and they are most likley a script handled ped (for stores and robberies for example)
|
||||
if IsEntityPositionFrozen(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Ignore dead peds
|
||||
if GetEntityHealth(ped) == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
if not IsEntityVisible(ped) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Makes the nearby peds flee from the ped
|
||||
---@param coords vector3
|
||||
---@param fleePed integer The ped to flee from
|
||||
local function reactAndFleeNearbyPeds(peds, coords, fleePed)
|
||||
for index = 1, #peds do
|
||||
local ped = NetworkGetEntityFromNetworkId(peds[index])
|
||||
|
||||
if canGivePedFleeTask(ped, coords) then
|
||||
TaskReactAndFleePed(ped, fleePed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Checks if the weapon should break
|
||||
---@param weaponHash integer
|
||||
---@return boolean shouldBreak
|
||||
local function shouldWeaponBreak(weaponHash)
|
||||
if not Config.CanWeaponsBreak then
|
||||
return false
|
||||
end
|
||||
|
||||
local chanceToBreak = Config.AllowedWeapons[weaponHash].breakChance
|
||||
if not chanceToBreak then
|
||||
warn(string.format("Weapon with hash %s does not have a specified chance at breaking. Please add it in under Config.AllowedWeapons or set Config.CanWeaponsBreak to false", weaponHash))
|
||||
return false
|
||||
end
|
||||
|
||||
if chanceToBreak == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local chance = math.random(1, 1000) / 10
|
||||
if chance > chanceToBreak then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Checks and validations function for when a player wants to slash a tire
|
||||
---@param netId integer netId of the vehicle
|
||||
---@param tireIndex integer The index of the tire that was slashed
|
||||
---@param reactPeds table<integer, integer> The peds that the client belives should react to tire slashing
|
||||
---@param hasBurstedTire boolean If the client already has bursted the tire on the client side
|
||||
local function slashTire(netId, tireIndex, reactPeds, hasBurstedTire)
|
||||
local src = source
|
||||
local vehicle = NetworkGetEntityFromNetworkId(netId)
|
||||
|
||||
if vehicle == 0 then
|
||||
Log(src, 'slashtires:cheaterOrError', string.format("attempted to slash a tire of a vehicle with an invalid netId: %s", netId), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire })
|
||||
DisplayNotification(src, GetLocalization('no_vehicle_nearby'))
|
||||
return
|
||||
end
|
||||
|
||||
local entityType = GetEntityType(vehicle)
|
||||
if entityType ~= 2 then
|
||||
Log(src, 'slashtires:cheaterOrError', string.format("attempted to slash a tire of a non-vehicle entity with netId: %s", netId), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, entityType = entityType })
|
||||
DisplayNotification(src, GetLocalization('no_vehicle_nearby'))
|
||||
return
|
||||
end
|
||||
|
||||
local tireIndexType = type(tireIndex)
|
||||
if tireIndexType ~= 'number' or not TIRE_LABLES[tireIndex] then
|
||||
Log(src, 'slashtires:cheaterOrError', string.format("attempted to slash an unknown tire with index: %s (lua type: %s)", tireIndex, tireIndexType), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, tireIndexType = tireIndexType })
|
||||
DisplayNotification(src, GetLocalization('no_tire_nearby'))
|
||||
return
|
||||
end
|
||||
|
||||
local playerPed = GetPlayerPed(src)
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
local vehicleCoords = GetEntityCoords(vehicle)
|
||||
local distance = #(vehicleCoords - playerCoords)
|
||||
if distance > 15.0 then
|
||||
Log(src, 'slashtires:cheater', string.format("attempted to slash the %s tire of a vehicle that was %.2f meters away", getTireLabel(tireIndex), distance), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance })
|
||||
DisplayNotification(src, GetLocalization('too_far_away'))
|
||||
return
|
||||
end
|
||||
|
||||
local canPlayerSlash, reason = CanPlayerSlashTires(src, playerPed)
|
||||
if not canPlayerSlash and reason then
|
||||
Log(src, 'slashtires:cheaterOrError', string.format("attempted to slash the %s tire of a vehicle but was was blocked by a server bridge script (blocked reason: %s)", reason), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance, blockedReason = reason })
|
||||
DisplayNotification(src, GetLocalization(reason))
|
||||
return
|
||||
end
|
||||
|
||||
if IsPedRagdoll(playerPed) then
|
||||
Log(src, 'slashtires:cheaterOrError', "attempted to slash the %s tire of a vehicle but was blocked due to being in ragdoll", { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance })
|
||||
DisplayNotification(src, GetLocalization('in_ragdoll'))
|
||||
return
|
||||
end
|
||||
|
||||
local canWeaponSlash, weaponHash = canCurrentWeaponSlashTires(playerPed)
|
||||
if not canWeaponSlash then
|
||||
Log(src, 'slashtires:cheater', string.format("attempted to slash the %s tire of a vehicle but did not have a allowed weapon equipped (current player weapon hash: %s)", getTireLabel(tireIndex), weaponHash), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance, weaponHash = weaponHash })
|
||||
DisplayNotification(src, GetLocalization('invalid_weapon'))
|
||||
return
|
||||
end
|
||||
|
||||
local hasItem = HasWeapon(src, weaponHash)
|
||||
local weaponName = Config.AllowedWeapons[weaponHash]?.name or string.format("unknown (hash: %s)", weaponHash)
|
||||
if not hasItem then
|
||||
Log(src, 'slashtires:cheater', string.format("attempted to slash the %s tire of a vehicle but did not have the weapon item required (item needed: %s)", getTireLabel(tireIndex), weaponName), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance, weaponHash = weaponHash, weaponName = weaponName })
|
||||
DisplayNotification(src, GetLocalization('invalid_weapon'))
|
||||
return
|
||||
end
|
||||
|
||||
local vehicleModel = GetEntityModel(vehicle)
|
||||
local isBlacklisted, blacklistReason = isVehicleModelBlacklisted(vehicleModel)
|
||||
if isBlacklisted then
|
||||
Log(src, 'slashtires:cheater', string.format("attempted to slash the %s tire of a vehicle that was blacklisted (model: %s)", getTireLabel(tireIndex), vehicleModel), { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance, weaponHash = weaponHash, weaponName = weaponName, vehicleModel = vehicleModel })
|
||||
DisplayNotification(src, GetLocalization(blacklistReason))
|
||||
return
|
||||
end
|
||||
|
||||
local sendtAlert = false
|
||||
if Config.Dispatch and #reactPeds > 0 then
|
||||
local chance = math.random(0, 1000) / 10
|
||||
if chance < Config.DispatchAlertChance then
|
||||
sendtAlert = true
|
||||
SendDispatchAlert(source, playerCoords, vehicle)
|
||||
end
|
||||
end
|
||||
|
||||
if Config.AIReactAndFlee then
|
||||
reactAndFleeNearbyPeds(reactPeds, playerCoords, playerPed)
|
||||
end
|
||||
|
||||
local wasWeaponRemoved = false
|
||||
if shouldWeaponBreak(weaponHash) then
|
||||
local success = RemoveWeapon(src, weaponHash, playerPed)
|
||||
if success then
|
||||
wasWeaponRemoved = true
|
||||
end
|
||||
elseif Config.ReducedItemDurability and Config.AllowedWeapons[weaponHash]?.durability then
|
||||
local weaponBroke = ReduceDurabilityForWeapon(src, weaponHash, playerPed)
|
||||
if weaponBroke then
|
||||
wasWeaponRemoved = true
|
||||
end
|
||||
end
|
||||
|
||||
if wasWeaponRemoved then
|
||||
DisplayNotification(source, GetLocalization('weapon_broke'))
|
||||
end
|
||||
|
||||
local numberPlate = GetVehicleNumberPlateText(vehicle)
|
||||
local data = { source = src, netId = netId, tireIndex = tireIndex, hasBurstedTire = hasBurstedTire, vehicleCoords = vehicleCoords, playerCoords = playerCoords, distance = distance, weaponHash = weaponHash, weaponName = weaponName, sendtAlert = sendtAlert, weaponRemoved = wasWeaponRemoved, vehicleModel = vehicleModel, numberPlate = numberPlate }
|
||||
Log(src, 'slashtires:slashedTire', string.format("slashed the %s tire of a vehicle with plate \"%s\"", getTireLabel(tireIndex), numberPlate), data)
|
||||
|
||||
-- Event for other scripts to listen to
|
||||
TriggerEvent('slashtires:slashedTire', data)
|
||||
|
||||
-- If the tire has already been bursted by the client then there isn't any need to send any events.
|
||||
if hasBurstedTire then
|
||||
return
|
||||
end
|
||||
|
||||
local netOwner = NetworkGetEntityOwner(vehicle)
|
||||
TriggerClientEvent('slashtires:burstTire', netOwner, netId, tireIndex)
|
||||
end
|
||||
|
||||
RegisterServerEvent('slashtires:slashTire', slashTire)
|
|
@ -1,175 +0,0 @@
|
|||
---Loads a resource file provided the file path
|
||||
---@param filePath string
|
||||
---@param resourceName string|nil The resource to load the file from, uses CURRENT_RESOURCE if not spesified
|
||||
---@return table
|
||||
local function loadFile(filePath, resourceName)
|
||||
local file = LoadResourceFile(resourceName or CURRENT_RESOURCE, filePath)
|
||||
local path = string.format('%s/%s', resourceName or CURRENT_RESOURCE, filePath)
|
||||
|
||||
if not file then
|
||||
warn(string.format('No file was found with path %s', path))
|
||||
return {}
|
||||
end
|
||||
|
||||
local func, err = load(file, path)
|
||||
if not func or err then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
return func()
|
||||
end
|
||||
|
||||
---Checks if a export exist in the spesified resouce
|
||||
---@param resource string
|
||||
---@param export string
|
||||
---@return boolean
|
||||
local function doesExportExist(resource, export)
|
||||
return pcall(function()
|
||||
return exports[resource][export]
|
||||
end)
|
||||
end
|
||||
|
||||
---Force loads init.lua from ox_lib
|
||||
local function forceIncludeOxLib()
|
||||
loadFile('init.lua', 'ox_lib')
|
||||
warn("ox_lib was force included by the script, please add it to the fxmanifest if you intend to use ox_lib with this script, otherwise configure the config file differently.")
|
||||
end
|
||||
|
||||
local environment = IsDuplicityVersion() and 'server' or 'client'
|
||||
local EXPORTS <const> = {
|
||||
QB = doesExportExist('qb-core', 'GetCoreObject'),
|
||||
ESX = doesExportExist('es_extended', 'getSharedObject')
|
||||
}
|
||||
|
||||
local framework = Config.Framework
|
||||
if framework == 'auto' then
|
||||
if GetResourceState('ox_core') == 'started' then
|
||||
framework = 'ox'
|
||||
elseif EXPORTS.QB then
|
||||
framework = 'qb'
|
||||
elseif EXPORTS.ESX then
|
||||
framework = 'esx'
|
||||
elseif doesExportExist('ND_Core', 'GetCoreObject') then
|
||||
framework = 'nd'
|
||||
else
|
||||
framework = 'standalone'
|
||||
end
|
||||
end
|
||||
|
||||
-- People are stupid and don't read instructions, so let's force include ox_lib if needed.
|
||||
if (framework == 'ox' or framework == 'nd') and not lib then
|
||||
forceIncludeOxLib()
|
||||
end
|
||||
|
||||
loadFile(string.format('bridge/framework/%s/%s.lua', framework, environment))
|
||||
|
||||
---@type string|boolean
|
||||
local dispatch = Config.Dispatch
|
||||
if dispatch then
|
||||
if dispatch == 'auto' or dispatch == true then
|
||||
if GetResourceState('ps-dispatch') == 'started' then
|
||||
dispatch = 'ps'
|
||||
elseif GetResourceState('ND_MDT') == 'started' then
|
||||
dispatch = 'nd'
|
||||
elseif GetResourceState('ox_mdt') == 'started' then
|
||||
dispatch = 'ox'
|
||||
elseif doesExportExist('core_dispatch', 'addCall') then
|
||||
dispatch = 'core'
|
||||
elseif GetResourceState('rcore_dispatch') == 'started' then
|
||||
dispatch = 'rcore'
|
||||
elseif doesExportExist('qs-dispatch', 'GetPlayerInfo') then
|
||||
dispatch = 'quasar'
|
||||
else
|
||||
dispatch = false
|
||||
|
||||
-- Force disable to prevent server attempting to call on function
|
||||
Config.Dispatch = false
|
||||
end
|
||||
end
|
||||
|
||||
if dispatch then
|
||||
loadFile(string.format('bridge/dispatch/%s/%s.lua', dispatch, environment))
|
||||
end
|
||||
end
|
||||
|
||||
local inventory = Config.Inventory
|
||||
if inventory == 'auto' then
|
||||
if doesExportExist('ox_inventory', 'Items') then
|
||||
inventory = 'ox'
|
||||
elseif EXPORTS.QB then
|
||||
inventory = 'qb'
|
||||
elseif EXPORTS.ESX then
|
||||
inventory = 'esx'
|
||||
else
|
||||
inventory = 'standalone'
|
||||
end
|
||||
end
|
||||
|
||||
loadFile(string.format('bridge/inventory/%s/%s.lua', inventory, environment))
|
||||
|
||||
if environment == 'client' then
|
||||
local notification = Config.Notification
|
||||
|
||||
---@type string|boolean
|
||||
local helptext = Config.HelpText
|
||||
|
||||
---@type string|boolean
|
||||
local target = Config.Target
|
||||
|
||||
if notification then
|
||||
if notification == 'auto' then
|
||||
if doesExportExist('ox_lib', 'notify') then
|
||||
notification = 'ox'
|
||||
elseif EXPORTS.QB then
|
||||
notification = 'qb'
|
||||
elseif EXPORTS.ESX then
|
||||
notification = 'esx'
|
||||
else
|
||||
notification = 'standalone'
|
||||
end
|
||||
end
|
||||
|
||||
loadFile(string.format('bridge/notification/%s.lua', notification))
|
||||
end
|
||||
|
||||
if helptext then
|
||||
if helptext == 'auto' then
|
||||
if doesExportExist('ox_lib', 'showTextUI') then
|
||||
helptext = 'ox'
|
||||
elseif doesExportExist('qb-core', 'DrawText') then
|
||||
helptext = 'qb'
|
||||
elseif EXPORTS.ESX then
|
||||
helptext = 'esx'
|
||||
else
|
||||
helptext = 'standalone'
|
||||
end
|
||||
end
|
||||
|
||||
-- People are stupid and don't read instructions, so let's force include ox_lib if needed.
|
||||
if helptext == 'ox' and not lib then
|
||||
forceIncludeOxLib()
|
||||
end
|
||||
|
||||
loadFile(string.format('bridge/helptext/%s.lua', helptext))
|
||||
end
|
||||
|
||||
if target then
|
||||
if target == 'auto' or target == true then
|
||||
if doesExportExist('ox_target', 'addGlobalVehicle') then
|
||||
target = 'ox_target'
|
||||
elseif doesExportExist('qb-target', 'AddTargetBone') then
|
||||
target = 'qb-target'
|
||||
elseif doesExportExist('qtarget', 'AddTargetBone') then
|
||||
target = 'qtarget'
|
||||
elseif doesExportExist('bt-target', 'AddTargetModel') then
|
||||
target = 'bt-target'
|
||||
else
|
||||
target = false
|
||||
end
|
||||
end
|
||||
|
||||
if target then
|
||||
loadFile(string.format('bridge/target/%s.lua', target))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
local localization = {}
|
||||
|
||||
---Returns the the text associated with the key in the language set in the config
|
||||
---@param key string
|
||||
---@param ... any
|
||||
---@return string
|
||||
function GetLocalization(key, ...)
|
||||
local locale = localization[key]
|
||||
if not locale then
|
||||
return tostring(key)
|
||||
end
|
||||
|
||||
if ... ~= nil then
|
||||
return string.format(locale, ...)
|
||||
else
|
||||
return locale
|
||||
end
|
||||
end
|
||||
|
||||
---Attempts to load the spesifed localization file
|
||||
---@param langCode string
|
||||
---@return boolean success
|
||||
local function loadLocalizationFile(langCode)
|
||||
local jsonFile = LoadResourceFile(CURRENT_RESOURCE, string.format('locales/%s.json', langCode))
|
||||
if jsonFile == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local locales = json.decode(jsonFile)
|
||||
if locales == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
localization = locales
|
||||
return true
|
||||
end
|
||||
|
||||
---Loads the translations into a lua table for later use
|
||||
local function loadTranslations()
|
||||
local success = loadLocalizationFile(Config.Language)
|
||||
if success then
|
||||
return
|
||||
end
|
||||
|
||||
local loadedDefault = loadLocalizationFile('en')
|
||||
if loadedDefault then
|
||||
warn(string.format('The selected language "%s" (%s.json) was not able to load! en.json was loaded instead! (does the file exist in the locales folder?)', tostring(Config.Language), tostring(Config.Language)))
|
||||
else
|
||||
error(string.format('Neither the selected language "%s" (%s.json) nor en.json was able to load! This will cause major issues.', tostring(Config.Language), tostring(Config.Language)))
|
||||
end
|
||||
end
|
||||
|
||||
loadTranslations()
|
|
@ -1,21 +0,0 @@
|
|||
CURRENT_RESOURCE = GetCurrentResourceName()
|
||||
WHEEL_BONES = {
|
||||
['wheel_lf'] = 0,
|
||||
['wheel_rf'] = 1,
|
||||
['wheel_lm1'] = 2,
|
||||
['wheel_rm1'] = 3,
|
||||
['wheel_lr'] = 4,
|
||||
['wheel_rr'] = 5,
|
||||
['wheel_lm2'] = 45,
|
||||
['wheel_lm3'] = 46,
|
||||
['wheel_rm2'] = 47,
|
||||
['wheel_rm3'] = 48
|
||||
}
|
||||
VEHICLE_BLACKLIST_REASONS = {
|
||||
[1] = 'vehicle_is_blacklisted',
|
||||
[2] = 'tire_is_indestructible',
|
||||
[3] = 'vehicle_is_emergency',
|
||||
[4] = 'tire_is_track',
|
||||
[5] = 'tire_is_train_wheel',
|
||||
[6] = 'tire_is_invisible'
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue