entfernung slashtires

This commit is contained in:
Max 2025-06-15 00:12:48 +02:00
parent 5297db2a11
commit 84fa2ba04a
55 changed files with 0 additions and 2731 deletions

View file

@ -1 +0,0 @@
-- Dispatch alerts are handled on the server for core-dispatch

View file

@ -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

View file

@ -1 +0,0 @@
-- Dispatch alerts are handled on the server for ND_MDT

View file

@ -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

View file

@ -1 +0,0 @@
-- Dispatch alerts are handled on the server for ox_mdt

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -1 +0,0 @@
-- Dispatch alerts are handled on the server for rcore_dispatch

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,5 +0,0 @@
---Displays a notification to the player
---@param message string
function DisplayNotification(message)
TriggerEvent('QBCore:Notify', message, 'error')
end

View file

@ -1,7 +0,0 @@
---Displays a notification to the player
---@param message string
function DisplayNotification(message)
BeginTextCommandThefeedPost('STRING')
AddTextComponentSubstringPlayerName(message)
EndTextCommandThefeedPostTicker(false, false)
end

View file

@ -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
})

View file

@ -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
}
})

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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
}

View file

@ -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'

View file

@ -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!"
}

View file

@ -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!"
}

View file

@ -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!"
}

View file

@ -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!  

View file

@ -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)

View file

@ -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

View file

@ -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()

View file

@ -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'
}