mirror of
https://github.com/ND-Framework/ND_Core.git
synced 2026-08-17 05:56:01 +01:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1547d310eb | ||
|
|
9d4708f6d9 | ||
|
|
a7713804f0 | ||
|
|
a9785ce754 | ||
|
|
fe922e1b98 | ||
|
|
b97f42bb0a | ||
|
|
d132c12025 | ||
|
|
119b0034bf | ||
|
|
622b6fa8b0 | ||
|
|
2e6dfa9e5f | ||
|
|
4c4166de94 | ||
|
|
dea7ac6c8f | ||
|
|
120d924cae | ||
|
|
2a263a6c2e | ||
|
|
4ff4f487a1 | ||
|
|
e26821841b | ||
|
|
e9aafe1f2d | ||
|
|
6987bb63ae | ||
|
|
e0c4a8419b | ||
|
|
66f93bde14 | ||
|
|
2460df2f34 | ||
|
|
b79bb6ec7f | ||
|
|
eef1bb60f5 | ||
|
|
1320c4ab7d | ||
|
|
2c7aa5723a | ||
|
|
97a8b991ae | ||
|
|
2a3ac3b63b | ||
|
|
5d3c051149 | ||
|
|
fc82b217e9 | ||
|
|
284411ce66 | ||
|
|
a7257cf68f | ||
|
|
841a5771c5 | ||
|
|
8fd7878ba6 | ||
|
|
60e86d2038 | ||
|
|
626f0ad06f | ||
|
|
d5c3acbd81 | ||
|
|
98cba87bec | ||
|
|
001fc22ef6 | ||
|
|
87420e99e9 | ||
|
|
c5597161d9 | ||
|
|
898b9aefe9 | ||
|
|
5545650dd5 | ||
|
|
f4f01a5b1c | ||
|
|
3252118f93 | ||
|
|
9d4708a1f8 | ||
|
|
d0d04ae282 | ||
|
|
c005c1b28b | ||
|
|
590044b5d6 | ||
|
|
3146172c0c | ||
|
|
2ce47ef8d1 | ||
|
|
6258651d8b | ||
|
|
eecbc8f690 | ||
|
|
1d25b54e0f | ||
|
|
e18389a52a | ||
|
|
539e522373 | ||
|
|
2bacdd2a20 | ||
|
|
6242a44c0b | ||
|
|
74e4ccc2de | ||
|
|
2fda7655b5 | ||
|
|
ade82436a5 | ||
|
|
f512d0ed0c | ||
|
|
0a19fe8a33 | ||
|
|
2882c7c1ae | ||
|
|
6291690bd4 | ||
|
|
af82c447c1 | ||
|
|
46f4bdbd64 | ||
|
|
4870d639d4 | ||
|
|
ed895b4e6d | ||
|
|
5d2925d0c3 | ||
|
|
0500cef32f | ||
|
|
0e1fb43cd2 | ||
|
|
3260aa01f2 | ||
|
|
71a54be704 | ||
|
|
d939607d64 | ||
|
|
5cb038819c | ||
|
|
9f5bb34bdd | ||
|
|
29006870c3 | ||
|
|
a60e1b9e32 | ||
|
|
7fe7901a13 | ||
|
|
ca8f4369f6 | ||
|
|
e1d4b2fcff | ||
|
|
8b0f2b010d | ||
|
|
24e8874050 | ||
|
|
289d040b5c | ||
|
|
3f0c47c2d0 | ||
|
|
543b23a644 | ||
|
|
4b106d3688 | ||
|
|
db5c54f2d8 | ||
|
|
a1150bb821 | ||
|
|
8f7c52130a | ||
|
|
6e71142970 | ||
|
|
d9df135abb | ||
|
|
72fb153cfc |
16
README.md
16
README.md
@@ -16,9 +16,13 @@
|
||||
* [oxmysql](https://github.com/overextended/oxmysql/releases)
|
||||
* [ox_lib](https://github.com/overextended/ox_lib/releases)
|
||||
|
||||
## v2 Addons
|
||||
* [Character selection](https://github.com/ND-Framework/ND_Characters/tree/wip-v2)
|
||||
* [Banking](https://github.com/ND-Framework/ND_Banking/tree/wip-v2)
|
||||
* [Appearance shops](https://github.com/ND-Framework/ND_AppearanceShops/tree/wip-v2)
|
||||
* [Dealership](https://github.com/ND-Framework/ND_Dealership/tree/v2)
|
||||
* [Inventory](https://github.com/overextended/ox_inventory/pull/1403)
|
||||
## Addons
|
||||
* [Character selection](https://github.com/ND-Framework/ND_Characters/releases)
|
||||
* [Banking](https://github.com/ND-Framework/ND_Banking/releases)
|
||||
* [Appearance shops](https://github.com/ND-Framework/ND_AppearanceShops/releases)
|
||||
* [Dealership](https://github.com/ND-Framework/ND_Dealership/releases)
|
||||
* [Inventory](https://github.com/overextended/ox_inventory/releases)
|
||||
* [Ambulance job](https://github.com/ND-Framework/ND_Ambulance/releases)
|
||||
* [Casino](https://github.com/ND-Framework/ND_Casino/releases)
|
||||
* [Blackjack](https://github.com/ND-Framework/ND_Blackjack/releases)
|
||||
* [Nitro](https://github.com/ND-Framework/ND_Nitro/releases)
|
||||
|
||||
@@ -29,14 +29,13 @@ AddEventHandler("gameEventTriggered", function(name, args)
|
||||
local victim = args[1]
|
||||
if not IsPedAPlayer(victim) or NetworkGetPlayerIndexFromPed(victim) ~= cache.playerId then return end
|
||||
|
||||
if not IsPedDeadOrDying(victim, true) and GetEntityHealth(victim) > 0 then
|
||||
local hit, bone = GetPedLastDamageBone(victim)
|
||||
if hit and usingAmbulance then
|
||||
local damageWeapon = ambulance:getLastDamagingWeapon(victim)
|
||||
return damageWeapon and ambulance:updateBodyDamage(bone, damageWeapon)
|
||||
end
|
||||
return
|
||||
local hit, bone = GetPedLastDamageBone(victim)
|
||||
if hit and usingAmbulance then
|
||||
local damageWeapon = ambulance:getLastDamagingWeapon(victim)
|
||||
ambulance:updateBodyDamage(bone, damageWeapon)
|
||||
end
|
||||
|
||||
if not IsPedDeadOrDying(victim, true) or GetEntityHealth(victim) > 100 then return end
|
||||
|
||||
local killerEntity, deathCause = GetPedSourceOfDeath(cache.ped), GetPedCauseOfDeath(cache.ped)
|
||||
local killerClientId = NetworkGetPlayerIndexFromPed(killerEntity)
|
||||
|
||||
@@ -22,5 +22,54 @@ RegisterNetEvent("ND:updateLastLocation", function(location)
|
||||
end)
|
||||
|
||||
RegisterNetEvent("ND:revivePlayer", function()
|
||||
NDCore.revivePlayer(true)
|
||||
if source == "" then return end
|
||||
local oldPed = cache.ped
|
||||
local veh = GetVehiclePedIsIn(oldPed)
|
||||
local seat = cache.seat
|
||||
local coords = GetEntityCoords(oldPed)
|
||||
local armor = GetPedArmour(oldPed)
|
||||
|
||||
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(oldPed), true, true, false)
|
||||
|
||||
local ped = PlayerPedId()
|
||||
if oldPed ~= ped then
|
||||
DeleteEntity(oldPed)
|
||||
ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false)
|
||||
end
|
||||
|
||||
SetEntityInvincible(ped, false)
|
||||
FreezeEntityPosition(ped, false)
|
||||
SetEntityVisible(ped, true)
|
||||
SetEveryoneIgnorePlayer(ped, false)
|
||||
SetPedCanBeTargetted(ped, true)
|
||||
SetEntityCanBeDamaged(ped, true)
|
||||
SetBlockingOfNonTemporaryEvents(ped, false)
|
||||
SetPedCanRagdollFromPlayerImpact(ped, true)
|
||||
ClearPedTasksImmediately(ped)
|
||||
SetPedArmour(ped, armor)
|
||||
|
||||
if veh and veh ~= 0 then
|
||||
SetPedIntoVehicle(ped, veh, seat)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent("ND:characterUnloaded")
|
||||
|
||||
RegisterNetEvent("ND:clothingMenu", function()
|
||||
if GetResourceState("fivem-appearance") ~= "started" then return end
|
||||
|
||||
local function customize(appearance)
|
||||
if not appearance then return end
|
||||
TriggerServerEvent("ND:updateClothing", appearance)
|
||||
end
|
||||
|
||||
exports["fivem-appearance"]:startPlayerCustomization(customize, {
|
||||
ped = false,
|
||||
headBlend = true,
|
||||
faceFeatures = true,
|
||||
headOverlays = true,
|
||||
components = true,
|
||||
props = true,
|
||||
tattoos = true
|
||||
})
|
||||
end)
|
||||
|
||||
@@ -26,56 +26,15 @@ function NDCore.getPlayersFromCoords(distance, coords)
|
||||
return closePlayers
|
||||
end
|
||||
|
||||
function NDCore.revivePlayer(reset, keepDead)
|
||||
local usingAmbulance = GetResourceState("ND_Ambulance") == "started"
|
||||
if not keepDead then
|
||||
LocalPlayer.state.dead = false
|
||||
if usingAmbulance then
|
||||
local state = Player(cache.serverId).state
|
||||
state:set("isDead", false, true)
|
||||
end
|
||||
end
|
||||
|
||||
local veh = GetVehiclePedIsIn(cache.ped)
|
||||
local seat = cache.seat
|
||||
local coords = GetEntityCoords(cache.ped)
|
||||
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(cache.ped), true, true, false)
|
||||
|
||||
local ped = PlayerPedId()
|
||||
if cache.ped ~= ped then
|
||||
DeleteEntity(cache.ped)
|
||||
ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false)
|
||||
end
|
||||
|
||||
SetEntityInvincible(ped, false)
|
||||
FreezeEntityPosition(ped, false)
|
||||
SetEntityVisible(ped, true)
|
||||
SetEveryoneIgnorePlayer(ped, false)
|
||||
SetPedCanBeTargetted(ped, true)
|
||||
SetEntityCanBeDamaged(ped, true)
|
||||
SetBlockingOfNonTemporaryEvents(ped, false)
|
||||
SetPedCanRagdollFromPlayerImpact(ped, true)
|
||||
ClearPedTasksImmediately(ped)
|
||||
|
||||
if veh and veh ~= 0 then
|
||||
SetPedIntoVehicle(ped, veh, seat)
|
||||
end
|
||||
if reset and GetPedMovementClipset(ped) == `move_m@injured` then
|
||||
ClearEntityLastDamageEntity(ped)
|
||||
SetPedMoveRateOverride(ped, 1.0)
|
||||
ResetPedMovementClipset(ped, 0)
|
||||
end
|
||||
if reset and usingAmbulance then
|
||||
exports["ND_Ambulance"]:resetBodyDamage()
|
||||
function NDCore.getConfig(info)
|
||||
if not info then
|
||||
return Config
|
||||
end
|
||||
return Config[info]
|
||||
end
|
||||
|
||||
function NDCore.notify(...)
|
||||
if GetResourceState("ModernHUD") == "started" then
|
||||
exports["ModernHUD"]:notify(...)
|
||||
elseif GetResourceState("ox_lib") == "started" then
|
||||
lib.notify(...)
|
||||
end
|
||||
lib.notify(...)
|
||||
end
|
||||
|
||||
for name, func in pairs(NDCore) do
|
||||
|
||||
@@ -7,14 +7,16 @@ Config = {
|
||||
discordAsset = GetConvar("core:discordAsset", "andyyy"),
|
||||
discordAssetSmall = GetConvar("core:discordAssetSmall", "andyyy"),
|
||||
discordActionText = GetConvar("core:discordActionText", "DISCORD"),
|
||||
discordActionLink = GetConvar("discordActionLink", "https://discord.gg/Z9Mxu72zZ6"),
|
||||
discordActionLink = GetConvar("core:discordActionLink", "https://discord.gg/Z9Mxu72zZ6"),
|
||||
discordActionText2 = GetConvar("core:discordActionText2", "STORE"),
|
||||
discordActionLink2 = GetConvar("core:discordActionLink2", "https://andyyy.tebex.io/category/fivem-scripts"),
|
||||
randomUnlockedVehicleChance = GetConvarInt("core:randomUnlockedVehicleChance", 30),
|
||||
disableVehicleAirControl = GetConvarInt("core:disableVehicleAirControl", 1) == 1,
|
||||
randomUnlockedVehicleChance = GetConvarInt("core:randomUnlockedVehicleChance", 30),
|
||||
requireKeys = GetConvarInt("core:requireKeys", 1) == 1,
|
||||
useInventoryForKeys = GetConvarInt("core:useInventoryForKeys", 1) == 1,
|
||||
groups = json.decode(GetConvar("core:groups", "[]")),
|
||||
compatibility = json.decode(GetConvar("core:compatibility", "[]"))
|
||||
compatibility = json.decode(GetConvar("core:compatibility", "[]")),
|
||||
lockpickTries = GetConvarInt("core:lockpickTries", 3)
|
||||
}
|
||||
|
||||
-- Discord rich presence.
|
||||
|
||||
@@ -218,10 +218,10 @@ end)
|
||||
RegisterCommand("getclothing", function(source, args, rawCommand)
|
||||
local info = ""
|
||||
for k, v in pairs(clothingComponents) do
|
||||
info = ("%s\n%s = {\n drawable = %s,\n texture = %s\n},"):format(info, k, GetPedDrawableVariation(cache.ped, v), GetPedTextureVariation(cache.ped, v))
|
||||
info = ("%s\n%s = { drawable = %s, texture = %s },"):format(info, k, GetPedDrawableVariation(cache.ped, v), GetPedTextureVariation(cache.ped, v))
|
||||
end
|
||||
for k, v in pairs(clothingProps) do
|
||||
info = ("%s\n%s = {\n drawable = %s,\n texture = %s\n},"):format(info, k, GetPedPropIndex(cache.ped, v), GetPedPropTextureIndex(cache.ped, v))
|
||||
info = ("%s\n%s = { drawable = %s, texture = %s },"):format(info, k, GetPedPropIndex(cache.ped, v), GetPedPropTextureIndex(cache.ped, v))
|
||||
end
|
||||
lib.setClipboard(info)
|
||||
end, false)
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
return {
|
||||
{
|
||||
garageType = "land",
|
||||
groups = {"lsfd"},
|
||||
ped = vector4(370.9027, -593.8090, 28.8681, 73.6009),
|
||||
vehicleSpawns = {
|
||||
vec4(366.7840, -591.4883, 28.7261, 339.6823),
|
||||
vec4(365.0753, -582.8641, 28.7156, 135.0064),
|
||||
vec4(357.4239, -604.7719, 28.6767, 177.1355),
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "land",
|
||||
groups = {"sahp", "lspd", "bcso"},
|
||||
@@ -240,4 +250,52 @@ return {
|
||||
vector4(216.56, -801.90, 30.79, 69.39)
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "land",
|
||||
ped = vector4(587.5941, 2744.2844, 42.0691, 181.0514),
|
||||
vehicleSpawns = {
|
||||
vector4(584.3921, 2721.3599, 41.6483, 184.3260),
|
||||
vector4(577.1069, 2736.2322, 41.6097, 184.6912),
|
||||
vector4(577.9459, 2721.0010, 41.6481, 185.1414),
|
||||
vector4(574.1685, 2735.7288, 41.6397, 184.5562)
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "land",
|
||||
ped = vector4(2746.1726, 3458.7378, 55.8272, 245.1009),
|
||||
vehicleSpawns = {
|
||||
vector4(2768.2136, 3456.2710, 55.2840, 67.7897),
|
||||
vector4(2759.3218, 3451.1448, 55.4786, 248.0150),
|
||||
vector4(2763.6526, 3445.0544, 55.4741, 66.9754),
|
||||
vector4(2787.2947, 3467.1001, 54.9407, 247.4356),
|
||||
vector4(2773.9514, 3471.6238, 55.0407, 246.8264)
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "land",
|
||||
ped = vector4(120.4042, 6623.5190, 31.9593, 228.8283),
|
||||
vehicleSpawns = {
|
||||
vector4(155.9047, 6593.3252, 31.4343, 359.3789),
|
||||
vector4(155.7900, 6602.6978, 31.4463, 358.8232),
|
||||
vector4(145.8267, 6614.0996, 31.4007, 178.7948),
|
||||
vector4(145.6977, 6602.8950, 31.4397, 181.0616),
|
||||
vector4(132.4042, 6585.2139, 31.5501, 91.0906)
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "heli",
|
||||
groups = {"lspd"},
|
||||
ped = vector4(465.6194, -985.4730, 43.6918, 0.8591),
|
||||
vehicleSpawns = {
|
||||
vector4(449.3105, -981.1057, 44.0788, 359.6042)
|
||||
}
|
||||
},
|
||||
{
|
||||
garageType = "heli",
|
||||
groups = {"lsfd"},
|
||||
ped = vector4(339.6271, -581.0325, 74.1656, 267.8232),
|
||||
vehicleSpawns = {
|
||||
vector4(351.3463, -588.1304, 74.1698, 108.5617)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,6 +293,7 @@ AddStateBagChangeHandler("props", nil, function(bagName, key, value, reserved, r
|
||||
lib.setVehicleProperties(entity, props)
|
||||
end)
|
||||
|
||||
local playingKey = 0
|
||||
local function playKeyFob(veh)
|
||||
local keyFob
|
||||
local ped = cache.ped
|
||||
@@ -300,12 +301,21 @@ local function playKeyFob(veh)
|
||||
if #(coords-GetEntityCoords(veh)) > 25.0 then return end
|
||||
|
||||
if not playerVehicle then
|
||||
playingKey += 1
|
||||
SetPedCurrentWeaponVisible(ped, false, false)
|
||||
ClearPedTasks(ped)
|
||||
lib.requestAnimDict("anim@mp_player_intmenu@key_fob@")
|
||||
TaskPlayAnim(ped, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false)
|
||||
keyFob = CreateObject(`lr_prop_carkey_fob`, 0, 0, 0, true, true, true)
|
||||
AttachEntityToEntity(keyFob, ped, GetPedBoneIndex(ped, 0xDEAD), 0.12, 0.04, -0.025, -100.0, 100.0, 0.0, true, true, false, true, 1, true)
|
||||
Wait(700)
|
||||
SetTimeout(400, function()
|
||||
playingKey -= 1
|
||||
end)
|
||||
SetTimeout(1200, function()
|
||||
if playingKey > 0 then return end
|
||||
SetPedCurrentWeaponVisible(ped, true, false)
|
||||
end)
|
||||
end
|
||||
|
||||
PlaySoundFromEntity(-1, "Remote_Control_Fob", ped, "PI_Menu_Sounds", true, 0)
|
||||
@@ -346,8 +356,9 @@ AddStateBagChangeHandler("locked", nil, function(bagName, key, value, reserved,
|
||||
end)
|
||||
end)
|
||||
|
||||
lib.callback.register("ND_Vehicles:getProps", function(netId)
|
||||
local veh = getVehFromNetId(netId)
|
||||
local function getProps(veh)
|
||||
if not veh or not DoesEntityExist(veh) then return end
|
||||
|
||||
local props = lib.getVehicleProperties(veh)
|
||||
local colorPrimary, colorSecondary = GetVehicleColours(veh)
|
||||
if not props then return end
|
||||
@@ -358,7 +369,18 @@ lib.callback.register("ND_Vehicles:getProps", function(netId)
|
||||
props.className = vehicleClassNames[GetVehicleClass(veh)]
|
||||
props.makeName = GetLabelText(GetMakeNameFromVehicleModel(props.model))
|
||||
props.modelName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
|
||||
|
||||
return props
|
||||
end
|
||||
|
||||
lib.callback.register("ND_Vehicles:getProps", function(netId)
|
||||
local veh = getVehFromNetId(netId)
|
||||
return getProps(veh)
|
||||
end)
|
||||
|
||||
lib.callback.register("ND_Vehicles:getPropsFromCurrentVeh", function()
|
||||
local veh = GetVehiclePedIsIn(cache.ped)
|
||||
return getProps(veh)
|
||||
end)
|
||||
|
||||
lib.callback.register("ND_Vehicles:getVehicleModelMakeLabel", function(model)
|
||||
@@ -470,22 +492,35 @@ CreateThread(function()
|
||||
local wait = 500
|
||||
while true do
|
||||
Wait(wait)
|
||||
|
||||
local reset = true
|
||||
playerVehicle = cache.seat == -1 and cache.vehicle
|
||||
if playerVehicle then
|
||||
if Config.disableVehicleAirControl and not vehicleClassNotDisableAirControl[GetVehicleClass(playerVehicle)] and (IsEntityInAir(playerVehicle) or IsEntityUpsidedown(playerVehicle)) then
|
||||
wait = 0
|
||||
DisableControlAction(0, 59) -- disable vehicle air control.
|
||||
DisableControlAction(0, 60)
|
||||
elseif not GetIsVehicleEngineRunning(playerVehicle) and not hasVehicleKeysCheck(playerVehicle) then
|
||||
wait = 0
|
||||
DisableControlAction(0, 59)
|
||||
if DoesEntityExist(playerVehicle) and IsVehicleEngineStarting(playerVehicle) then
|
||||
SetVehicleEngineOn(playerVehicle, false, true, true) -- don't turn on engine if no keys.
|
||||
end
|
||||
else
|
||||
wait = 500
|
||||
|
||||
local entering = GetVehiclePedIsEntering(cache.ped)
|
||||
if entering and DoesEntityExist(entering) and IsVehicleNeedsToBeHotwired(entering) then
|
||||
SetVehicleNeedsToBeHotwired(entering, false)
|
||||
end
|
||||
|
||||
if not playerVehicle then goto skip end
|
||||
|
||||
if Config.disableVehicleAirControl and not vehicleClassNotDisableAirControl[GetVehicleClass(playerVehicle)] and (IsEntityInAir(playerVehicle) or IsEntityUpsidedown(playerVehicle)) then
|
||||
wait = 0
|
||||
reset = false
|
||||
DisableControlAction(0, 59) -- disable vehicle air control.
|
||||
DisableControlAction(0, 60)
|
||||
end
|
||||
if Config.requireKeys and not GetIsVehicleEngineRunning(playerVehicle) and not hasVehicleKeysCheck(playerVehicle) then
|
||||
wait = 0
|
||||
reset = false
|
||||
DisableControlAction(0, 59)
|
||||
DisableControlAction(0, 71)
|
||||
if DoesEntityExist(playerVehicle) and IsVehicleEngineStarting(playerVehicle) then
|
||||
SetVehicleEngineOn(playerVehicle, false, true, true) -- don't turn on engine if no keys.
|
||||
end
|
||||
elseif wait ~= 500 then
|
||||
end
|
||||
|
||||
::skip::
|
||||
if (reset or not playerVehicle) and wait ~= 500 then
|
||||
wait = 500
|
||||
end
|
||||
end
|
||||
@@ -574,7 +609,7 @@ local function lockpickVehicle()
|
||||
}
|
||||
|
||||
lib.requestAnimDict("veh@break_in@0h@p_m_one@")
|
||||
for i=1, 7 do
|
||||
for i=1, Config.lockpickTries do
|
||||
TaskPlayAnimAdvanced(cache.ped, "veh@break_in@0h@p_m_one@", "std_force_entry_ds", pos.x, pos.y, pos.z+0.025, rot.x, rot.y, rot.z, 8.0, 8.0, 1800, 28, 0.1)
|
||||
local dificulty = dificulties[math.random(1, #dificulties)]
|
||||
local success = lib.skillCheck(dificulty)
|
||||
@@ -697,9 +732,14 @@ lib.addKeybind({
|
||||
})
|
||||
end
|
||||
if not playerVehicle then return end
|
||||
|
||||
local speed = math.floor(GetEntitySpeed(playerVehicle) * 2.236936)
|
||||
if speed < 10 then return end
|
||||
|
||||
cruiseControlEnabled = true
|
||||
cruiseSpeedVehicle = math.floor(GetEntitySpeed(playerVehicle) * 2.236936)
|
||||
cruiseSpeedVehicle = speed
|
||||
cruiseSpeedSet = cruiseSpeedVehicle
|
||||
|
||||
lib.notify({
|
||||
title = "Cruise control",
|
||||
description = ("Set to %d mph."):format(math.floor(cruiseSpeedSet)),
|
||||
|
||||
@@ -5,13 +5,32 @@ exports("GetCoreObject", function()
|
||||
end)
|
||||
|
||||
NDCore.Functions = {}
|
||||
NDCore.Functions.GetPlayer = NDCore.getPlayer
|
||||
NDCore.Functions.GetPlayers = NDCore.getPlayers
|
||||
NDCore.Functions.GetUserDiscordInfo = NDCore.getDiscordInfo
|
||||
NDCore.Functions.SetActiveCharacter = NDCore.setActiveCharacter
|
||||
NDCore.Functions.GetPlayerCharacters = NDCore.fetchAllCharacters
|
||||
NDCore.Functions.GetPlayerByCharacterId = NDCore.fetchCharacter
|
||||
|
||||
function NDCore.Functions.GetPlayer(src)
|
||||
local player = NDCore.getPlayer(src)
|
||||
return {
|
||||
source = player.source,
|
||||
id = player.id,
|
||||
firstName = player.firstname,
|
||||
lastName = player.lastname,
|
||||
dob = player.dob,
|
||||
gender = player.gender,
|
||||
cash = player.cash,
|
||||
bank = player.bank,
|
||||
phoneNumber = player.metadata.phone,
|
||||
lastLocation = player.metadata.lastLocation,
|
||||
inventory = player.inventory,
|
||||
discordInfo = player.discordInfo,
|
||||
data = player.metadata,
|
||||
job = player.job
|
||||
}
|
||||
end
|
||||
|
||||
function NDCore.Functions.GetPlayerIdentifierFromType(identifierType, src)
|
||||
return GetPlayerIdentifierByType(src, identifierType)
|
||||
end
|
||||
|
||||
@@ -60,7 +60,7 @@ function NDCore.GetPlayerData()
|
||||
|
||||
player.coords = GetEntityCoords(cache.ped)
|
||||
player.loadout = {}
|
||||
player.maxWeight = exports.ox_inventory:GetPlayerMaxWeight()
|
||||
player.maxWeight = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:GetPlayerMaxWeight() or 0
|
||||
player.money = player.Accounts.Money
|
||||
player.sex = player.gender
|
||||
player.firstName = player.firstname
|
||||
@@ -112,7 +112,7 @@ function NDCore.Progressbar(message, lenght, options)
|
||||
end
|
||||
|
||||
function NDCore.SearchInventory(item, count)
|
||||
local itemCount = exports.ox_inventory:Search(item)
|
||||
local itemCount = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:Search(item) or 0
|
||||
return itemCount >= count and itemCount
|
||||
end
|
||||
|
||||
@@ -133,7 +133,7 @@ function NDCore.ShowHelpNotification()
|
||||
end
|
||||
|
||||
function NDCore.ShowInventory()
|
||||
exports.ox_inventory:openInventory("player", cache.serverId)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:openInventory("player", cache.serverId)
|
||||
end
|
||||
|
||||
function NDCore.ShowNotification(msg, type, time)
|
||||
|
||||
@@ -5,7 +5,8 @@ local registeredItems = {}
|
||||
|
||||
local function getAmmoFromWeapon(weapon)
|
||||
if not weapon then return end
|
||||
for item, data in pairs(exports.ox_inventory:Items()) do
|
||||
local items = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:Items() or {}
|
||||
for item, data in pairs(items) do
|
||||
if data.weapon and data.model and data.model:lower() == weapon:lower() then
|
||||
return data.ammoname
|
||||
end
|
||||
@@ -60,7 +61,7 @@ local function createPlayerFunctions(self)
|
||||
end
|
||||
|
||||
function self.addInventoryItem(item, count)
|
||||
exports.ox_inventory:AddItem(self.source, item, count)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:AddItem(self.source, item, count)
|
||||
end
|
||||
|
||||
function self.addMoney(amount)
|
||||
@@ -100,11 +101,11 @@ local function createPlayerFunctions(self)
|
||||
end
|
||||
|
||||
function self.canCarryItem(item, count)
|
||||
return exports.ox_inventory:CanCarryItem(self.source, item, count)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:CanCarryItem(self.source, item, count)
|
||||
end
|
||||
|
||||
function self.canSwapItem(firstItem, firstItemCount, testItem, testItemCount)
|
||||
exports.ox_inventory:CanSwapItem(self.source, firstItem, firstItemCount, testItem, testItemCount)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:CanSwapItem(self.source, firstItem, firstItemCount, testItem, testItemCount)
|
||||
end
|
||||
|
||||
function self.clearMeta(index)
|
||||
@@ -137,7 +138,7 @@ local function createPlayerFunctions(self)
|
||||
end
|
||||
|
||||
function self.getInventory(minimal)
|
||||
local playerItems = exports.ox_inventory:GetInventoryItems(self.source)
|
||||
local playerItems = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:GetInventoryItems(self.source) or {}
|
||||
if not minimal then
|
||||
return playerItems
|
||||
end
|
||||
@@ -145,7 +146,7 @@ local function createPlayerFunctions(self)
|
||||
end
|
||||
|
||||
function self.getInventoryItem(item)
|
||||
local playerItems = exports.ox_inventory:GetInventoryItems(self.source)
|
||||
local playerItems = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:GetInventoryItems(self.source) or {}
|
||||
for name, data in pairs(playerItems) do
|
||||
if name == item then
|
||||
return data
|
||||
@@ -162,11 +163,11 @@ local function createPlayerFunctions(self)
|
||||
end
|
||||
|
||||
function self.hasItem(item, metadata)
|
||||
return exports.ox_inventory:GetItem(self.source, item, metadata)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:GetItem(self.source, item, metadata)
|
||||
end
|
||||
|
||||
function self.removeInventoryItem(item, count)
|
||||
exports.ox_inventory:RemoveItem(self.source, item, count)
|
||||
return GetResourceState("ox_inventory") == "started" and exports.ox_inventory:RemoveItem(self.source, item, count)
|
||||
end
|
||||
|
||||
function self.removeMoney(amount)
|
||||
@@ -304,7 +305,8 @@ end
|
||||
function NDCore.GetItemLabel(item)
|
||||
if not itemNames then
|
||||
itemNames = {}
|
||||
for item, data in pairs(exports.ox_inventory:Items()) do
|
||||
local items = GetResourceState("ox_inventory") == "started" and exports.ox_inventory:Items() or {}
|
||||
for item, data in pairs(items) do
|
||||
itemNames[item] = data.label
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
||||
|
||||
config = {
|
||||
serverName = "Andy's Development",
|
||||
characterLimit = 15, -- How many characters can a player create.
|
||||
customPauseMenu = true, -- A custom pause menu will display your money, characters name and the server name in the pause menu.
|
||||
enablePVP = true, -- pvp allows doing damage to other players.
|
||||
|
||||
-- Money related
|
||||
startingCash = 2500, -- default cash the character will start with if the character creator doesn't specify it.
|
||||
startingBank = 8000,-- default money in the bank account the character will start with if the character creator doesn't specify it.
|
||||
|
||||
-- If you'd like to whitelist certain roles on discord then set this to true and add role ids.
|
||||
enableDiscordWhitelist = false,
|
||||
notWhitelistedMessage = "You're not allowlisted in this server please join our discord to apply for a allowlist: https://discord.gg/Z9Mxu72zZ6",
|
||||
whitelistRoles = {
|
||||
"872921520719142932"
|
||||
},
|
||||
|
||||
-- These are admins roles that will give a user permission to admin commands and more.
|
||||
adminRoles = {
|
||||
"872921520719142932"
|
||||
},
|
||||
|
||||
-- Discord Rich presence
|
||||
enableRichPresence = true,
|
||||
updateIntervall = 60, -- how many seconds of delay until it updates status.
|
||||
appId = 858146067018416128,
|
||||
largeLogo = "andyyy",
|
||||
smallLogo = "andyyy",
|
||||
firstButtonName = "DISCORD",
|
||||
firstButtonLink = "https://discord.gg/Z9Mxu72zZ6",
|
||||
secondButtonName = "TEBEX",
|
||||
secondButtonLink = "https://andyyy.tebex.io/category/fivem-scripts",
|
||||
|
||||
|
||||
-- Groups can be gangs, jobs, subdivisions, etc.
|
||||
groups = {
|
||||
["Ballas"] = {
|
||||
"Member", -- rank 1
|
||||
"Boss" -- rank 2
|
||||
},
|
||||
["SWAT"] = {
|
||||
"Member", -- rank 1
|
||||
"Sniper", -- rank 2
|
||||
"Team lead", -- rank 3
|
||||
"Commander" -- rank 4
|
||||
},
|
||||
["SAHP"] = {
|
||||
"Trooper",
|
||||
"Senior Trooper",
|
||||
"Corporal",
|
||||
"Sergeant",
|
||||
"Lieutenant",
|
||||
"Cheif"
|
||||
},
|
||||
["LSPD"] = {
|
||||
"Officer",
|
||||
"Senior officer",
|
||||
"Corporal",
|
||||
"Sergeant",
|
||||
"Lieutenant",
|
||||
"Cheif"
|
||||
},
|
||||
["BCSO"] = {
|
||||
"Deputy",
|
||||
"Senior Deputy",
|
||||
"Corporal",
|
||||
"Sergeant",
|
||||
"Lieutenant",
|
||||
"Cheif"
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
||||
|
||||
server_config = {
|
||||
discordServerToken = "OTAwODg1MDMxMDQ2Nzc0ODQ1.GU1TSC.Ed8D2_wcU-UQ1vZhe1khahgV8J3hLahOp4N1D8", -- discord bot token for permissions
|
||||
guildId = "872496972454592523", -- discord guild id
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
CREATE TABLE IF NOT EXISTS `nd_characters` (
|
||||
`charid` INT(10) NOT NULL AUTO_INCREMENT,
|
||||
`identifier` VARCHAR(200) NOT NULL DEFAULT '0',
|
||||
`name` VARCHAR(50) DEFAULT NULL,
|
||||
`firstname` VARCHAR(50) DEFAULT NULL,
|
||||
`lastname` VARCHAR(50) DEFAULT NULL,
|
||||
`dob` VARCHAR(50) DEFAULT NULL,
|
||||
`gender` VARCHAR(50) DEFAULT NULL,
|
||||
`cash` INT(10) DEFAULT '0',
|
||||
`bank` INT(10) DEFAULT '0',
|
||||
`groups` LONGTEXT DEFAULT '[]',
|
||||
`metadata` LONGTEXT DEFAULT '[]',
|
||||
`inventory` LONGTEXT DEFAULT '[]',
|
||||
PRIMARY KEY (`charid`) USING BTREE
|
||||
`charid` INT(10) NOT NULL AUTO_INCREMENT,
|
||||
`identifier` VARCHAR(200) NOT NULL DEFAULT '0',
|
||||
`name` VARCHAR(50) DEFAULT NULL,
|
||||
`firstname` VARCHAR(50) DEFAULT NULL,
|
||||
`lastname` VARCHAR(50) DEFAULT NULL,
|
||||
`dob` VARCHAR(50) DEFAULT NULL,
|
||||
`gender` VARCHAR(50) DEFAULT NULL,
|
||||
`cash` INT(10) DEFAULT '0',
|
||||
`bank` INT(10) DEFAULT '0',
|
||||
`phonenumber` VARCHAR(20) DEFAULT NULL,
|
||||
`groups` LONGTEXT DEFAULT ('[]'),
|
||||
`metadata` LONGTEXT DEFAULT ('[]'),
|
||||
`inventory` LONGTEXT DEFAULT ('[]'),
|
||||
PRIMARY KEY (`charid`) USING BTREE
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
CREATE TABLE IF NOT EXISTS `nd_vehicles` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`owner` INT(11) DEFAULT NULL,
|
||||
`plate` VARCHAR(255) DEFAULT NULL,
|
||||
`glovebox` LONGTEXT DEFAULT '[]',
|
||||
`trunk` LONGTEXT DEFAULT '[]',
|
||||
`properties` LONGTEXT DEFAULT '[]',
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`owner` INT(11) DEFAULT NULL,
|
||||
`plate` VARCHAR(255) DEFAULT NULL,
|
||||
`glovebox` LONGTEXT DEFAULT ('[]'),
|
||||
`trunk` LONGTEXT DEFAULT ('[]'),
|
||||
`properties` LONGTEXT DEFAULT ('[]'),
|
||||
`stored` INT(11) DEFAULT '1',
|
||||
`impounded` INT(11) DEFAULT '0',
|
||||
`stolen` INT(11) DEFAULT '0',
|
||||
`metadata` LONGTEXT DEFAULT '[]',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `owner` (`owner`) USING BTREE,
|
||||
CONSTRAINT `vehowner` FOREIGN KEY (`owner`) REFERENCES `nd_characters` (`charid`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
`impounded` INT(11) DEFAULT '0',
|
||||
`stolen` INT(11) DEFAULT '0',
|
||||
`metadata` LONGTEXT DEFAULT ('[]'),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `owner` (`owner`) USING BTREE,
|
||||
CONSTRAINT `vehowner` FOREIGN KEY (`owner`) REFERENCES `nd_characters` (`charid`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
author "Andyyy#7666"
|
||||
description "ND Framework Core"
|
||||
version "2.0.0"
|
||||
version "2.3.0"
|
||||
|
||||
fx_version "cerulean"
|
||||
game "gta5"
|
||||
@@ -37,6 +37,11 @@ files {
|
||||
"compatibility/**/locale.lua"
|
||||
}
|
||||
|
||||
dependency "oxmysql"
|
||||
dependenies {
|
||||
"ox_lib",
|
||||
"oxmysql"
|
||||
}
|
||||
|
||||
-- below were used with backwards compatibility but could interfere with resources checking if the resources are started.
|
||||
-- provide "es_extended"
|
||||
-- provide "qb-Core"
|
||||
|
||||
@@ -15,7 +15,7 @@ local moneyActions = {
|
||||
}
|
||||
|
||||
lib.addCommand("setmoney", {
|
||||
help = "Admin command, manage player money.",
|
||||
help = "Admin command, set a players money.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
@@ -164,7 +164,7 @@ lib.addCommand("setgroup", {
|
||||
end)
|
||||
|
||||
lib.addCommand("skin", {
|
||||
help = "Admin command, set player into character clothing menu.",
|
||||
help = "Admin command, show character clothing menu for player.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
@@ -178,7 +178,7 @@ lib.addCommand("skin", {
|
||||
end)
|
||||
|
||||
lib.addCommand("character", {
|
||||
help = "Admin command, set player into character selection menu.",
|
||||
help = "Admin command, show character selection menu for player.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
@@ -194,27 +194,50 @@ end)
|
||||
lib.addCommand("pay", {
|
||||
help = "give money to nearby player.",
|
||||
params = {
|
||||
{
|
||||
name = "target",
|
||||
type = "playerId",
|
||||
help = "Target player's server id"
|
||||
},
|
||||
{
|
||||
name = "amount",
|
||||
type = "number"
|
||||
type = "number",
|
||||
help = "Amount of cash to give"
|
||||
}
|
||||
}
|
||||
}, function(source, args, raw)
|
||||
if not source then return end
|
||||
local targetPlayer
|
||||
local pedCoords = GetEntityCoords(GetPlayerPed(source))
|
||||
for targetId, targetInfo in pairs(NDCore.players) do
|
||||
local targetCoords = GetEntityCoords(GetPlayerPed(targetId))
|
||||
if #(pedCoords-targetCoords) < 2.0 and targetId ~= source then
|
||||
targetPlayer = targetInfo
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local player = NDCore.getPlayer(source)
|
||||
if not player then return end
|
||||
local success = player.deductMoney("cash", args.amount)
|
||||
local targetPlayer = NDCore.getPlayer(args.target)
|
||||
|
||||
if not player or not targetPlayer then
|
||||
return player.notify({
|
||||
title = "Error",
|
||||
description = "No player found",
|
||||
type = "error"
|
||||
})
|
||||
end
|
||||
|
||||
if player.cash < args.amount then
|
||||
return player.notify({
|
||||
title = "Error",
|
||||
description = "You don't have enough cash",
|
||||
type = "error"
|
||||
})
|
||||
end
|
||||
|
||||
local playerCoords = GetEntityCoords(GetPlayerPed(player.source))
|
||||
local targetCoords = GetEntityCoords(GetPlayerPed(targetPlayer.source))
|
||||
if #(playerCoords-targetCoords) > 2.0 then
|
||||
return player.notify({
|
||||
title = "Error",
|
||||
description = "Player is not nearby",
|
||||
type = "error"
|
||||
})
|
||||
end
|
||||
|
||||
local success = player.deductMoney("cash", args.amount) and targetPlayer.addMoney("cash", args.amount)
|
||||
if not success then
|
||||
return player.notify({
|
||||
title = "Couldn't give money",
|
||||
@@ -223,55 +246,38 @@ lib.addCommand("pay", {
|
||||
})
|
||||
end
|
||||
|
||||
if not targetPlayer or not targetPlayer.addMoney("cash", args.amount) then return end
|
||||
targetPlayer.notify({
|
||||
title = "Money received",
|
||||
description = ("Received $%d in cash"):format(args.amount),
|
||||
type = "inform",
|
||||
duration = 10000
|
||||
duration = 5000
|
||||
})
|
||||
|
||||
player.notify({
|
||||
title = "Money given",
|
||||
description = ("You gave someone $%d in cash"):format(args.amount),
|
||||
description = ("You gave $%d in cash"):format(args.amount),
|
||||
type = "inform",
|
||||
duration = 10000
|
||||
duration = 5000
|
||||
})
|
||||
end)
|
||||
|
||||
lib.addCommand("unlock", {
|
||||
help = "Admin force unlock vehicles",
|
||||
help = "Admin Command, force unlock a vehicle.",
|
||||
restricted = "group.admin",
|
||||
}, function(source, args, raw)
|
||||
local ped = GetPlayerPed(source)
|
||||
local playerVeh = GetVehiclePedIsIn(ped)
|
||||
local coords = GetEntityCoords(ped)
|
||||
local vehicles = GetAllVehicles()
|
||||
local maxDistance = 2.0
|
||||
local closestVehicle
|
||||
local veh = lib.getClosestVehicle(coords, 2.5, true)
|
||||
|
||||
if not playerVeh or playerVeh == 0 or not DoesEntityExist(playerVeh) then
|
||||
for i=1, #vehicles do
|
||||
local vehicle = vehicles[i]
|
||||
local vehicleCoords = GetEntityCoords(vehicle)
|
||||
local distance = #(coords-vehicleCoords)
|
||||
|
||||
if distance < maxDistance then
|
||||
maxDistance = distance
|
||||
closestVehicle = vehicle
|
||||
end
|
||||
end
|
||||
if not closestVehicle or not DoesEntityExist(closestVehicle) then return end
|
||||
local state = Entity(closestVehicle).state
|
||||
state.locked = false
|
||||
else
|
||||
local state = Entity(playerVeh).state
|
||||
state.hotwired = true
|
||||
end
|
||||
if not veh then return end
|
||||
|
||||
local state = Entity(veh).state
|
||||
state.hotwired = true
|
||||
state.locked = false
|
||||
end)
|
||||
|
||||
lib.addCommand("revive", {
|
||||
help = "Admin command, revive player.",
|
||||
help = "Admin command, revive a player.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
@@ -287,60 +293,48 @@ lib.addCommand("revive", {
|
||||
end)
|
||||
|
||||
lib.addCommand("dv", {
|
||||
help = "Admin command, delete vehicles within the range.",
|
||||
help = "Admin command, delete vehicles within the range or the closest.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
name = "range",
|
||||
type = "number",
|
||||
help = "The range to select vehicles for deleteion from",
|
||||
help = "Range to delete vehicles in",
|
||||
optional = true
|
||||
}
|
||||
}
|
||||
}, function(source, args, raw)
|
||||
local ped = GetPlayerPed(source)
|
||||
local veh = GetVehiclePedIsIn(ped)
|
||||
if veh and veh ~= 0 and DoesEntityExist(veh) then
|
||||
DeleteEntity(veh)
|
||||
return TriggerClientEvent("chat:addMessage", source, {
|
||||
color = {50, 100, 235},
|
||||
multiline = true,
|
||||
args = {"Staff action", "deleted 1 vehicle"}
|
||||
})
|
||||
end
|
||||
|
||||
local count = 0
|
||||
local coords = GetEntityCoords(ped)
|
||||
local count = 0
|
||||
local message = nil
|
||||
local veh = lib.getClosestVehicle(coords, 3.0)
|
||||
|
||||
if args.range then
|
||||
for _, veh in ipairs(GetAllVehicles()) do
|
||||
local vehDist = #(GetEntityCoords(veh) - coords)
|
||||
if vehDist < args.range then
|
||||
DeleteEntity(veh)
|
||||
count += 1
|
||||
end
|
||||
local vehicles = lib.getNearbyVehicles(coords, args.range)
|
||||
count = #vehicles
|
||||
|
||||
for i=1, count do
|
||||
local veh = vehicles[i]
|
||||
DeleteEntity(veh.vehicle)
|
||||
end
|
||||
return TriggerClientEvent("chat:addMessage", source, {
|
||||
color = {50, 100, 235},
|
||||
multiline = true,
|
||||
args = {"Staff action", ("deleted %d vehicles"):format(count)}
|
||||
})
|
||||
elseif veh then
|
||||
DeleteEntity(veh)
|
||||
count = 1
|
||||
end
|
||||
|
||||
local closest, dist
|
||||
for _, veh in ipairs(GetAllVehicles()) do
|
||||
local vehDist = #(GetEntityCoords(veh) - coords)
|
||||
if vehDist < 5.0 and not closest or (dist and dist > vehDist) then
|
||||
closest = veh
|
||||
dist = vehDist
|
||||
end
|
||||
if count == 0 then
|
||||
message = {"Staff action [dv]", "no vehicles found"}
|
||||
elseif count == 1 then
|
||||
message = {"Staff action [dv]", "deleted 1 vehicle"}
|
||||
else
|
||||
message = {"Staff action [dv]", ("deleted %d vehicles"):format(count)}
|
||||
end
|
||||
|
||||
if not closest then return "no vehicle found nearby" end
|
||||
DeleteEntity(closest)
|
||||
TriggerClientEvent("chat:addMessage", source, {
|
||||
color = {50, 100, 235},
|
||||
multiline = true,
|
||||
args = {"Staff action", "deleted 1 vehicle"}
|
||||
args = message
|
||||
})
|
||||
end)
|
||||
|
||||
@@ -411,7 +405,7 @@ lib.addCommand("unfreeze", {
|
||||
end)
|
||||
|
||||
lib.addCommand("vehicle", {
|
||||
help = "Admin command, unfreeze a player.",
|
||||
help = "Admin command, spawn a vehicle.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
@@ -444,3 +438,45 @@ lib.addCommand("vehicle", {
|
||||
Wait(100)
|
||||
end
|
||||
end)
|
||||
|
||||
lib.addCommand("claim-veh", {
|
||||
help = "Admin command, add a copy of the vehicle you're inside to players garage.",
|
||||
restricted = "group.admin",
|
||||
params = {
|
||||
{
|
||||
name = "target",
|
||||
type = "playerId",
|
||||
help = "Target player's server id"
|
||||
}
|
||||
}
|
||||
}, function(source, args, raw)
|
||||
local player = NDCore.getPlayer(source)
|
||||
if not player then return end
|
||||
|
||||
local targetPlayer = NDCore.getPlayer(args.target)
|
||||
if not targetPlayer then
|
||||
return player.notify({
|
||||
title = "Player not found!",
|
||||
description = "Target player not found, make sure they select a charcter!",
|
||||
type = "error"
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
local properties = lib.callback.await("ND_Vehicles:getPropsFromCurrentVeh", source)
|
||||
if not properties then
|
||||
return player.notify({
|
||||
title = "Vehicle data not found!",
|
||||
description = "The vehicle properties data was not found!",
|
||||
type = "error"
|
||||
})
|
||||
end
|
||||
|
||||
NDCore.setVehicleOwned(targetPlayer.id, properties, true)
|
||||
|
||||
player.notify({
|
||||
title = "Vehicle added!",
|
||||
description = ("The vehicle has now been added to %s's garage!"):format(targetPlayer.name),
|
||||
type = "success"
|
||||
})
|
||||
end)
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
||||
|
||||
-- Check if discord is connected, and if whitelist is enabled then it will only allow you to join if you have the roles.
|
||||
AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
|
||||
local player = source
|
||||
local discordIdentifier = NDCore.Functions.GetPlayerIdentifierFromType("discord", player)
|
||||
|
||||
deferrals.defer()
|
||||
Wait(0)
|
||||
deferrals.update("Connecting to discord.")
|
||||
Wait(0)
|
||||
|
||||
if not discordIdentifier then
|
||||
deferrals.done("Your discord isn't connected to FiveM, make sure discord is open and restart FiveM.")
|
||||
else
|
||||
if config.enableDiscordWhitelist then
|
||||
local discordUserId = discordIdentifier:gsub("discord:", "")
|
||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
||||
for _, whitelistRole in pairs(config.whitelistRoles) do
|
||||
if whitelistRole == 0 or whitelistRole == "0" or (discordInfo and discordInfo.roles[whitelistRole]) then
|
||||
deferrals.done()
|
||||
break
|
||||
end
|
||||
end
|
||||
deferrals.done(config.notWhitelistedMessage)
|
||||
else
|
||||
deferrals.done()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Getting all the characters the player has and returning them to the client.
|
||||
RegisterNetEvent("ND:GetCharacters", function()
|
||||
local player = source
|
||||
TriggerClientEvent("ND:returnCharacters", player, NDCore.Functions.GetPlayerCharacters(player))
|
||||
end)
|
||||
|
||||
-- Creating a new character.
|
||||
RegisterNetEvent("ND:newCharacter", function(newCharacter)
|
||||
local player = source
|
||||
NDCore.Functions.CreateCharacter(player, newCharacter.firstName, newCharacter.lastName, newCharacter.dob, newCharacter.gender, newCharacter.cash, newCharacter.bank)
|
||||
end)
|
||||
|
||||
-- Update the character info when edited.
|
||||
RegisterNetEvent("ND:editCharacter", function(newCharacter)
|
||||
local player = source
|
||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
||||
if not characters[newCharacter.id] then return end
|
||||
NDCore.Functions.UpdateCharacterData(newCharacter.id, newCharacter.firstName, newCharacter.lastName, newCharacter.dob, newCharacter.gender)
|
||||
end)
|
||||
|
||||
-- Delete character from database.
|
||||
RegisterNetEvent("ND:deleteCharacter", function(characterId)
|
||||
local player = source
|
||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
||||
if not characters[characterId] then return end
|
||||
NDCore.Functions.DeleteCharacter(characterId)
|
||||
end)
|
||||
|
||||
-- add a player to the table.
|
||||
RegisterNetEvent("ND:setCharacterOnline", function(id)
|
||||
local player = source
|
||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
||||
if not characters[id] then return end
|
||||
NDCore.Functions.SetActiveCharacter(player, id)
|
||||
end)
|
||||
|
||||
-- Update the characters clothes.
|
||||
RegisterNetEvent("ND:updateClothes", function(clothing)
|
||||
local player = source
|
||||
local character = NDCore.Players[player]
|
||||
NDCore.Functions.SetPlayerData(character.id, "clothing", clothing)
|
||||
end)
|
||||
|
||||
-- Disconnecting a player
|
||||
RegisterNetEvent("ND:exitGame", function()
|
||||
local player = source
|
||||
DropPlayer(player, "Disconnected.")
|
||||
end)
|
||||
|
||||
-- Remove player from NDCore.Players table when they leave.
|
||||
AddEventHandler("playerDropped", function()
|
||||
local player = source
|
||||
local character = NDCore.Players[player]
|
||||
if character then
|
||||
local ped = GetPlayerPed(player)
|
||||
local lastLocation = GetEntityCoords(ped)
|
||||
NDCore.Functions.UpdateLastLocation(character.id, {x = lastLocation.x, y = lastLocation.y, z = lastLocation.z})
|
||||
end
|
||||
TriggerEvent("ND:characterUnloaded", player, character)
|
||||
character = nil
|
||||
end)
|
||||
|
||||
-- Get player discord info on join.
|
||||
AddEventHandler("playerJoining", function()
|
||||
local src = source
|
||||
|
||||
local discordUserId = NDCore.Functions.GetPlayerIdentifierFromType("discord", src):gsub("discord:", "")
|
||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
||||
|
||||
NDCore.PlayersDiscordInfo[src] = discordInfo
|
||||
end)
|
||||
|
||||
AddEventHandler("onResourceStart", function(resourceName)
|
||||
if (GetCurrentResourceName() ~= resourceName) then
|
||||
return
|
||||
end
|
||||
Wait(1000)
|
||||
|
||||
if not next(NDCore.PlayersDiscordInfo) then
|
||||
for _, playerId in ipairs(GetPlayers()) do
|
||||
local discordUserId = NDCore.Functions.GetPlayerIdentifierFromType("discord", playerId):gsub("discord:", "")
|
||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
||||
NDCore.PlayersDiscordInfo[tonumber(playerId)] = discordInfo
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -1,3 +1,10 @@
|
||||
function NDCore.getPlayerIdentifierByType(src, indentifierType)
|
||||
if Config.sv_lan then
|
||||
return ("%s:sv_lan"):format(indentifierType)
|
||||
end
|
||||
return GetPlayerIdentifierByType(src, indentifierType)
|
||||
end
|
||||
|
||||
---@param src number
|
||||
---@return table
|
||||
function NDCore.getPlayer(src)
|
||||
@@ -34,6 +41,13 @@ function NDCore.getPlayerServerInfo(source)
|
||||
return PlayersInfo[source]
|
||||
end
|
||||
|
||||
function NDCore.getConfig(info)
|
||||
if not info then
|
||||
return Config
|
||||
end
|
||||
return Config[info]
|
||||
end
|
||||
|
||||
---@param fileLocation string|tabale
|
||||
---@return boolean
|
||||
function NDCore.loadSQL(fileLocation, resource)
|
||||
|
||||
@@ -7,6 +7,7 @@ local tempPlayersInfo = {}
|
||||
Config = {
|
||||
serverName = GetConvar("core:serverName", "Unconfigured ND-Core Server"),
|
||||
discordInvite = GetConvar("core:discordInvite", "https://discord.gg/Z9Mxu72zZ6"),
|
||||
discordMemeberRequired = GetConvarInt("core:discordMemeberRequired", 1) == 1,
|
||||
discordAppId = GetConvar("core:discordAppId", "858146067018416128"),
|
||||
discordAsset = GetConvar("core:discordAsset", "andyyy"),
|
||||
discordAssetSmall = GetConvar("core:discordAssetSmall", "andyyy"),
|
||||
@@ -23,8 +24,10 @@ Config = {
|
||||
groups = json.decode(GetConvar("core:groups", "[]")),
|
||||
admins = json.decode(GetConvar("core:admins", "[]")),
|
||||
adminDiscordRoles = json.decode(GetConvar("core:adminDiscordRoles", "[]")),
|
||||
groupRoles = json.decode(GetConvar("core:groupRoles", "[]")),
|
||||
multiCharacter = false,
|
||||
compatibility = json.decode(GetConvar("core:compatibility", "[]"))
|
||||
compatibility = json.decode(GetConvar("core:compatibility", "[]")),
|
||||
sv_lan = GetConvar("sv_lan", "false") == "true",
|
||||
}
|
||||
|
||||
SetConvarServerInfo("Discord", Config.discordInvite)
|
||||
@@ -41,13 +44,23 @@ local function getIdentifierList(src)
|
||||
list[identifierType] = identifier
|
||||
end
|
||||
end
|
||||
|
||||
if Config.sv_lan then
|
||||
list[Config.characterIdentifier] = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
|
||||
end
|
||||
|
||||
return list
|
||||
end
|
||||
|
||||
AddEventHandler("playerJoining", function(oldId)
|
||||
local src = source
|
||||
PlayersInfo[src] = tempPlayersInfo[oldId]
|
||||
tempPlayersInfo[oldId] = nil
|
||||
local oldTempId = tonumber(oldId)
|
||||
PlayersInfo[src] = tempPlayersInfo[oldTempId]
|
||||
tempPlayersInfo[oldTempId] = nil
|
||||
|
||||
if Config.sv_lan then
|
||||
lib.addPrincipal(("player.%s"):format(src), "group.admin")
|
||||
end
|
||||
|
||||
if Config.multiCharacter then return end
|
||||
Wait(3000)
|
||||
@@ -93,14 +106,14 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
|
||||
local tempSrc = source
|
||||
local identifiers = getIdentifierList(tempSrc)
|
||||
local mainIdentifier = identifiers[Config.characterIdentifier]
|
||||
local discordInfo = {}
|
||||
local discordInfo = nil
|
||||
|
||||
deferrals.defer()
|
||||
Wait(0)
|
||||
|
||||
if mainIdentifier and Config.discordBotToken ~= "false" and Config.discordGuildId ~= "false" and not discordInfo then
|
||||
if mainIdentifier and Config.discordBotToken ~= "false" and Config.discordGuildId ~= "false" then
|
||||
discordInfo = checkDiscordIdentifier(identifiers)
|
||||
if not discordInfo then
|
||||
if not discordInfo and Config.discordMemeberRequired and not Config.sv_lan then
|
||||
deferrals.done(("Your discord was not found, join our discord here: %s."):format(Config.discordInvite))
|
||||
Wait(0)
|
||||
end
|
||||
@@ -109,6 +122,17 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
|
||||
deferrals.update("Connecting...")
|
||||
Wait(0)
|
||||
|
||||
if Config.sv_lan then
|
||||
tempPlayersInfo[tempSrc] = {
|
||||
identifiers = {
|
||||
[Config.characterIdentifier] = "sv_lan"
|
||||
},
|
||||
discord = discordInfo
|
||||
}
|
||||
deferrals.done()
|
||||
return
|
||||
end
|
||||
|
||||
if mainIdentifier then
|
||||
tempPlayersInfo[tempSrc] = {
|
||||
identifiers = identifiers,
|
||||
@@ -152,3 +176,10 @@ RegisterNetEvent("ND:playerEliminated", function(info)
|
||||
deathInfo = info
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNetEvent("ND:updateClothing", function(clothing)
|
||||
local src = source
|
||||
local player = NDCore.getPlayer(src)
|
||||
if not player or not clothing or type(clothing) ~= "table" then return end
|
||||
player.setMetadata("clothing", clothing)
|
||||
end)
|
||||
|
||||
@@ -25,6 +25,7 @@ local function createCharacterTable(info)
|
||||
gender = info.gender,
|
||||
cash = info.cash,
|
||||
bank = info.bank,
|
||||
phonenumber = info.phonenumber,
|
||||
groups = info.groups,
|
||||
metadata = info.metadata,
|
||||
inventory = info.inventory
|
||||
@@ -112,7 +113,8 @@ local function createCharacterTable(info)
|
||||
TriggerEvent("ND:moneyChange", self.source, key, value, "set", reason)
|
||||
end
|
||||
end
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), key)
|
||||
TriggerEvent("ND:updateCharacter", self, key)
|
||||
end
|
||||
|
||||
---@param key string|table
|
||||
@@ -126,7 +128,8 @@ local function createCharacterTable(info)
|
||||
else
|
||||
self.metadata[key] = value
|
||||
end
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
|
||||
TriggerEvent("ND:updateCharacter", self, "metadata")
|
||||
return self.metadata
|
||||
end
|
||||
|
||||
@@ -164,8 +167,23 @@ local function createCharacterTable(info)
|
||||
end
|
||||
|
||||
-- Save character information to database
|
||||
function self.save()
|
||||
local affectedRows = MySQL.update.await("UPDATE nd_characters SET name = ?, firstname = ?, lastname = ?, dob = ?, gender = ?, cash = ?, bank = ?, groups = ?, metadata = ? WHERE charid = ?", {
|
||||
function self.save(key)
|
||||
if key then
|
||||
local charData = self[key]
|
||||
if not charData or type(charData) == "function" then
|
||||
return lib.print.error(key, "Is not valid character data.")
|
||||
end
|
||||
|
||||
if type(charData) == "table" then
|
||||
charData = json.encode(charData)
|
||||
end
|
||||
|
||||
local query = ("UPDATE nd_characters SET `%s` = ? WHERE charid = ?"):format(key)
|
||||
local affectedRows = MySQL.update.await(query, {charData, self.id})
|
||||
return affectedRows > 0
|
||||
end
|
||||
|
||||
local affectedRows = MySQL.update.await("UPDATE nd_characters SET name = ?, firstname = ?, lastname = ?, dob = ?, gender = ?, cash = ?, bank = ?, phonenumber = ?, `groups` = ?, metadata = ? WHERE charid = ?", {
|
||||
self.name,
|
||||
self.firstname,
|
||||
self.lastname,
|
||||
@@ -173,6 +191,7 @@ local function createCharacterTable(info)
|
||||
self.gender,
|
||||
self.cash,
|
||||
self.bank,
|
||||
self.phonenumber,
|
||||
json.encode(self.groups),
|
||||
json.encode(self.metadata),
|
||||
self.id
|
||||
@@ -206,7 +225,8 @@ local function createCharacterTable(info)
|
||||
else
|
||||
self.metadata.licenses = {license}
|
||||
end
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
|
||||
TriggerEvent("ND:updateCharacter", self, "metadata")
|
||||
end
|
||||
|
||||
function self.getLicense(identifier)
|
||||
@@ -252,11 +272,7 @@ local function createCharacterTable(info)
|
||||
|
||||
function self.notify(...)
|
||||
if not self.source then return end
|
||||
if GetResourceState("ModernHUD") == "started" then
|
||||
TriggerClientEvent("ModernHUD:notify", self.source, ...)
|
||||
elseif GetResourceState("ox_lib") == "started" then
|
||||
TriggerClientEvent("ox_lib:notify", self.source, ...)
|
||||
end
|
||||
TriggerClientEvent("ox_lib:notify", self.source, ...)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -293,6 +309,12 @@ local function createCharacterTable(info)
|
||||
self.addGroup("admin")
|
||||
end
|
||||
end
|
||||
|
||||
for group, role in pairs(Config.groupRoles) do
|
||||
if lib.table.contains(roles, role) then
|
||||
self.addGroup(group)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for name, _ in pairs(self.groups) do
|
||||
@@ -307,23 +329,38 @@ local function createCharacterTable(info)
|
||||
---@param rank number
|
||||
---@param isJob boolean
|
||||
---@return boolean
|
||||
function self.addGroup(name, rank, isJob)
|
||||
function self.addGroup(name, rank, customGroup, isJob)
|
||||
local groupRank = tonumber(rank) or 1
|
||||
local groupInfo = Config.groups[name]
|
||||
-- if not groupInfo then return end
|
||||
local groupInfo = lib.table.deepclone(Config.groups?[name] or {})
|
||||
local bossRank = groupInfo?.minimumBossRank
|
||||
|
||||
for k, v in pairs(customGroup or {}) do
|
||||
groupInfo[k] = v
|
||||
end
|
||||
|
||||
if isJob then
|
||||
for _, group in pairs(self.groups) do
|
||||
group.isJob = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.groups[name] = {
|
||||
label = groupInfo and groupInfo.label or name,
|
||||
rankName = groupInfo and groupInfo.ranks[groupRank] or groupRank,
|
||||
name = name,
|
||||
label = groupInfo?.label or name,
|
||||
rankName = groupInfo?.ranks?[groupRank] or groupRank,
|
||||
rank = groupRank,
|
||||
isJob = isJob
|
||||
isJob = isJob,
|
||||
isBoss = bossRank and groupRank >= bossRank,
|
||||
metadata = groupInfo.metadata or {}
|
||||
}
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
|
||||
|
||||
if not isJob then
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
|
||||
TriggerEvent("ND:updateCharacter", self, "groups")
|
||||
end
|
||||
|
||||
lib.addPrincipal(self.source, ("group.%s"):format(name))
|
||||
|
||||
return self.groups[name]
|
||||
end
|
||||
|
||||
@@ -337,8 +374,16 @@ local function createCharacterTable(info)
|
||||
function self.removeGroup(name)
|
||||
local group = self.groups[name]
|
||||
if not group then return end
|
||||
|
||||
if self.job == name then
|
||||
self.job = nil
|
||||
self.jobInfo = nil
|
||||
end
|
||||
|
||||
self.groups[name] = nil
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
|
||||
TriggerEvent("ND:updateCharacter", self, "groups")
|
||||
TriggerEvent("ND:groupRemoved", self, group)
|
||||
lib.removePrincipal(self.source, ("group.%s"):format(name))
|
||||
return group
|
||||
end
|
||||
@@ -348,12 +393,13 @@ local function createCharacterTable(info)
|
||||
---@return boolean
|
||||
function self.setJob(name, rank)
|
||||
self.removeGroup(self.job)
|
||||
local job = self.addGroup(name, rank, true)
|
||||
local jobName, jobInfo = self.getJob()
|
||||
if jobInfo then
|
||||
self.job = jobName
|
||||
self.jobInfo = jobInfo
|
||||
local job = self.addGroup(name, rank, nil, true)
|
||||
if job then
|
||||
self.job = job.name
|
||||
self.jobInfo = job
|
||||
end
|
||||
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "job")
|
||||
TriggerEvent("ND:updateCharacter", self, "job")
|
||||
return job
|
||||
end
|
||||
|
||||
@@ -380,7 +426,7 @@ end
|
||||
---@param info table
|
||||
---@return table
|
||||
function NDCore.newCharacter(src, info)
|
||||
local identifier = GetPlayerIdentifierByType(src, Config.characterIdentifier)
|
||||
local identifier = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
|
||||
if not identifier then return end
|
||||
|
||||
local charInfo = {
|
||||
@@ -393,12 +439,13 @@ function NDCore.newCharacter(src, info)
|
||||
gender = info.gender or "",
|
||||
cash = info.cash or 0,
|
||||
bank = info.bank or 0,
|
||||
phonenumber = info.phonenumber,
|
||||
groups = info.groups or {},
|
||||
metadata = info.metadata or {},
|
||||
inventory = info.inventory or {},
|
||||
inventory = info.inventory or {}
|
||||
}
|
||||
|
||||
charInfo.id = MySQL.insert.await("INSERT INTO nd_characters (identifier, name, firstname, lastname, dob, gender, cash, bank, groups, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", {
|
||||
charInfo.id = MySQL.insert.await("INSERT INTO nd_characters (identifier, name, firstname, lastname, dob, gender, cash, bank, phonenumber, `groups`, metadata, inventory) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", {
|
||||
identifier,
|
||||
charInfo.name,
|
||||
charInfo.firstname,
|
||||
@@ -407,8 +454,10 @@ function NDCore.newCharacter(src, info)
|
||||
charInfo.gender,
|
||||
charInfo.cash,
|
||||
charInfo.bank,
|
||||
charInfo.phonenumber,
|
||||
json.encode(charInfo.groups),
|
||||
json.encode(charInfo.metadata)
|
||||
json.encode(charInfo.metadata),
|
||||
json.encode(charInfo.inventory)
|
||||
})
|
||||
|
||||
return createCharacterTable(charInfo)
|
||||
@@ -419,7 +468,7 @@ end
|
||||
function NDCore.fetchCharacter(id, src)
|
||||
local result
|
||||
if src then
|
||||
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ? and identifier = ?", {id, GetPlayerIdentifierByType(src, Config.characterIdentifier)})
|
||||
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ? and identifier = ?", {id, NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)})
|
||||
else
|
||||
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ?", {id})
|
||||
end
|
||||
@@ -437,6 +486,7 @@ function NDCore.fetchCharacter(id, src)
|
||||
gender = info.gender,
|
||||
cash = info.cash,
|
||||
bank = info.bank,
|
||||
phonenumber = info.phonenumber,
|
||||
groups = json.decode(info.groups),
|
||||
metadata = json.decode(info.metadata),
|
||||
inventory = json.decode(info.inventory)
|
||||
@@ -447,7 +497,7 @@ end
|
||||
---@return table
|
||||
function NDCore.fetchAllCharacters(src)
|
||||
local characters = {}
|
||||
local result = MySQL.query.await("SELECT * FROM nd_characters WHERE identifier = ?", {GetPlayerIdentifierByType(src, Config.characterIdentifier)})
|
||||
local result = MySQL.query.await("SELECT * FROM nd_characters WHERE identifier = ?", {NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)})
|
||||
|
||||
for i=1, #result do
|
||||
local info = result[i]
|
||||
@@ -462,9 +512,10 @@ function NDCore.fetchAllCharacters(src)
|
||||
gender = info.gender,
|
||||
cash = info.cash,
|
||||
bank = info.bank,
|
||||
phonenumber = info.phonenumber,
|
||||
groups = json.decode(info.groups),
|
||||
metadata = json.decode(info.metadata),
|
||||
inventory = json.decode(info.inventory),
|
||||
inventory = json.decode(info.inventory)
|
||||
})
|
||||
end
|
||||
return characters
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local ox_inventory
|
||||
local inventoryStarted = false
|
||||
local spawnedPlayerVehicles = {}
|
||||
local vehicleTypes = json.decode(GetResourceKvpString("ND_Core:vehTypes") or "[]")
|
||||
|
||||
NDCore.isResourceStarted("ox_inventory", function(started)
|
||||
inventoryStarted = started
|
||||
@@ -8,16 +9,24 @@ NDCore.isResourceStarted("ox_inventory", function(started)
|
||||
ox_inventory = exports.ox_inventory
|
||||
end)
|
||||
|
||||
local function getVehicleType(model)
|
||||
local tempVehicle = CreateVehicle(model, 0, 0, 0, 0, true, true)
|
||||
local function getVehicleType(coords, model)
|
||||
if vehicleTypes[model] then
|
||||
return vehicleTypes[model]
|
||||
end
|
||||
|
||||
local tempVehicle = CreateVehicle(model, coords.x, coords.y, coords.z-5.0, coords.w, true, false)
|
||||
local time = os.time()
|
||||
while not DoesEntityExist(tempVehicle) and time-os.time() < 5 do Wait(5) end
|
||||
|
||||
|
||||
while not DoesEntityExist(tempVehicle) and os.time()-time < 5 do Wait(0) end
|
||||
if not DoesEntityExist(tempVehicle) then return end
|
||||
local entityType = GetVehicleType(tempVehicle)
|
||||
|
||||
local vehType = GetVehicleType(tempVehicle)
|
||||
DeleteEntity(tempVehicle)
|
||||
return entityType
|
||||
|
||||
vehicleTypes[model] = vehType
|
||||
SetResourceKvp("ND_Core:vehTypes", json.encode(vehicleTypes))
|
||||
|
||||
return vehType
|
||||
end
|
||||
|
||||
local function generatePlate()
|
||||
@@ -90,18 +99,35 @@ function NDCore.getVehicle(entity)
|
||||
if saveProperties and self.id and self.owner then
|
||||
local properties = lib.callback.await("ND_Vehicles:getProps", NetworkGetEntityOwner(entity), self.netId)
|
||||
if properties then
|
||||
if self.properties?.callsign then
|
||||
properties.callsign = true
|
||||
end
|
||||
MySQL.query("UPDATE nd_vehicles SET properties = ? WHERE id = ?", {json.encode(properties), self.id})
|
||||
end
|
||||
end
|
||||
DeleteEntity(entity)
|
||||
end
|
||||
|
||||
|
||||
-- remvoe vehicle from db.
|
||||
function self.remove(keepEntity)
|
||||
if not keepEntity and DoesEntityExist(entity) then
|
||||
DeleteEntity(entity)
|
||||
end
|
||||
MySQL.query("DELETE FROM nd_vehicles WHERE id = ?", {self.id})
|
||||
end
|
||||
|
||||
--- set vehicle properties
|
||||
---@param props table
|
||||
function self.setProperties(props)
|
||||
if not DoesEntityExist(entity) then return end
|
||||
local properties = type(props) == "string" and json.decode(props) or props
|
||||
local state = Entity(entity).state
|
||||
|
||||
if self.properties?.callsign then
|
||||
properties.callsign = true
|
||||
end
|
||||
|
||||
state.props = properties
|
||||
self.properties = properties
|
||||
|
||||
@@ -148,13 +174,22 @@ function NDCore.getVehicle(entity)
|
||||
|
||||
function self.setMetadata(key, value)
|
||||
self.metadata[key] = value
|
||||
|
||||
if DoesEntityExist(entity) then
|
||||
local state = Entity(self.entity).state
|
||||
local metadata = state.metadata
|
||||
metadata[key] = value
|
||||
state.metadata = metadata
|
||||
|
||||
if not state.metadata then
|
||||
state.metadata = self.metadata
|
||||
else
|
||||
state.metadata[key] = value
|
||||
end
|
||||
end
|
||||
if not self.id or not self.owner then return end
|
||||
|
||||
if not self.id or not self.owner then
|
||||
lib.print.debug(('Skipped storing metadata for vehicle %s as it does not have an id/owner associated with it.'):format(self.entity))
|
||||
return
|
||||
end
|
||||
|
||||
MySQL.query("UPDATE nd_vehicles SET metadata = ? WHERE id = ?", {json.encode(self.metadata), self.id})
|
||||
end
|
||||
|
||||
@@ -245,14 +280,14 @@ function NDCore.createVehicle(info)
|
||||
end
|
||||
|
||||
local model = info.model or properties.model
|
||||
local vehType = getVehicleType(model)
|
||||
local vehType = getVehicleType(spawnCoords, model)
|
||||
if not vehType then
|
||||
return Citizen.Trace("NDCore.createVehicle", "vehType not found")
|
||||
end
|
||||
|
||||
local veh = CreateVehicleServerSetter(model, vehType, spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w)
|
||||
local time = os.time()
|
||||
while not DoesEntityExist(veh) and time-os.time() < 5 do Wait(5) end
|
||||
while not DoesEntityExist(veh) and os.time()-time < 5 do Wait(5) end
|
||||
if not veh or not DoesEntityExist(veh) then
|
||||
return Citizen.Trace("NDCore.createVehicle", "vehicle entity doesn't exist")
|
||||
end
|
||||
@@ -403,14 +438,31 @@ function NDCore.spawnOwnedVehicle(source, vehicleId, coords, heading)
|
||||
if not player then return end
|
||||
|
||||
local vehicle = NDCore.getVehicleById(vehicleId)
|
||||
if not vehicle or not vehicle.available or vehicle.owner ~= player.id then return end
|
||||
if not vehicle or vehicle.owner ~= player.id then return end
|
||||
if not vehicle.available and not vehicle.impounded then return end
|
||||
|
||||
MySQL.query.await("UPDATE nd_vehicles SET stored = ? WHERE id = ?", {0, vehicleId})
|
||||
|
||||
local properties = vehicle.properties
|
||||
if properties.callsign then
|
||||
local callsign = player.getMetadata("callsign")
|
||||
if not callsign or callsign == "" then goto skip end
|
||||
|
||||
callsign = tostring(callsign)
|
||||
if not callsign or callsign:len() ~= 3 then goto skip end
|
||||
|
||||
properties.modFender = tonumber(callsign:sub(1, 1))
|
||||
properties.modRightFender = tonumber(callsign:sub(2, 2))
|
||||
properties.modRoof = tonumber(callsign:sub(3, 3))
|
||||
end
|
||||
|
||||
::skip::
|
||||
|
||||
return NDCore.createVehicle({
|
||||
owner = player.id,
|
||||
model = vehicle.properties.model,
|
||||
model = properties.model,
|
||||
coords = vec4(coords.x, coords.y, coords.z, coords.w or coords.heading or heading),
|
||||
properties = vehicle.properties,
|
||||
properties = properties,
|
||||
vehicleId = vehicleId,
|
||||
source = source
|
||||
})
|
||||
@@ -567,12 +619,24 @@ RegisterNetEvent("ND_Vehicles:toggleVehicleLock", function(netId)
|
||||
end)
|
||||
|
||||
-- locking of npc vehicles, if the players spawns inside a vehicle it won't be locked.
|
||||
RegisterNetEvent("entityCreated", function(entity)
|
||||
AddEventHandler("entityCreated", function(entity)
|
||||
local time = os.time()
|
||||
while not DoesEntityExist(entity) and os.time()-time < 5 do Wait(50) end
|
||||
|
||||
if not DoesEntityExist(entity) or GetEntityType(entity) ~= 2 then return end
|
||||
|
||||
local state = Entity(entity).state
|
||||
if state.owner or state.locked ~= nil then return end
|
||||
|
||||
time = os.time()
|
||||
local driver = GetPedInVehicleSeat(entity, -1)
|
||||
while DoesEntityExist(entity) and driver == 0 and os.time()-time < 2 do
|
||||
driver = GetPedInVehicleSeat(entity, -1)
|
||||
Wait(100)
|
||||
end
|
||||
|
||||
if not DoesEntityExist(entity) then return end
|
||||
|
||||
if DoesEntityExist(driver) and IsPedAPlayer(driver) then
|
||||
state.locked = false
|
||||
state.hotwired = true
|
||||
@@ -665,6 +729,11 @@ RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations)
|
||||
local vehicle = NDCore.getVehicleById(vehId)
|
||||
local player = NDCore.getPlayer(src)
|
||||
if not player or not vehicle or vehicle.owner ~= player.id then return end
|
||||
|
||||
local info = NDCore.spawnOwnedVehicle(src, vehicle.id, isParkingAvailable(locations))
|
||||
if not info then return end
|
||||
TriggerClientEvent("ND_Vehicles:blip", src, info.netId, true)
|
||||
|
||||
if vehicle.impounded then
|
||||
local reclaimPrice = vehicle.metadata.impoundReclaimPrice or 200
|
||||
if not player.deductMoney("bank", reclaimPrice, "Vehicle impound reclaim") then
|
||||
@@ -683,10 +752,6 @@ RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations)
|
||||
})
|
||||
MySQL.query.await("UPDATE nd_vehicles SET impounded = ? WHERE id = ?", {0, vehicle.id})
|
||||
end
|
||||
|
||||
local info = NDCore.spawnOwnedVehicle(src, vehicle.id, isParkingAvailable(locations))
|
||||
if not info then return end
|
||||
TriggerClientEvent("ND_Vehicles:blip", src, info.netId, true)
|
||||
end)
|
||||
|
||||
lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src)
|
||||
@@ -694,3 +759,30 @@ lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src)
|
||||
if not player then return end
|
||||
return NDCore.getVehicles(player.id)
|
||||
end)
|
||||
|
||||
AddEventHandler("ND:characterLoaded", function(player)
|
||||
local ownedExistingVehicles = {}
|
||||
local ownedVehicles = NDCore.getVehicles(player.id)
|
||||
local vehicles = GetAllVehicles()
|
||||
local vehiclesToImpound = {}
|
||||
|
||||
for i=1, #vehicles do
|
||||
local veh = vehicles[i]
|
||||
local state = Entity(veh).state
|
||||
if state.owner == player.id then
|
||||
ownedExistingVehicles[#ownedExistingVehicles+1] = state.id
|
||||
end
|
||||
end
|
||||
|
||||
for i=1, #ownedVehicles do
|
||||
local veh = ownedVehicles[i]
|
||||
if veh and not veh.stored and not veh.impounded and not lib.table.contains(ownedExistingVehicles, veh.id) then
|
||||
vehiclesToImpound[#vehiclesToImpound+1] = veh.id
|
||||
end
|
||||
end
|
||||
|
||||
if #vehiclesToImpound == 0 then return end
|
||||
|
||||
local query = ("UPDATE nd_vehicles SET impounded = ? WHERE owner = ? AND id IN (%s)"):format(table.concat(vehiclesToImpound, ", "))
|
||||
MySQL.rawExecute(query, {1, player.id})
|
||||
end)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
NDCore = exports["ND_Core"]:GetCoreObject()
|
||||
@@ -1,30 +0,0 @@
|
||||
local startedResources = {}
|
||||
local callbacks = {}
|
||||
|
||||
AddEventHandler("onResourceStart", function(resourceName)
|
||||
startedResources[resourceName] = true
|
||||
local callback = callbacks[resourceName]
|
||||
if not callback then return end
|
||||
callback(true)
|
||||
end)
|
||||
|
||||
AddEventHandler("onResourceStop", function(resourceName)
|
||||
startedResources[resourceName] = nil
|
||||
local callback = callbacks[resourceName]
|
||||
if not callback then return end
|
||||
callback(false)
|
||||
end)
|
||||
|
||||
function isResourceStarted(resourceName, cb)
|
||||
local started = GetResourceState(resourceName) == "started"
|
||||
startedResources[resourceName] = started
|
||||
|
||||
if cb then
|
||||
callbacks[resourceName] = cb
|
||||
cb(started)
|
||||
end
|
||||
|
||||
return started
|
||||
end
|
||||
|
||||
exports("isResourceStarted", isResourceStarted)
|
||||
Reference in New Issue
Block a user