mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-09-02 03:08:52 +00:00
optimizations + more modules
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
ESX = {}
|
||||
ESX.Loops = {}
|
||||
ESX.LoopsRunning = {}
|
||||
ESX.Modules = {}
|
||||
ESX.PlayerData = {}
|
||||
ESX.PlayerLoaded = false
|
||||
@@ -57,6 +59,59 @@ RegisterNUICallback('frame_message', function(data, cb)
|
||||
cb('')
|
||||
end)
|
||||
|
||||
ESX.LogError = function(err)
|
||||
local str = err .. ' ' .. debug.traceback()
|
||||
print(str)
|
||||
TriggerServerEvent('esx:error:log', str);
|
||||
end
|
||||
|
||||
ESX.LogScopeError = function(scope, err)
|
||||
local str = '[esx] error in scope (' .. scope .. ') ' .. err .. ' ' .. debug.traceback()
|
||||
print(str)
|
||||
TriggerServerEvent('esx:error:log', str);
|
||||
end
|
||||
|
||||
|
||||
ESX.LogLoopError = function(loop, err)
|
||||
local str = '[esx] error in loop (' .. loop .. ') ' .. err .. ' ' .. debug.traceback()
|
||||
print(str)
|
||||
TriggerServerEvent('esx:error:log', str);
|
||||
end
|
||||
|
||||
ESX.Loop = function(name, func, wait, conditions)
|
||||
|
||||
ESX.Loops[name] = {
|
||||
func = func,
|
||||
wait = wait,
|
||||
conditons = conditions or {},
|
||||
name = name,
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
ESX.Scope = function(name, func)
|
||||
|
||||
local status, result = xpcall(func, function(err)
|
||||
ESX.LogScopeError(name, err)
|
||||
end)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
ESX.MakeScope = function(name, func)
|
||||
|
||||
return function(...)
|
||||
|
||||
local status, result = xpcall(func, ESX.LogError, function(err)
|
||||
ESX.LogScopeError(name, err)
|
||||
end)
|
||||
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ESX.IsPlayerLoaded = function()
|
||||
return ESX.PlayerLoaded
|
||||
end
|
||||
|
||||
+191
-93
@@ -1,5 +1,80 @@
|
||||
local isLoadoutLoaded, isPaused, pickups = false, false, {}
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
|
||||
AddTextEntry('FE_THDR_GTAO', 'ESX')
|
||||
|
||||
local logLoopError = function(err)
|
||||
ESX.LogLoopError(name, err)
|
||||
end
|
||||
|
||||
local runLoop = function(name, loop)
|
||||
|
||||
local conditionsMet = true
|
||||
|
||||
for j=1, #loop.conditons, 1 do
|
||||
if not loop.conditons[j]() then
|
||||
conditionsMet = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if conditionsMet then
|
||||
|
||||
ESX.LoopsRunning[name] = true
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
|
||||
local tests = #loop.conditons
|
||||
|
||||
for i=1, #loop.conditons, 1 do
|
||||
|
||||
if not loop.conditons[i]() then
|
||||
break
|
||||
end
|
||||
|
||||
tests = tests - 1
|
||||
|
||||
end
|
||||
|
||||
if tests > 0 then
|
||||
ESX.LoopsRunning[name] = false
|
||||
return
|
||||
end
|
||||
|
||||
local status, result = xpcall(loop.func, logLoopError)
|
||||
|
||||
if not status then
|
||||
ESX.Loops[name] = nil
|
||||
ESX.LoopsRunning[name] = false
|
||||
return
|
||||
end
|
||||
|
||||
Citizen.Wait(loop.wait)
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
while true do
|
||||
|
||||
for name, loop in pairs(ESX.Loops) do
|
||||
|
||||
if ESX.LoopsRunning[name] ~= true then
|
||||
local status, result = xpcall(runLoop, ESX.LogError, name, loop)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Citizen.Wait(250)
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
@@ -56,8 +131,6 @@ AddEventHandler('esx:playerLoaded', function(playerData)
|
||||
TriggerEvent('esx:onPlayerSpawn')
|
||||
TriggerEvent('esx:restoreLoadout')
|
||||
|
||||
StartServerSyncLoops()
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
@@ -80,7 +153,8 @@ AddEventHandler('skinchanger:modelLoaded', function()
|
||||
end)
|
||||
|
||||
AddEventHandler('esx:restoreLoadout', function()
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
local ammoTypes = {}
|
||||
|
||||
RemoveAllPedWeapons(playerPed, true)
|
||||
@@ -272,10 +346,11 @@ AddEventHandler('esx:createPickup', function(pickupId, label, playerId, type, na
|
||||
SetEntityCollision(obj, false, true)
|
||||
|
||||
pickups[pickupId] = {
|
||||
obj = obj,
|
||||
label = label,
|
||||
id = pickupId,
|
||||
obj = obj,
|
||||
label = label,
|
||||
inRange = false,
|
||||
coords = objectCoords
|
||||
coords = objectCoords
|
||||
}
|
||||
|
||||
end
|
||||
@@ -420,116 +495,139 @@ if Config.EnableHud then
|
||||
end)
|
||||
end
|
||||
|
||||
function StartServerSyncLoops()
|
||||
-- keep track of ammo
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
ESX.Loop('server-sync-ammo', function()
|
||||
|
||||
if ESX.IsDead then
|
||||
Citizen.Wait(500)
|
||||
else
|
||||
local playerPed = PlayerPedId()
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if IsPedShooting(playerPed) then
|
||||
local _,weaponHash = GetCurrentPedWeapon(playerPed, true)
|
||||
local weapon = ESX.GetWeaponFromHash(weaponHash)
|
||||
if IsPedShooting(playerPed) then
|
||||
local _,weaponHash = GetCurrentPedWeapon(playerPed, true)
|
||||
local weapon = ESX.GetWeaponFromHash(weaponHash)
|
||||
|
||||
if weapon then
|
||||
local ammoCount = GetAmmoInPedWeapon(playerPed, weaponHash)
|
||||
TriggerServerEvent('esx:updateWeaponAmmo', weapon.name, ammoCount)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if weapon then
|
||||
local ammoCount = GetAmmoInPedWeapon(playerPed, weaponHash)
|
||||
TriggerServerEvent('esx:updateWeaponAmmo', weapon.name, ammoCount)
|
||||
end
|
||||
end
|
||||
|
||||
-- sync current player coords with server
|
||||
Citizen.CreateThread(function()
|
||||
local previousCoords = vector3(ESX.PlayerData.coords.x, ESX.PlayerData.coords.y, ESX.PlayerData.coords.z)
|
||||
end, 250, {
|
||||
function() return ESX.PlayerLoaded and (not ESX.IsDead) end
|
||||
})
|
||||
|
||||
while true do
|
||||
Citizen.Wait(1000)
|
||||
local playerPed = PlayerPedId()
|
||||
local previousCoords
|
||||
|
||||
if DoesEntityExist(playerPed) then
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
local distance = #(playerCoords - previousCoords)
|
||||
ESX.Loop('server-sync-coords', function()
|
||||
|
||||
if distance > 1 then
|
||||
previousCoords = playerCoords
|
||||
local playerHeading = ESX.Math.Round(GetEntityHeading(playerPed), 1)
|
||||
local formattedCoords = {x = ESX.Math.Round(playerCoords.x, 1), y = ESX.Math.Round(playerCoords.y, 1), z = ESX.Math.Round(playerCoords.z, 1), heading = playerHeading}
|
||||
TriggerServerEvent('esx:updateCoords', formattedCoords)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if DoesEntityExist(playerPed) then
|
||||
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
previousCoords = previousCoords or playerCoords
|
||||
local distance = #(playerCoords - previousCoords)
|
||||
|
||||
if distance > 1 then
|
||||
previousCoords = playerCoords
|
||||
local playerHeading = ESX.Math.Round(GetEntityHeading(playerPed), 1)
|
||||
local formattedCoords = {x = ESX.Math.Round(playerCoords.x, 1), y = ESX.Math.Round(playerCoords.y, 1), z = ESX.Math.Round(playerCoords.z, 1), heading = playerHeading}
|
||||
TriggerServerEvent('esx:updateCoords', formattedCoords)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end, 1000, {
|
||||
function() return ESX.PlayerLoaded and (not ESX.IsDead) end
|
||||
})
|
||||
|
||||
-- Disable wanted level
|
||||
if Config.DisableWantedLevel then
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
local playerId = PlayerId()
|
||||
|
||||
if GetPlayerWantedLevel(playerId) ~= 0 then
|
||||
SetPlayerWantedLevel(playerId, 0, false)
|
||||
SetPlayerWantedLevelNow(playerId, false)
|
||||
end
|
||||
end
|
||||
end)
|
||||
ESX.Loop('disable-wanted-level', function()
|
||||
|
||||
local playerId = PlayerId()
|
||||
|
||||
if GetPlayerWantedLevel(playerId) ~= 0 then
|
||||
SetPlayerWantedLevel(playerId, 0, false)
|
||||
SetPlayerWantedLevelNow(playerId, false)
|
||||
end
|
||||
|
||||
end, 0)
|
||||
|
||||
end
|
||||
|
||||
-- Pickups
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords, letSleep = GetEntityCoords(playerPed), true
|
||||
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer(playerCoords)
|
||||
local pickupsInRange = {}
|
||||
local closestUsablePickup = nil
|
||||
|
||||
for pickupId,pickup in pairs(pickups) do
|
||||
local distance = #(playerCoords - pickup.coords)
|
||||
ESX.Loop('get-pickups-in-range', function()
|
||||
|
||||
if distance < 5 then
|
||||
local label = pickup.label
|
||||
letSleep = false
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
|
||||
if distance < 1 then
|
||||
if IsControlJustReleased(0, 38) then
|
||||
if IsPedOnFoot(playerPed) and (closestDistance == -1 or closestDistance > 3) and not pickup.inRange then
|
||||
pickup.inRange = true
|
||||
pickupsInRange = {}
|
||||
closestUsablePickup = nil
|
||||
|
||||
local dict, anim = 'weapons@first_person@aim_rng@generic@projectile@sticky_bomb@', 'plant_floor'
|
||||
ESX.Streaming.RequestAnimDict(dict)
|
||||
TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false)
|
||||
Citizen.Wait(1000)
|
||||
for pickupId, pickup in pairs(pickups) do
|
||||
|
||||
TriggerServerEvent('esx:onPickup', pickupId)
|
||||
PlaySoundFrontend(-1, 'PICK_UP', 'HUD_FRONTEND_DEFAULT_SOUNDSET', false)
|
||||
end
|
||||
end
|
||||
local distance = #(playerCoords - pickup.coords)
|
||||
|
||||
end
|
||||
if distance < 5.0 then
|
||||
|
||||
ESX.ShowFloatingHelpNotification(label, {
|
||||
x = pickup.coords.x,
|
||||
y = pickup.coords.y,
|
||||
z = pickup.coords.z + 0.25
|
||||
}, 100)
|
||||
pickupsInRange[#pickupsInRange + 1] = pickup
|
||||
|
||||
elseif pickup.inRange then
|
||||
pickup.inRange = false
|
||||
end
|
||||
end
|
||||
if distance < 1.0 then
|
||||
closestUsablePickup = pickup
|
||||
end
|
||||
|
||||
if letSleep then
|
||||
Citizen.Wait(500)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end, 500)
|
||||
|
||||
ESX.Loop('draw-pickups', function()
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
local playerCoords = GetEntityCoords(playerPed)
|
||||
|
||||
for i=1, #pickupsInRange, 1 do
|
||||
|
||||
local pickup = pickupsInRange[i]
|
||||
|
||||
ESX.ShowFloatingHelpNotification(pickup.label, {
|
||||
x = pickup.coords.x,
|
||||
y = pickup.coords.y,
|
||||
z = pickup.coords.z + 0.25
|
||||
}, 100)
|
||||
|
||||
end
|
||||
|
||||
end, 0)
|
||||
|
||||
ESX.Loop('pickup-actions', function()
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
local pickup = closestUsablePickup
|
||||
|
||||
if IsControlJustReleased(0, 38) then
|
||||
if IsPedOnFoot(playerPed) then
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
|
||||
local dict, anim = 'weapons@first_person@aim_rng@generic@projectile@sticky_bomb@', 'plant_floor'
|
||||
ESX.Streaming.RequestAnimDict(dict)
|
||||
TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false)
|
||||
Citizen.Wait(1000)
|
||||
TriggerServerEvent('esx:onPickup', pickup.id)
|
||||
PlaySoundFrontend(-1, 'PICK_UP', 'HUD_FRONTEND_DEFAULT_SOUNDSET', false)
|
||||
|
||||
end)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end, 0, {
|
||||
function() return closestUsablePickup ~= nil end
|
||||
})
|
||||
|
||||
AddEventHandler('luaconsole:getHandlers', function(cb)
|
||||
|
||||
|
||||
+40
-53
@@ -1,64 +1,51 @@
|
||||
Citizen.CreateThread(function()
|
||||
local isDead = false
|
||||
AddEventHandler('baseevents:onPlayerDied', function(killerType, deathCoords)
|
||||
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
local player = PlayerId()
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if NetworkIsPlayerActive(player) then
|
||||
local playerPed = PlayerPedId()
|
||||
local data = {
|
||||
killed = false,
|
||||
killerType = killerType,
|
||||
deathCoords = deathCoords,
|
||||
deathCause = GetPedCauseOfDeath(playerPed)
|
||||
}
|
||||
|
||||
if IsPedFatallyInjured(playerPed) and not isDead then
|
||||
isDead = true
|
||||
TriggerEvent('esx:onPlayerDeath', data)
|
||||
TriggerServerEvent('esx:onPlayerDeath', data)
|
||||
|
||||
local killerEntity, deathCause = GetPedSourceOfDeath(playerPed), GetPedCauseOfDeath(playerPed)
|
||||
local killerClientId = NetworkGetPlayerIndexFromPed(killerEntity)
|
||||
|
||||
if killerEntity ~= playerPed and killerClientId and NetworkIsPlayerActive(killerClientId) then
|
||||
PlayerKilledByPlayer(GetPlayerServerId(killerClientId), killerClientId, deathCause)
|
||||
else
|
||||
PlayerKilled(deathCause)
|
||||
end
|
||||
|
||||
elseif not IsPedFatallyInjured(playerPed) then
|
||||
isDead = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function PlayerKilledByPlayer(killerServerId, killerClientId, deathCause)
|
||||
local victimCoords = GetEntityCoords(PlayerPedId())
|
||||
local killerCoords = GetEntityCoords(GetPlayerPed(killerClientId))
|
||||
local distance = #(victimCoords - killerCoords)
|
||||
|
||||
local data = {
|
||||
victimCoords = {x = ESX.Math.Round(victimCoords.x, 1), y = ESX.Math.Round(victimCoords.y, 1), z = ESX.Math.Round(victimCoords.z, 1)},
|
||||
killerCoords = {x = ESX.Math.Round(killerCoords.x, 1), y = ESX.Math.Round(killerCoords.y, 1), z = ESX.Math.Round(killerCoords.z, 1)},
|
||||
|
||||
killedByPlayer = true,
|
||||
deathCause = deathCause,
|
||||
distance = ESX.Math.Round(distance, 1),
|
||||
|
||||
killerServerId = killerServerId,
|
||||
killerClientId = killerClientId
|
||||
}
|
||||
|
||||
TriggerEvent('esx:onPlayerDeath', data)
|
||||
TriggerServerEvent('esx:onPlayerDeath', data)
|
||||
end
|
||||
|
||||
function PlayerKilled(deathCause)
|
||||
AddEventHandler('baseevents:onPlayerKilled', function(killerId, data)
|
||||
local playerPed = PlayerPedId()
|
||||
local victimCoords = GetEntityCoords(playerPed)
|
||||
local killer = GetPlayerFromServerId(killerId)
|
||||
|
||||
local data = {
|
||||
victimCoords = {x = ESX.Math.Round(victimCoords.x, 1), y = ESX.Math.Round(victimCoords.y, 1), z = ESX.Math.Round(victimCoords.z, 1)},
|
||||
if NetworkIsPlayerActive(killer) then
|
||||
|
||||
killedByPlayer = false,
|
||||
deathCause = deathCause
|
||||
}
|
||||
local victimCoords = data.killerpos
|
||||
local weaponHash = data.weaponhash
|
||||
|
||||
data.killerpos = nil
|
||||
data.weaponhash = nil
|
||||
|
||||
local killerPed = GetPlayerPed(killer)
|
||||
local killerCoords = GetEntityCoords(killerPed)
|
||||
local distance = GetDistanceBetweenCoords(victimCoords[1], victimCoords[2], victimCoords[3], killerCoords, false)
|
||||
|
||||
data.victimCoords = victimCoords
|
||||
data.weaponHash = weaponHash
|
||||
data.deathCause = GetPedCauseOfDeath(playerPed)
|
||||
data.killed = true
|
||||
data.killerId = killerId
|
||||
data.killerCoords = {x = killerCoords.x, y = killerCoords.y, z = killerCoords.z}
|
||||
data.distance = distance
|
||||
|
||||
else
|
||||
|
||||
data.killed = false
|
||||
data.deathCause = GetPedCauseOfDeath(playerPed)
|
||||
|
||||
end
|
||||
|
||||
TriggerEvent('esx:onPlayerDeath', data)
|
||||
TriggerServerEvent('esx:onPlayerDeath', data)
|
||||
end
|
||||
TriggerServerEvent('esx:onPlayerDeath', data)
|
||||
|
||||
end)
|
||||
|
||||
+7
-1
@@ -94,7 +94,9 @@ server_exports {
|
||||
|
||||
dependencies {
|
||||
'mysql-async',
|
||||
'async'
|
||||
'async',
|
||||
'cron',
|
||||
'skinchanger',
|
||||
}
|
||||
|
||||
-- ESX Modules
|
||||
@@ -120,6 +122,7 @@ esxmodule 'interact' -- Interact menu (marker / npc)
|
||||
esxmodule 'addonaccount' -- Addon account
|
||||
esxmodule 'addoninventory' -- Addon inventory
|
||||
esxmodule 'datastore' -- Arbitrary data store
|
||||
esxmodule 'society' -- Society management
|
||||
|
||||
-- UI
|
||||
esxmodule 'hud' -- Money / society etc... HUD
|
||||
@@ -127,5 +130,8 @@ esxmodule 'menu_default' -- Default menu
|
||||
esxmodule 'menu_dialog' -- Dialog menu
|
||||
esxmodule 'menu_list' -- List menu
|
||||
|
||||
-- Misc
|
||||
esxmodule 'skin' -- Skin management
|
||||
|
||||
-- Jobs
|
||||
esxmodule 'job_police' -- Job police
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
local self = ESX.Modules['input']
|
||||
|
||||
self.InitESX()
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
|
||||
|
||||
@@ -454,8 +454,8 @@ end
|
||||
|
||||
self.InitESX = function()
|
||||
|
||||
self.RegisterControl(Input.Groups.MOVE, Input.Controls[Config.InventoryKey])
|
||||
self.On('released', Input.Groups.MOVE, Input.Controls[Config.InventoryKey], function(lastPressed)
|
||||
self.RegisterControl(self.Groups.MOVE, self.Controls[Config.InventoryKey])
|
||||
self.On('released', self.Groups.MOVE, self.Controls[Config.InventoryKey], function(lastPressed)
|
||||
|
||||
if (not ESX.IsDead) and (not ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory')) then
|
||||
ESX.ShowInventory()
|
||||
|
||||
@@ -31,7 +31,7 @@ Citizen.CreateThread(function()
|
||||
local distance = #(data.pos - self.Cache.player.coords);
|
||||
if
|
||||
(distance <= data.distance) and
|
||||
(ESX.Table.FindIndex(self.Cache.current, function(e) return e.__id == data.__id end) == -1)
|
||||
(ESX.Table.FindIndex(self.Cache.current , function(e) return e.__id == data.__id end) == -1)
|
||||
then
|
||||
|
||||
if (data.check == nil) or data.check(self.Cache.player.ped, self.Cache.player.coords) then
|
||||
@@ -62,33 +62,29 @@ Citizen.CreateThread(function()
|
||||
end)
|
||||
|
||||
-- Markers
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
ESX.Loop('input-markers', function()
|
||||
|
||||
Citizen.Wait(0)
|
||||
for i=1, #self.Cache.current, 1 do
|
||||
|
||||
for i=1, #self.Cache.current, 1 do
|
||||
local curr = self.Cache.current[i]
|
||||
|
||||
local curr = self.Cache.current[i]
|
||||
if curr.type == 'marker' then
|
||||
|
||||
if curr.type == 'marker' then
|
||||
|
||||
DrawMarker(
|
||||
curr.mtype,
|
||||
curr.pos.x + 0.0, curr.pos.y + 0.0, curr.pos.z + 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
curr.size.x + 0.0, curr.size.y + 0.0, curr.size.z + 0.0,
|
||||
curr.color.r, curr.color.g, curr.color.b, curr.color.a,
|
||||
curr.bobUpAndDown, curr.faceCamera, 2, curr.rotate, nil, nil, false
|
||||
)
|
||||
|
||||
end
|
||||
DrawMarker(
|
||||
curr.mtype,
|
||||
curr.pos.x + 0.0, curr.pos.y + 0.0, curr.pos.z + 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
curr.size.x + 0.0, curr.size.y + 0.0, curr.size.z + 0.0,
|
||||
curr.color.r, curr.color.g, curr.color.b, curr.color.a,
|
||||
curr.bobUpAndDown, curr.faceCamera, 2, curr.rotate, nil, nil, false
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
end, 0)
|
||||
|
||||
-- NPCs
|
||||
Citizen.CreateThread(function()
|
||||
|
||||
@@ -9,7 +9,10 @@ self.Cache = {
|
||||
ped = 0,
|
||||
coords = vector3(0.0, 0.0, 0.0)
|
||||
},
|
||||
current = {},
|
||||
current = {
|
||||
marker = {},
|
||||
npc = {},
|
||||
},
|
||||
using = {},
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ Citizen.CreateThread(function()
|
||||
end
|
||||
end)
|
||||
|
||||
--[[
|
||||
-- Enter / Exit entity zone events
|
||||
Citizen.CreateThread(function()
|
||||
local trackedEntities = {
|
||||
@@ -154,4 +155,4 @@ Citizen.CreateThread(function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
]]--
|
||||
|
||||
@@ -5,7 +5,7 @@ Config.MarkerType = 1
|
||||
Config.MarkerSize = {x = 1.5, y = 1.5, z = 0.5}
|
||||
Config.MarkerColor = {r = 50, g = 50, b = 204, a = 100}
|
||||
|
||||
Config.EnablePlayerManagement = false
|
||||
Config.EnablePlayerManagement = true
|
||||
Config.EnableArmoryManagement = true
|
||||
Config.EnableESXIdentity = false -- enable if you're using esx_identity
|
||||
Config.EnableLicenses = false -- enable if you're using esx_license
|
||||
|
||||
@@ -4,12 +4,5 @@ if self.Config.EnableESXService then
|
||||
TriggerEvent('esx_service:activateService', 'police', self.Config.MaxInService)
|
||||
end
|
||||
|
||||
AddEventHandler('onResourceStart', function(resource)
|
||||
|
||||
if resource == 'esx_society' then
|
||||
TriggerEvent('esx_society:registerSociety', 'police', 'Police', 'society_police', 'society_police', 'society_police', {type = 'public'})
|
||||
elseif resource == 'esx_phone' then
|
||||
TriggerEvent('esx_phone:registerNumber', 'police', _U('alert_police'), true, true)
|
||||
end
|
||||
|
||||
end)
|
||||
TriggerEvent('esx_society:registerSociety', 'police', 'Police', 'society_police', 'society_police', 'society_police', {type = 'public'})
|
||||
TriggerEvent('esx_phone:registerNumber', 'police', _U('alert_police'), true, true)
|
||||
|
||||
@@ -3,22 +3,3 @@ local self = ESX.Modules['menu_dialog']
|
||||
|
||||
ESX.UI.Menu.RegisterType(self.MenuType, self.openMenu, self.closeMenu)
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(10)
|
||||
|
||||
if ESX.Table.SizeOf(self.OpenedMenus) > 0 then
|
||||
DisableControlAction(0, 1, true) -- LookLeftRight
|
||||
DisableControlAction(0, 2, true) -- LookUpDown
|
||||
DisableControlAction(0, 142, true) -- MeleeAttackAlternate
|
||||
DisableControlAction(0, 106, true) -- VehicleMouseControlOverride
|
||||
DisableControlAction(0, 12, true) -- WeaponWheelUpDown
|
||||
DisableControlAction(0, 14, true) -- WeaponWheelNext
|
||||
DisableControlAction(0, 15, true) -- WeaponWheelPrev
|
||||
DisableControlAction(0, 16, true) -- SelectNextWeapon
|
||||
DisableControlAction(0, 17, true) -- SelectPrevWeapon
|
||||
else
|
||||
Citizen.Wait(500)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1,12 +1,55 @@
|
||||
ESX.Modules['menu_dialog'] = {};
|
||||
local self = ESX.Modules['menu_dialog']
|
||||
local Input = ESX.Modules['input']
|
||||
|
||||
self.Timeouts = {}
|
||||
self.OpenedMenus = {}
|
||||
self.MenuType = 'dialog'
|
||||
|
||||
self.RegisterControls = function()
|
||||
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.LOOK_LR)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.LOOK_UD)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.MELEE_ATTACK_ALTERNATE)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.VEH_MOUSE_CONTROL_OVERRIDE)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_UD)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_NEXT)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_PREV)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.SELECT_NEXT_WEAPON)
|
||||
Input.RegisterControl(Input.Groups.LOOK, Input.Controls.SELECT_PREV_WEAPON)
|
||||
|
||||
end
|
||||
|
||||
self.EnableControls = function()
|
||||
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.LOOK_LR)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.LOOK_UD)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.MELEE_ATTACK_ALTERNATE)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.VEH_MOUSE_CONTROL_OVERRIDE)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_UD)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_NEXT)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_PREV)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.SELECT_NEXT_WEAPON)
|
||||
Input.EnableControl(Input.Groups.LOOK, Input.Controls.SELECT_PREV_WEAPON)
|
||||
|
||||
end
|
||||
|
||||
self.DisableControls = function()
|
||||
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.LOOK_LR)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.LOOK_UD)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.MELEE_ATTACK_ALTERNATE)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.VEH_MOUSE_CONTROL_OVERRIDE)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_UD)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_NEXT)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.WEAPON_WHEEL_PREV)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.SELECT_NEXT_WEAPON)
|
||||
Input.DisableControl(Input.Groups.LOOK, Input.Controls.SELECT_PREV_WEAPON)
|
||||
|
||||
end
|
||||
|
||||
self.openMenu = function(namespace, name, data)
|
||||
|
||||
|
||||
for i=1, #self.Timeouts, 1 do
|
||||
ESX.ClearTimeout(self.Timeouts[i])
|
||||
end
|
||||
@@ -24,11 +67,14 @@ self.openMenu = function(namespace, name, data)
|
||||
ESX.FocusFrame('menu_dialog', true, true)
|
||||
end)
|
||||
|
||||
table.insert(self.Timeouts, timeoutId)
|
||||
table.insert(self.Timeouts, timeoutId)
|
||||
|
||||
self.DisableControls()
|
||||
|
||||
end
|
||||
|
||||
self.closeMenu = function(namespace, name)
|
||||
|
||||
|
||||
self.OpenedMenus[namespace .. '_' .. name] = nil
|
||||
|
||||
ESX.SendFrameMessage('menu_dialog', {
|
||||
@@ -38,7 +84,8 @@ self.closeMenu = function(namespace, name)
|
||||
data = data
|
||||
})
|
||||
|
||||
if ESX.Table.SizeOf(self.OpenedMenus) == 0 then
|
||||
if ESX.Table.SizeOf(self.OpenedMenus) == 0 then
|
||||
self.EnableControls()
|
||||
SetNuiFocus(false)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
AddEventHandler('esx:onPlayerSpawn', function()
|
||||
Citizen.CreateThread(function()
|
||||
|
||||
while not ESX.PlayerLoaded do
|
||||
Citizen.Wait(100)
|
||||
end
|
||||
|
||||
if self.firstSpawn then
|
||||
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
|
||||
if skin == nil then
|
||||
TriggerEvent('skinchanger:loadSkin', {sex = 0}, OpenSaveableMenu)
|
||||
else
|
||||
TriggerEvent('skinchanger:loadSkin', skin)
|
||||
end
|
||||
end)
|
||||
|
||||
self.firstSpawn = false
|
||||
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_skin:getLastSkin', function(cb)
|
||||
cb(self.lastSkin)
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_skin:setLastSkin', function(skin)
|
||||
self.lastSkin = skin
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_skin:openMenu')
|
||||
AddEventHandler('esx_skin:openMenu', function(submitCb, cancelCb)
|
||||
self.OpenMenu(submitCb, cancelCb, nil)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_skin:openRestrictedMenu')
|
||||
AddEventHandler('esx_skin:openRestrictedMenu', function(submitCb, cancelCb, restrict)
|
||||
self.OpenMenu(submitCb, cancelCb, restrict)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_skin:openSaveableMenu')
|
||||
AddEventHandler('esx_skin:openSaveableMenu', function(submitCb, cancelCb)
|
||||
self.OpenSaveableMenu(submitCb, cancelCb, nil)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_skin:openSaveableRestrictedMenu')
|
||||
AddEventHandler('esx_skin:openSaveableRestrictedMenu', function(submitCb, cancelCb, restrict)
|
||||
self.OpenSaveableMenu(submitCb, cancelCb, restrict)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_skin:requestSaveSkin')
|
||||
AddEventHandler('esx_skin:requestSaveSkin', function()
|
||||
TriggerEvent('skinchanger:getSkin', function(skin)
|
||||
TriggerServerEvent('esx_skin:responseSaveSkin', skin)
|
||||
end)
|
||||
end)
|
||||
@@ -0,0 +1,84 @@
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
|
||||
Citizen.Wait(0)
|
||||
|
||||
if self.isCameraActive then
|
||||
DisableControlAction(2, 30, true)
|
||||
DisableControlAction(2, 31, true)
|
||||
DisableControlAction(2, 32, true)
|
||||
DisableControlAction(2, 33, true)
|
||||
DisableControlAction(2, 34, true)
|
||||
DisableControlAction(2, 35, true)
|
||||
DisableControlAction(0, 25, true) -- Input Aim
|
||||
DisableControlAction(0, 24, true) -- Input Attack
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
local coords = GetEntityCoords(playerPed)
|
||||
|
||||
local angle = heading * math.pi / 180.0
|
||||
local theta = {
|
||||
x = math.cos(angle),
|
||||
y = math.sin(angle)
|
||||
}
|
||||
|
||||
local pos = {
|
||||
x = coords.x + (zoomOffset * theta.x),
|
||||
y = coords.y + (zoomOffset * theta.y)
|
||||
}
|
||||
|
||||
local angleToLook = heading - 140.0
|
||||
if angleToLook > 360 then
|
||||
angleToLook = angleToLook - 360
|
||||
elseif angleToLook < 0 then
|
||||
angleToLook = angleToLook + 360
|
||||
end
|
||||
|
||||
angleToLook = angleToLook * math.pi / 180.0
|
||||
local thetaToLook = {
|
||||
x = math.cos(angleToLook),
|
||||
y = math.sin(angleToLook)
|
||||
}
|
||||
|
||||
local posToLook = {
|
||||
x = coords.x + (zoomOffset * thetaToLook.x),
|
||||
y = coords.y + (zoomOffset * thetaToLook.y)
|
||||
}
|
||||
|
||||
SetCamCoord(cam, pos.x, pos.y, coords.z + camOffset)
|
||||
PointCamAtCoord(cam, posToLook.x, posToLook.y, coords.z + camOffset)
|
||||
|
||||
ESX.ShowHelpNotification(_U('use_rotate_view'))
|
||||
else
|
||||
Citizen.Wait(500)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
local angle = 90
|
||||
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
|
||||
if self.isCameraActive then
|
||||
if IsControlPressed(0, 108) then
|
||||
self.angle = angle - 1
|
||||
elseif IsControlPressed(0, 109) then
|
||||
self.angle = angle + 1
|
||||
end
|
||||
|
||||
if self.angle > 360 then
|
||||
self.angle = self.angle - 360
|
||||
elseif angle < 0 then
|
||||
self.angle = self.angle + 360
|
||||
end
|
||||
|
||||
self.heading = angle + 0.0
|
||||
else
|
||||
Citizen.Wait(500)
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,178 @@
|
||||
ESX.Modules['skin'] = {}
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
self.lastSkin = nil
|
||||
self.playerLoaded = false
|
||||
self.cam = nil
|
||||
self.isCameraActive = false
|
||||
|
||||
self.firstSpawn = true
|
||||
self.zoomOffset = 0.0
|
||||
self.camOffset = 0.0
|
||||
self.heading = 90.0
|
||||
|
||||
self.OpenMenu = function(submitCb, cancelCb, restrict)
|
||||
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
TriggerEvent('skinchanger:getSkin', function(skin)
|
||||
self.lastSkin = skin
|
||||
end)
|
||||
|
||||
TriggerEvent('skinchanger:getData', function(components, maxVals)
|
||||
local elements = {}
|
||||
local _components = {}
|
||||
|
||||
-- Restrict menu
|
||||
if restrict == nil then
|
||||
for i=1, #components, 1 do
|
||||
_components[i] = components[i]
|
||||
end
|
||||
else
|
||||
for i=1, #components, 1 do
|
||||
local found = false
|
||||
|
||||
for j=1, #restrict, 1 do
|
||||
if components[i].name == restrict[j] then
|
||||
found = true
|
||||
end
|
||||
end
|
||||
|
||||
if found then
|
||||
table.insert(_components, components[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Insert elements
|
||||
for i=1, #_components, 1 do
|
||||
local value = _components[i].value
|
||||
local componentId = _components[i].componentId
|
||||
|
||||
if componentId == 0 then
|
||||
value = GetPedPropIndex(playerPed, _components[i].componentId)
|
||||
end
|
||||
|
||||
local data = {
|
||||
label = _components[i].label,
|
||||
name = _components[i].name,
|
||||
value = value,
|
||||
min = _components[i].min,
|
||||
textureof = _components[i].textureof,
|
||||
zoomOffset= _components[i].zoomOffset,
|
||||
camOffset = _components[i].camOffset,
|
||||
type = 'slider'
|
||||
}
|
||||
|
||||
for k,v in pairs(maxVals) do
|
||||
if k == _components[i].name then
|
||||
data.max = v
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(elements, data)
|
||||
end
|
||||
|
||||
self.CreateSkinCam()
|
||||
self.zoomOffset = _components[1].zoomOffset
|
||||
self.camOffset = _components[1].camOffset
|
||||
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'skin', {
|
||||
title = _U('skin_menu'),
|
||||
align = 'top-left',
|
||||
elements = elements
|
||||
}, function(data, menu)
|
||||
TriggerEvent('skinchanger:getSkin', function(skin)
|
||||
self.lastSkin = skin
|
||||
end)
|
||||
|
||||
submitCb(data, menu)
|
||||
DeleteSkinCam()
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
self.DeleteSkinCam()
|
||||
TriggerEvent('skinchanger:loadSkin', lastSkin)
|
||||
|
||||
if cancelCb ~= nil then
|
||||
cancelCb(data, menu)
|
||||
end
|
||||
end, function(data, menu)
|
||||
local skin, components, maxVals
|
||||
|
||||
TriggerEvent('skinchanger:getSkin', function(getSkin)
|
||||
skin = getSkin
|
||||
end)
|
||||
|
||||
zoomOffset = data.current.zoomOffset
|
||||
camOffset = data.current.camOffset
|
||||
|
||||
if skin[data.current.name] ~= data.current.value then
|
||||
-- Change skin element
|
||||
TriggerEvent('skinchanger:change', data.current.name, data.current.value)
|
||||
|
||||
-- Update max values
|
||||
TriggerEvent('skinchanger:getData', function(comp, max)
|
||||
components, maxVals = comp, max
|
||||
end)
|
||||
|
||||
local newData = {}
|
||||
|
||||
for i=1, #elements, 1 do
|
||||
newData = {}
|
||||
newData.max = maxVals[elements[i].name]
|
||||
|
||||
if elements[i].textureof ~= nil and data.current.name == elements[i].textureof then
|
||||
newData.value = 0
|
||||
end
|
||||
|
||||
menu.update({name = elements[i].name}, newData)
|
||||
end
|
||||
|
||||
menu.refresh()
|
||||
end
|
||||
end, function(data, menu)
|
||||
DeleteSkinCam()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
self.CreateSkinCam = function()
|
||||
if not DoesCamExist(cam) then
|
||||
self.cam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
|
||||
end
|
||||
|
||||
SetCamActive(cam, true)
|
||||
RenderScriptCams(true, true, 500, true, true)
|
||||
|
||||
self.isCameraActive = true
|
||||
SetCamRot(cam, 0.0, 0.0, 270.0, true)
|
||||
SetEntityHeading(playerPed, 90.0)
|
||||
end
|
||||
|
||||
self.DeleteSkinCam = function()
|
||||
self.isCameraActive = false
|
||||
SetCamActive(cam, false)
|
||||
RenderScriptCams(false, true, 500, true, true)
|
||||
cam = nil
|
||||
end
|
||||
|
||||
self.OpenSaveableMenu = function(submitCb, cancelCb, restrict)
|
||||
TriggerEvent('skinchanger:getSkin', function(skin)
|
||||
lastSkin = skin
|
||||
end)
|
||||
|
||||
self.OpenMenu(function(data, menu)
|
||||
menu.close()
|
||||
DeleteSkinCam()
|
||||
|
||||
TriggerEvent('skinchanger:getSkin', function(skin)
|
||||
TriggerServerEvent('esx_skin:save', skin)
|
||||
|
||||
if submitCb ~= nil then
|
||||
submitCb(data, menu)
|
||||
end
|
||||
end)
|
||||
|
||||
end, cancelCb, restrict)
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
Config = {}
|
||||
|
||||
Config.Locale = 'fr'
|
||||
|
||||
Config.BackpackWeight = {
|
||||
[40] = 16, [41] = 20, [44] = 25, [45] = 23
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['br'] = {
|
||||
['skin_menu'] = 'Skin Menu',
|
||||
['use_rotate_view'] = 'Use ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ e ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ para girar a visão.',
|
||||
['skin'] = 'Trocar',
|
||||
['saveskin'] = 'Salvar',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['de'] = {
|
||||
['skin_menu'] = 'Skin Menü',
|
||||
['use_rotate_view'] = 'benutze ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ und ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ um die Sicht zu drehen.',
|
||||
['skin'] = 'Skin ändern',
|
||||
['saveskin'] = 'Skin speichern',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['en'] = {
|
||||
['skin_menu'] = 'Skin Menu',
|
||||
['use_rotate_view'] = 'use ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ and ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ to rotate the view.',
|
||||
['skin'] = 'change skin',
|
||||
['saveskin'] = 'save skin to a file',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['fi'] = {
|
||||
['skin_menu'] = 'ulkonäkö',
|
||||
['use_rotate_view'] = 'paina ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ tai ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ liikutaaksesi kameraa.',
|
||||
['skin'] = 'vaihda ulkonäköä',
|
||||
['saveskin'] = 'talleta ulkonäkö tiedostoon',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['fr'] = {
|
||||
['skin_menu'] = 'Skin Menu',
|
||||
['use_rotate_view'] = 'utilisez ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ et ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ pour tourner la vue.',
|
||||
['skin'] = 'changer de skin',
|
||||
['saveskin'] = 'sauvegarder skin dans un fichier',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['pl'] = {
|
||||
['skin_menu'] = 'menu wyglądu',
|
||||
['use_rotate_view'] = 'użyj ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ i ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ aby obrócić ekran.',
|
||||
['skin'] = 'zmień wygląd',
|
||||
['saveskin'] = 'zapisz wygląd do pliku',
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Locales['sv'] = {
|
||||
['skin_menu'] = 'skin meny',
|
||||
['use_rotate_view'] = 'använd ~INPUT_VEH_FLY_ROLL_LEFT_ONLY~ och ~INPUT_VEH_FLY_ROLL_RIGHT_ONLY~ för att rotera.',
|
||||
['skin'] = 'ändra skin',
|
||||
['saveskin'] = 'spara skin till fil',
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `users` ADD COLUMN `skin` LONGTEXT NULL DEFAULT NULL;
|
||||
@@ -0,0 +1,64 @@
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
RegisterServerEvent('esx_skin:save')
|
||||
AddEventHandler('esx_skin:save', function(skin)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
local defaultMaxWeight = ESX.GetConfig().MaxWeight
|
||||
local backpackModifier = Config.BackpackWeight[skin.bags_1]
|
||||
|
||||
if backpackModifier then
|
||||
xPlayer.setMaxWeight(defaultMaxWeight + backpackModifier)
|
||||
else
|
||||
xPlayer.setMaxWeight(defaultMaxWeight)
|
||||
end
|
||||
|
||||
MySQL.Async.execute('UPDATE users SET skin = @skin WHERE identifier = @identifier', {
|
||||
['@skin'] = json.encode(skin),
|
||||
['@identifier'] = xPlayer.identifier
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_skin:responseSaveSkin')
|
||||
AddEventHandler('esx_skin:responseSaveSkin', function(skin)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
|
||||
if xPlayer.getGroup() == 'admin' then
|
||||
local file = io.open('resources/[esx]/esx_skin/skins.txt', "a")
|
||||
|
||||
file:write(json.encode(skin) .. "\n\n")
|
||||
file:flush()
|
||||
file:close()
|
||||
else
|
||||
print(('esx_skin: %s attempted saving skin to file'):format(xPlayer.getIdentifier()))
|
||||
end
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_skin:getPlayerSkin', function(source, cb)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
|
||||
MySQL.Async.fetchAll('SELECT skin FROM users WHERE identifier = @identifier', {
|
||||
['@identifier'] = xPlayer.identifier
|
||||
}, function(users)
|
||||
local user, skin = users[1]
|
||||
|
||||
local jobSkin = {
|
||||
skin_male = xPlayer.job.skin_male,
|
||||
skin_female = xPlayer.job.skin_female
|
||||
}
|
||||
|
||||
if user.skin then
|
||||
skin = json.decode(user.skin)
|
||||
end
|
||||
|
||||
cb(skin, jobSkin)
|
||||
end)
|
||||
end)
|
||||
|
||||
ESX.RegisterCommand('skin', 'admin', function(xPlayer, args, showError)
|
||||
xPlayer.triggerEvent('esx_skin:openSaveableMenu')
|
||||
end, false, {help = _U('skin')})
|
||||
|
||||
ESX.RegisterCommand('skinsave', 'admin', function(xPlayer, args, showError)
|
||||
xPlayer.triggerEvent('esx_skin:requestSaveSkin')
|
||||
end, false, {help = _U('saveskin')})
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ESX.Modules['skin'] = {}
|
||||
local self = ESX.Modules['skin']
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
AddEventHandler('esx:migrations:ensure', function(register)
|
||||
register('society')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx_addonaccount:setMoney')
|
||||
AddEventHandler('esx_addonaccount:setMoney', function(society, money)
|
||||
if ESX.PlayerData.job and ESX.PlayerData.job.grade_name == 'boss' and 'society_' .. ESX.PlayerData.job.name == society then
|
||||
self.UpdateSocietyMoneyHUDElement(money)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx:setJob')
|
||||
AddEventHandler('esx:setJob', function(job)
|
||||
self.RefreshBossHUD()
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_society:openBossMenu', function(society, close, options)
|
||||
self.OpenBossMenu(society, close, options)
|
||||
end)
|
||||
@@ -0,0 +1,13 @@
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
self.Init()
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
|
||||
while ESX.PlayerData.job == nil do
|
||||
Citizen.Wait(10)
|
||||
end
|
||||
|
||||
self.RefreshBossHUD()
|
||||
|
||||
end)
|
||||
@@ -0,0 +1,345 @@
|
||||
ESX.Modules['society'] = {}
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
self.Config = ESX.EvalFile(GetCurrentResourceName(), 'modules/society/data/config.lua', {
|
||||
vector3 = vector3
|
||||
})['Config']
|
||||
|
||||
self.Init = function()
|
||||
|
||||
local translations = ESX.EvalFile(GetCurrentResourceName(), 'modules/society/data/locales/' .. Config.Locale .. '.lua')['Translations']
|
||||
LoadLocale('society', Config.Locale, translations)
|
||||
|
||||
end
|
||||
|
||||
self.base64MoneyIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAMAUExURQAAACmvPCmwPCuwPiywPi2wPy6xQC6xQS+yQTCxQTCyQTCyQjGyQzKyRDOzRTSzRTSzRjW0RjW0Rza0SDe0STi0STm1Sjq1Szq2Szu2TDy2TDy2TT22Tj63Tz+3UEC4UEG4UUG4UkK4U0O5VES5VEW6VUa6Vke6V0i7WEm7WUu8Wku8W0y8W028XE29XU++XlC9X1C+X1G+YFK+YVO/YlW/ZFXAZFfAZVfAZljBZlnBZ1rBaVvCaVvCalzDal7CbF/DbV/EbWHEbmLEb2LEcGTFcWfGdGjHdWrHd2vId2vIeGzIeW3JenHKfXLKfnPLf3TLgHXLgXXMgHXMgXbMgnjNg3nMhHrNhnrOhnzOiH7PiYLQjYPRjoTRjoTRj4XRkIXSkIfSkojSk4rUlYzUlo7VmJDWmpHWm5LXnJTXnZTXnpXYnpbYn5nZopzapJ3bpZ7bpp7bp6DcqKLcqqPcq6Tcq6TdrKberqjfr6jfsKnfsavgs6zgs6zgtK7hta/htrDit7LiuLLiubPjurTjurXju7bkvLbkvbnlv7rlwLrmwLzmwr3nw77nxMDnxcLox8PpyMTpycXpysXqysbqy8fqzMnrzcrrz8vsz8vs0Mzs0c3t0tHu1dHu1tPv19Tv2NXv2dXw2dbw2tfw29jw3Nnx3drx3t7z4d/z4uD04+H05OP15eP15uT15uT15+X16OX26Of26en36+r37Ov37er47Ov47ez47e347u347+758PD58fD68fD68vL69PT79fX79vb79/b89vb89/f8+Pj9+fn9+vr9+/v++/v+/Pz+/P3+/f3+/v7//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALfZHJgAAAEAdFJOU////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wBT9wclAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGHRFWHRTb2Z0d2FyZQBwYWludC5uZXQgNC4xLjb9TgnoAAAGdUlEQVRoQ7WZ93sURRiAFZO76O1eklt215OgBwqJgmgCRhAhRrAAiogBK4gBJEFEgWAEYiGIYEGp1kjXQECkiF0OWyjJ/k34zcy3db7Zu8fHe3/KTXnzPbPT56orRTEYAhMLUFgNKkeiGH8BNaV1KWSPVXveU9s3LW9pvhdoblm+afspTHZi5Wo1BnzpaOfcnFmWSBv29YBtpBNlZm5u59FLPDsmdJUaxQeXNugZw5IwMnrD0oO8iFKuUHNx/+bGZLWNMgm7Otm4uZ/LsVIEUs3F+Y5a3USNAlOv7cgr5ZSamQffyOnKgH1sPdfFi2PVILKaReEcmKwVIWbY2uQDvApW95HULIb+Ng0rFoXWxppcCjyqZuZjk4oNWWBrk44R7oiamXdkC3w9GTO7Q3aH1cy8OkWFnHtitstM4j/bqdWSO6Rm5nYdS4e5FbKQwxlMC6G3Q1bIHVQz8+IKLBphJLdydlRjWpiKxZAXdAfUPOak4gOO4FZOdxWmhbGTkbh9NTOvoVsDuGmAaxkdlZgWRV8Dub7bV0PyzhQWkqk5z7WMdjpqILUTslEXUEPQJ7Lq7pz9WXiBZ4iZUGBnTwTCdtVgvjgxpj+b3vTvTEteq5KbEy/6blcNVZapR3cmdc9Z4QV6Pnxzdr1GF9aWQQFUohqCPqQc3ZV17X3C6tP31kyL+Jy2dsgLW6jBPDgVc6OkR3XxCV/i9IqRRFedylxc6qk30L3DNF7ikz1Jft0oLOaT2hBSg/l8jmwOo24/amimYzkfOwfdlLtdNT1YjIaf0EFzgGhuNnB8teNcqCWDvs3vzSSLqC9Ze0F0EqaGoDeSQWt7UaHgXA0WDKFvFGEzNRS6mxot6VZhUNJNdm7zbsgSagj6UAKTQ5hnhEHJffRISIi+LdRLyNn9cTSoOExP3FZmiat2nIF66t9Xb0GFz8Df+AenVTEF2vUwAzM1BN1LfsTkcVS4bJs+fnRj84z3joqf+eFYUELvZWFzdSfZHjeeEwqXl6/myWaZ0bSVDf3uJP9NkOn01HPISXIMTJAB/hiB6WBPN+xxBpvxl4wxR6ihll8pSL1QupwLLhR22YL9ysVGrKRcfZJeAu4QSo+1yWA3rla2NGCeZGpoj13lmBJm1F/odDm+fv68phorU0l+miDlu6BFmLqbHDCWdhqVQQb/zPesW1inqxdoRqIb1SvSmBJG+wR1BF+/NkmLWUnTK1DdQq+i5gvoIbn85QPqtdRoQfU0TIgy4h/UKOi+gZ5DgGmonqIoob2CDhXHblE0ij2lgNo2YMcSy7fkhF2E2rIm/IoOFV/Q+78i1JkJheJ+jOzjnlr1GRk18swa4iC9t3U/o6LzCVLTP4dlVM14LBfC63yKIYOYeuMqcRoneZFqEW/IKAY6Q8xumla3YP2+PNnNt1Jqb6Arpifg5kXuHjNTaVi1s5/eJs0r+6gFUkxP6kkV2mKBs8UMZSYMdmAJcpxqTTGpqpcCEO1znCMTwlPFNbuF0uUs1UVwKYAWoRcwGDHsbNS/algwu+J1bvToI9TuAgZqetm1roPVk/FDazbhjaryr0SiSw/R1oFll94sWNnfsLrzS1eTkawyjKrE6HcwyeVtIix3s6Dc4ljzsTbnx74P1na83+uf8ZBn5cb0tjgsbHJjlvoMa8dxWT4XBDZmoCa3k7eH9yE0u4l9jr+dZN2P2ASnVorK8TwoVwxsglnYxNY9852oHMseogMEt+4QtnzgGDoTa8eRH4ulA4QOHCxs6ZhUBdNAIS7NIjp1+JgEaulwZzwsnXCjDDxPzB+Rwx1zS0fSoVZb/Mp4/lFqQxk5kjI1cZDWa179HTUEe8eRW9XoQZq5qeN/5fCFigWmd14VNRXLx3/et8lLC7N8XNtH0VP6mXfvV+z4iEsLFrbqqkXXho2Z8dynwgo8NdZK0SXpqxbmjrsgquhCsXrhgOYgL4h4k8Rca5VvFV7gTkySUVxrsbBjLuOGfMy1jCZFa6gv47hbeYU4ZA/XMmbRy13MFaJwqy4+Ez1cy3iSVsddfGLcdJvo33Ato5VcSeOva4WbvmQ2v+daxkrqfqXQJbNwk1fj9kOPuNwlZxdxNS7c5IW+MdRFMhd3oS/cpXmG4EOnRI8nAAt8sKsETz4AK1yahyqAy0vxvAaU7lEQcJ8yj9BPmUf+81MmR8iB//kBllOyZ2NOqR67XUAVABNjuXLlX2rCcoFjOcGoAAAAAElFTkSuQmCC'
|
||||
|
||||
self.RefreshBossHUD = function()
|
||||
|
||||
self.DisableSocietyMoneyHUDElement()
|
||||
|
||||
if ESX.PlayerData.job.grade_name == 'boss' then
|
||||
self.EnableSocietyMoneyHUDElement()
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:getSocietyMoney', function(money)
|
||||
self.UpdateSocietyMoneyHUDElement(money)
|
||||
end, ESX.PlayerData.job.name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.EnableSocietyMoneyHUDElement = function()
|
||||
local societyMoneyHUDElementTpl = '<div><img src="' .. self.base64MoneyIcon .. '" style="width:20px; height:20px; vertical-align:middle;"> {{money}}</div>'
|
||||
|
||||
if ESX.GetConfig().EnableHud then
|
||||
ESX.UI.HUD.RegisterElement('society_money', 3, 0, societyMoneyHUDElementTpl, {
|
||||
money = 0
|
||||
})
|
||||
end
|
||||
|
||||
TriggerEvent('esx_society:toggleSocietyHud', true)
|
||||
end
|
||||
|
||||
self.DisableSocietyMoneyHUDElement = function()
|
||||
if ESX.GetConfig().EnableHud then
|
||||
ESX.UI.HUD.RemoveElement('society_money')
|
||||
end
|
||||
|
||||
TriggerEvent('esx_society:toggleSocietyHud', false)
|
||||
end
|
||||
|
||||
self.UpdateSocietyMoneyHUDElement = function(money)
|
||||
if ESX.GetConfig().EnableHud then
|
||||
ESX.UI.HUD.UpdateElement('society_money', {
|
||||
money = ESX.Math.GroupDigits(money)
|
||||
})
|
||||
end
|
||||
|
||||
TriggerEvent('esx_society:setSocietyMoney', money)
|
||||
end
|
||||
|
||||
self.OpenBossMenu = function(society, close, options)
|
||||
options = options or {}
|
||||
local elements = {}
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:isBoss', function(isBoss)
|
||||
if isBoss then
|
||||
local defaultOptions = {
|
||||
withdraw = true,
|
||||
deposit = true,
|
||||
wash = true,
|
||||
employees = true,
|
||||
grades = true
|
||||
}
|
||||
|
||||
for k,v in pairs(defaultOptions) do
|
||||
if options[k] == nil then
|
||||
options[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
if options.withdraw then
|
||||
table.insert(elements, {label = _U('society:withdraw_society_money'), value = 'withdraw_society_money'})
|
||||
end
|
||||
|
||||
if options.deposit then
|
||||
table.insert(elements, {label = _U('society:deposit_society_money'), value = 'deposit_money'})
|
||||
end
|
||||
|
||||
if options.wash then
|
||||
table.insert(elements, {label = _U('society:wash_money'), value = 'wash_money'})
|
||||
end
|
||||
|
||||
if options.employees then
|
||||
table.insert(elements, {label = _U('society:employee_management'), value = 'manage_employees'})
|
||||
end
|
||||
|
||||
if options.grades then
|
||||
table.insert(elements, {label = _U('society:salary_management'), value = 'manage_grades'})
|
||||
end
|
||||
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'boss_actions_' .. society, {
|
||||
title = _U('society:boss_menu'),
|
||||
align = 'top-left',
|
||||
elements = elements
|
||||
}, function(data, menu)
|
||||
if data.current.value == 'withdraw_society_money' then
|
||||
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'withdraw_society_money_amount_' .. society, {
|
||||
title = _U('society:withdraw_amount')
|
||||
}, function(data2, menu2)
|
||||
local amount = tonumber(data2.value)
|
||||
|
||||
if amount == nil then
|
||||
ESX.ShowNotification(_U('society:invalid_amount'))
|
||||
else
|
||||
menu2.close()
|
||||
TriggerServerEvent('esx_society:withdrawMoney', society, amount)
|
||||
end
|
||||
end, function(data2, menu2)
|
||||
menu2.close()
|
||||
end)
|
||||
elseif data.current.value == 'deposit_money' then
|
||||
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'deposit_money_amount_' .. society, {
|
||||
title = _U('society:deposit_amount')
|
||||
}, function(data2, menu2)
|
||||
local amount = tonumber(data2.value)
|
||||
|
||||
if amount == nil then
|
||||
ESX.ShowNotification(_U('society:invalid_amount'))
|
||||
else
|
||||
menu2.close()
|
||||
TriggerServerEvent('esx_society:depositMoney', society, amount)
|
||||
end
|
||||
end, function(data2, menu2)
|
||||
menu2.close()
|
||||
end)
|
||||
elseif data.current.value == 'wash_money' then
|
||||
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'wash_money_amount_' .. society, {
|
||||
title = _U('society:wash_money_amount')
|
||||
}, function(data2, menu2)
|
||||
local amount = tonumber(data2.value)
|
||||
|
||||
if amount == nil then
|
||||
ESX.ShowNotification(_U('society:invalid_amount'))
|
||||
else
|
||||
menu2.close()
|
||||
TriggerServerEvent('esx_society:washMoney', society, amount)
|
||||
end
|
||||
end, function(data2, menu2)
|
||||
menu2.close()
|
||||
end)
|
||||
elseif data.current.value == 'manage_employees' then
|
||||
OpenManageEmployeesMenu(society)
|
||||
elseif data.current.value == 'manage_grades' then
|
||||
OpenManageGradesMenu(society)
|
||||
end
|
||||
end, function(data, menu)
|
||||
if close then
|
||||
close(data, menu)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end, society)
|
||||
end
|
||||
|
||||
self.OpenManageEmployeesMenu = function(society)
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'manage_employees_' .. society, {
|
||||
title = _U('society:employee_management'),
|
||||
align = 'top-left',
|
||||
elements = {
|
||||
{label = _U('society:employee_list'), value = 'employee_list'},
|
||||
{label = _U('society:recruit'), value = 'recruit'}
|
||||
}}, function(data, menu)
|
||||
if data.current.value == 'employee_list' then
|
||||
OpenEmployeeList(society)
|
||||
elseif data.current.value == 'recruit' then
|
||||
OpenRecruitMenu(society)
|
||||
end
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
end)
|
||||
end
|
||||
|
||||
self.OpenEmployeeList = function(society)
|
||||
ESX.TriggerServerCallback('esx_society:getEmployees', function(employees)
|
||||
|
||||
local elements = {
|
||||
head = {_U('society:employee'), _U('society:grade'), _U('society:actions')},
|
||||
rows = {}
|
||||
}
|
||||
|
||||
for i=1, #employees, 1 do
|
||||
local gradeLabel = (employees[i].job.grade_label == '' and employees[i].job.label or employees[i].job.grade_label)
|
||||
|
||||
table.insert(elements.rows, {
|
||||
data = employees[i],
|
||||
cols = {
|
||||
employees[i].name,
|
||||
gradeLabel,
|
||||
'{{' .. _U('society:promote') .. '|promote}} {{' .. _U('society:fire') .. '|fire}}'
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
ESX.UI.Menu.Open('list', GetCurrentResourceName(), 'employee_list_' .. society, elements, function(data, menu)
|
||||
local employee = data.data
|
||||
|
||||
if data.value == 'promote' then
|
||||
menu.close()
|
||||
OpenPromoteMenu(society, employee)
|
||||
elseif data.value == 'fire' then
|
||||
ESX.ShowNotification(_U('society:you_have_fired', employee.name))
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:setJob', function()
|
||||
OpenEmployeeList(society)
|
||||
end, employee.identifier, 'unemployed', 0, 'fire')
|
||||
end
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
OpenManageEmployeesMenu(society)
|
||||
end)
|
||||
end, society)
|
||||
end
|
||||
|
||||
self.OpenRecruitMenu = function(society)
|
||||
ESX.TriggerServerCallback('esx_society:getOnlinePlayers', function(players)
|
||||
local elements = {}
|
||||
|
||||
for i=1, #players, 1 do
|
||||
if players[i].job.name ~= society then
|
||||
table.insert(elements, {
|
||||
label = players[i].name,
|
||||
value = players[i].source,
|
||||
name = players[i].name,
|
||||
identifier = players[i].identifier
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'recruit_' .. society, {
|
||||
title = _U('society:recruiting'),
|
||||
align = 'top-left',
|
||||
elements = elements
|
||||
}, function(data, menu)
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'recruit_confirm_' .. society, {
|
||||
title = _U('society:do_you_want_to_recruit', data.current.name),
|
||||
align = 'top-left',
|
||||
elements = {
|
||||
{label = _U('society:no'), value = 'no'},
|
||||
{label = _U('society:yes'), value = 'yes'}
|
||||
}}, function(data2, menu2)
|
||||
menu2.close()
|
||||
|
||||
if data2.current.value == 'yes' then
|
||||
ESX.ShowNotification(_U('society:you_have_hired', data.current.name))
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:setJob', function()
|
||||
OpenRecruitMenu(society)
|
||||
end, data.current.identifier, society, 0, 'hire')
|
||||
end
|
||||
end, function(data2, menu2)
|
||||
menu2.close()
|
||||
end)
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
self.OpenPromoteMenu = function(society, employee)
|
||||
ESX.TriggerServerCallback('esx_society:getJob', function(job)
|
||||
local elements = {}
|
||||
|
||||
for i=1, #job.grades, 1 do
|
||||
local gradeLabel = (job.grades[i].label == '' and job.label or job.grades[i].label)
|
||||
|
||||
table.insert(elements, {
|
||||
label = gradeLabel,
|
||||
value = job.grades[i].grade,
|
||||
selected = (employee.job.grade == job.grades[i].grade)
|
||||
})
|
||||
end
|
||||
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'promote_employee_' .. society, {
|
||||
title = _U('society:promote_employee', employee.name),
|
||||
align = 'top-left',
|
||||
elements = elements
|
||||
}, function(data, menu)
|
||||
menu.close()
|
||||
ESX.ShowNotification(_U('society:you_have_promoted', employee.name, data.current.label))
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:setJob', function()
|
||||
OpenEmployeeList(society)
|
||||
end, employee.identifier, society, data.current.value, 'promote')
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
OpenEmployeeList(society)
|
||||
end)
|
||||
end, society)
|
||||
end
|
||||
|
||||
self.OpenManageGradesMenu = function(society)
|
||||
ESX.TriggerServerCallback('esx_society:getJob', function(job)
|
||||
local elements = {}
|
||||
|
||||
for i=1, #job.grades, 1 do
|
||||
local gradeLabel = (job.grades[i].label == '' and job.label or job.grades[i].label)
|
||||
|
||||
table.insert(elements, {
|
||||
label = ('%s - <span style="color:green;">%s</span>'):format(gradeLabel, _U('society:money_generic', ESX.Math.GroupDigits(job.grades[i].salary))),
|
||||
value = job.grades[i].grade
|
||||
})
|
||||
end
|
||||
|
||||
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'manage_grades_' .. society, {
|
||||
title = _U('society:salary_management'),
|
||||
align = 'top-left',
|
||||
elements = elements
|
||||
}, function(data, menu)
|
||||
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'manage_grades_amount_' .. society, {
|
||||
title = _U('society:salary_amount')
|
||||
}, function(data2, menu2)
|
||||
|
||||
local amount = tonumber(data2.value)
|
||||
|
||||
if amount == nil then
|
||||
ESX.ShowNotification(_U('society:invalid_amount'))
|
||||
elseif amount > Config.MaxSalary then
|
||||
ESX.ShowNotification(_U('society:invalid_amount_max'))
|
||||
else
|
||||
menu2.close()
|
||||
|
||||
ESX.TriggerServerCallback('esx_society:setJobSalary', function()
|
||||
OpenManageGradesMenu(society)
|
||||
end, society, data.current.value, amount)
|
||||
end
|
||||
end, function(data2, menu2)
|
||||
menu2.close()
|
||||
end)
|
||||
end, function(data, menu)
|
||||
menu.close()
|
||||
end)
|
||||
end, society)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Config = {}
|
||||
|
||||
Config.Locale = 'fr'
|
||||
Config.EnableESXIdentity = false
|
||||
Config.MaxSalary = 3500
|
||||
@@ -0,0 +1,38 @@
|
||||
Translations = {
|
||||
['actions'] = 'ações',
|
||||
['boss_menu'] = 'menu chefe',
|
||||
['money_generic'] = '$%s',
|
||||
['deposit_amount'] = 'valor do depósito',
|
||||
['deposit_society_money'] = 'depositar dinheiro da sociedade',
|
||||
['do_you_want_to_recruit'] = 'você quer recrutar %s?',
|
||||
['employee'] = 'empregado',
|
||||
['employee_list'] = 'lista de empregados',
|
||||
['employee_management'] = 'gestão de funcionários',
|
||||
['fire'] = 'fogo',
|
||||
['grade'] = 'grau(escolaridade)',
|
||||
['have_deposited'] = 'você depositou ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'você retirou ~g~$%s~s~',
|
||||
['invalid_amount'] = 'montante inválido',
|
||||
['invalid_amount_max'] = 'esse salário não é permitido',
|
||||
['no'] = 'não',
|
||||
['promote'] = 'promover',
|
||||
['promote_employee'] = 'promover %s',
|
||||
['recruit'] = 'recrutar',
|
||||
['recruiting'] = 'recrutamento',
|
||||
['salary_amount'] = 'valor do salário',
|
||||
['salary_management'] = 'gestão salarial',
|
||||
['wash_money'] = 'lavar dinheiro',
|
||||
['wash_money_amount'] = 'quantidade a lavar',
|
||||
['withdraw_amount'] = 'retirar montante',
|
||||
['withdraw_society_money'] = 'retirar dinheiro da sociedade',
|
||||
['yes'] = 'sim',
|
||||
['you_have'] = 'você tem ~g~$%s~s~ esperando lavagem de dinheiro (24h).',
|
||||
['you_have_laundered'] = 'você lavou ~g~$%s~s~ do seu dinheiro ',
|
||||
['you_have_hired'] = 'você recrutou %s',
|
||||
['you_have_been_hired'] = 'você foi contratado por %s',
|
||||
['you_have_fired'] = 'você demitiu %s',
|
||||
['you_have_been_fired'] = 'você foi demitido de %s',
|
||||
['you_have_promoted'] = 'você promoveu %s a %s',
|
||||
['you_have_been_promoted'] = 'você foi promovido ~b~promoted~s~!',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations = {
|
||||
['actions'] = 'akce',
|
||||
['boss_menu'] = 'akce šéfa',
|
||||
['money_generic'] = '$%s',
|
||||
['deposit_amount'] = 'množství vkladu',
|
||||
['deposit_society_money'] = 'vložit peníze do společnosti',
|
||||
['do_you_want_to_recruit'] = 'chceš najmout %s?',
|
||||
['employee'] = 'zaměstnanec',
|
||||
['employee_list'] = 'seznam zaměstnanců',
|
||||
['employee_management'] = 'správa zaměstnanců',
|
||||
['fire'] = 'vyhodit',
|
||||
['grade'] = 'povýšit',
|
||||
['have_deposited'] = 'vložil jsi ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'vybral jsi ~g~$%s~s~',
|
||||
['invalid_amount'] = 'neplatná částka',
|
||||
['invalid_amount_max'] = 'tento plat není povolen',
|
||||
['no'] = 'ne',
|
||||
['promote'] = 'povýšit',
|
||||
['promote_employee'] = 'povýšit %s',
|
||||
['recruit'] = 'najmout',
|
||||
['recruiting'] = 'najímání',
|
||||
['salary_amount'] = 'váše platu',
|
||||
['salary_management'] = 'správa platů',
|
||||
['wash_money'] = 'vyprat peníze',
|
||||
['wash_money_amount'] = 'množství na vyprání',
|
||||
['withdraw_amount'] = 'výběr peněz',
|
||||
['withdraw_society_money'] = 'vybrat peníze společnosti',
|
||||
['yes'] = 'ano',
|
||||
['you_have'] = 'máš ~g~$%s~s~ čekajících na vyprání~s~ (24h).',
|
||||
['you_have_laundered'] = '~r~Vypral jsi~s~ tvé peníze: ~g~$%s~s~',
|
||||
['you_have_hired'] = 'najmul jsi %s',
|
||||
['you_have_been_hired'] = 'byl jsi najmut hráčem %s',
|
||||
['you_have_fired'] = 'vyhodil jsi %s',
|
||||
['you_have_been_fired'] = 'byl jsi vyhozen hráčem %s',
|
||||
['you_have_promoted'] = 'byl jsi povýšen hráčem %s na %s',
|
||||
['you_have_been_promoted'] = 'byl jsi ~b~povýšen~s~!',
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations = {
|
||||
['actions'] = 'actions',
|
||||
['boss_menu'] = 'boss menu',
|
||||
['money_generic'] = '$%s',
|
||||
['deposit_amount'] = 'deposit amount',
|
||||
['deposit_society_money'] = 'deposit society money',
|
||||
['do_you_want_to_recruit'] = 'do you want to recruit %s?',
|
||||
['employee'] = 'employee',
|
||||
['employee_list'] = 'employee list',
|
||||
['employee_management'] = 'employee management',
|
||||
['fire'] = 'fire',
|
||||
['grade'] = 'grade',
|
||||
['have_deposited'] = 'you have deposited ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'you have withdrawn ~g~$%s~s~',
|
||||
['invalid_amount'] = 'invalid amount',
|
||||
['invalid_amount_max'] = 'that salary is not allowed',
|
||||
['no'] = 'no',
|
||||
['promote'] = 'promote',
|
||||
['promote_employee'] = 'promote %s',
|
||||
['recruit'] = 'recruit',
|
||||
['recruiting'] = 'recruiting',
|
||||
['salary_amount'] = 'salary amount',
|
||||
['salary_management'] = 'salary management',
|
||||
['wash_money'] = 'wash money',
|
||||
['wash_money_amount'] = 'amount to wash',
|
||||
['withdraw_amount'] = 'witdraw amount',
|
||||
['withdraw_society_money'] = 'withdraw society money',
|
||||
['yes'] = 'yes',
|
||||
['you_have'] = 'you have ~g~$%s~s~ waiting in ~y~money laundering~s~ (24h).',
|
||||
['you_have_laundered'] = 'you have ~r~laundered~s~ your money: ~g~$%s~s~',
|
||||
['you_have_hired'] = 'you have recruited %s',
|
||||
['you_have_been_hired'] = 'you have been hired by %s',
|
||||
['you_have_fired'] = 'you have fired %s',
|
||||
['you_have_been_fired'] = 'you have been fired from %s',
|
||||
['you_have_promoted'] = 'you have promoted %s as %s',
|
||||
['you_have_been_promoted'] = 'you have been ~b~promoted~s~!',
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations = {
|
||||
['actions'] = 'toiminnot',
|
||||
['boss_menu'] = 'boss menu',
|
||||
['money_generic'] = '€%s',
|
||||
['deposit_amount'] = 'talletus summa',
|
||||
['deposit_society_money'] = 'talleta yritykselle rahaa',
|
||||
['do_you_want_to_recruit'] = 'do you want to recruit %s?',
|
||||
['employee'] = 'työntekijä',
|
||||
['employee_list'] = 'työntekijä lista',
|
||||
['employee_management'] = 'työntekijöiden hallinta',
|
||||
['fire'] = 'anna potkut',
|
||||
['grade'] = 'taso',
|
||||
['have_deposited'] = 'sinä talletit ~r~€%s~s~',
|
||||
['have_withdrawn'] = 'sinä nostit ~g~€%s~s~',
|
||||
['invalid_amount'] = 'virheellinen summa',
|
||||
['invalid_amount_max'] = 'that salary is not allowed',
|
||||
['no'] = 'ei',
|
||||
['promote'] = 'ylennä',
|
||||
['promote_employee'] = 'ylennä henkilö %s',
|
||||
['recruit'] = 'rekrytoi',
|
||||
['recruiting'] = 'rekrytointi',
|
||||
['salary_amount'] = 'palkan määrä',
|
||||
['salary_management'] = 'palkan hallinta',
|
||||
['wash_money'] = 'pese rahaa',
|
||||
['wash_money_amount'] = 'pestävä määrä',
|
||||
['withdraw_amount'] = 'nostettava määrä',
|
||||
['withdraw_society_money'] = 'nosta yrityksen rahoja',
|
||||
['yes'] = 'kyllä',
|
||||
['you_have'] = 'you have ~g~€%s~s~ waiting in ~y~money laundering~s~ (24h).',
|
||||
['you_have_laundered'] = 'olet ~r~pessyt~s~ rahojasi: ~g~€%s~s~',
|
||||
['you_have_hired'] = 'sinä palkkasit henkilön %s',
|
||||
['you_have_been_hired'] = 'sinut on palkattu pelaajan %s toimesta',
|
||||
['you_have_fired'] = 'sinä annoit potkut pelaajalle %s',
|
||||
['you_have_been_fired'] = 'sinulle annettiin potkut työstä %s',
|
||||
['you_have_promoted'] = 'sinä ylensit henkilön %s arvolle %s',
|
||||
['you_have_been_promoted'] = 'sinut ylennettiin',
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations = {
|
||||
['actions'] = 'actions',
|
||||
['boss_menu'] = 'patron',
|
||||
['money_generic'] = '$%s',
|
||||
['deposit_amount'] = 'montant du dépôt',
|
||||
['deposit_society_money'] = 'déposer argent société',
|
||||
['do_you_want_to_recruit'] = 'Voulez-vous recruter %s?',
|
||||
['employee'] = 'employé',
|
||||
['employee_list'] = 'liste des employés',
|
||||
['employee_management'] = 'gestion employés',
|
||||
['fire'] = 'licencier',
|
||||
['grade'] = 'grade',
|
||||
['have_deposited'] = 'vous avez déposé ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'vous avez retiré ~g~$%s~s~',
|
||||
['invalid_amount'] = 'montant invalide',
|
||||
['invalid_amount_max'] = 'that salary is not allowed',
|
||||
['no'] = 'non',
|
||||
['promote'] = 'promouvoir',
|
||||
['promote_employee'] = 'promouvoir %s',
|
||||
['recruit'] = 'recruter',
|
||||
['recruiting'] = 'recrutement',
|
||||
['salary_amount'] = 'montant du salaire',
|
||||
['salary_management'] = 'gestion salaires',
|
||||
['wash_money'] = 'blanchir argent',
|
||||
['wash_money_amount'] = 'montant à blanchir',
|
||||
['withdraw_amount'] = 'montant du retrait',
|
||||
['withdraw_society_money'] = 'retirer argent société',
|
||||
['yes'] = 'oui',
|
||||
['you_have'] = 'vous avez ~g~$%s~s~ en attente de ~r~blanchiement~s~ (24h).',
|
||||
['you_have_laundered'] = 'vous avez ~r~blanchi~s~ votre argent : ~g~$%s~s~',
|
||||
['you_have_hired'] = 'Vous avez recruté %s',
|
||||
['you_have_been_hired'] = 'Vous avez été recruté dans la société %s',
|
||||
['you_have_fired'] = 'Vous avez viré %s',
|
||||
['you_have_been_fired'] = 'Vous avez été viré de la société %s',
|
||||
['you_have_promoted'] = 'Vous avez promu %s en tant que %s',
|
||||
['you_have_been_promoted'] = 'Vous avez été promu',
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
Translations = {
|
||||
['actions'] = 'acties',
|
||||
['boss_menu'] = 'baas menu',
|
||||
['money_generic'] = '€%s',
|
||||
['deposit_amount'] = 'stort hoeveelheid',
|
||||
['deposit_society_money'] = 'stort maatschappij geld',
|
||||
['do_you_want_to_recruit'] = 'Wil je %s aannemen?',
|
||||
['employee'] = 'werknemer',
|
||||
['employee_list'] = 'werknemer lijst',
|
||||
['employee_management'] = 'werknemer beheer',
|
||||
['fire'] = 'ontslaan',
|
||||
['grade'] = 'schaal',
|
||||
['have_deposited'] = 'je hebt gestort ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'je hebt opgenomen ~g~$%s~s~',
|
||||
['invalid_amount'] = 'ongeldige hoeveelheid',
|
||||
['invalid_amount_max'] = 'dit salaris is niet toegestaan',
|
||||
['no'] = 'nee',
|
||||
['promote'] = 'promoveer',
|
||||
['promote_employee'] = 'promoveer %s',
|
||||
['recruit'] = 'werv',
|
||||
['recruiting'] = 'werven',
|
||||
['salary_amount'] = 'salaris hoeveelheid',
|
||||
['salary_management'] = 'salaris beheer',
|
||||
['wash_money'] = 'witwas geld',
|
||||
['wash_money_amount'] = 'hoeveelheid om wit te wassen',
|
||||
['withdraw_amount'] = 'opneem hoeveelheid',
|
||||
['withdraw_society_money'] = 'neem maatschappelijk geld op',
|
||||
['yes'] = 'ja',
|
||||
['you_have'] = 'je hebt ~g~€%s~s~ staan in ~y~geld witwassen~s~ (24h).',
|
||||
['you_have_laundered'] = 'je hebt je geld: ~g~€%s~s~ ~r~witgewassen~s~ ',
|
||||
['you_have_hired'] = 'je bent gevraagt %s',
|
||||
['you_have_been_hired'] = 'je bent aangenomen door %s',
|
||||
['you_have_fired'] = 'je bent ontslagen %s',
|
||||
['you_have_been_fired'] = 'je bent ondslagen van %s',
|
||||
['you_have_promoted'] = 'je hebt gepromoveerd %s naar %s',
|
||||
['you_have_been_promoted'] = 'je bent ~b~gepromoveerd~s~!',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations = {
|
||||
['actions'] = 'akcje',
|
||||
['boss_menu'] = 'boss menu',
|
||||
['money_generic'] = '$%s',
|
||||
['deposit_amount'] = 'ilość depozytu',
|
||||
['deposit_society_money'] = 'zdeponuj społeczne pieniądze',
|
||||
['do_you_want_to_recruit'] = 'czy chcesz zrekrutować %s?',
|
||||
['employee'] = 'pracownik',
|
||||
['employee_list'] = 'lista pracowników',
|
||||
['employee_management'] = 'zarządzanie pracownikami',
|
||||
['fire'] = 'zwolnij',
|
||||
['grade'] = 'stopień',
|
||||
['have_deposited'] = 'zdeponowałeś ~r~$%s~s~',
|
||||
['have_withdrawn'] = 'wypłaciłeś ~g~$%s~s~',
|
||||
['invalid_amount'] = 'nieprawidłowa wartość',
|
||||
['invalid_amount_max'] = 'that salary is not allowed',
|
||||
['no'] = 'nie',
|
||||
['promote'] = 'awansuj',
|
||||
['promote_employee'] = 'awansuj %s',
|
||||
['recruit'] = 'zrekrutuj',
|
||||
['recruiting'] = 'rekrutacja',
|
||||
['salary_amount'] = 'wartość wynagrodzenia',
|
||||
['salary_management'] = 'zarządzaj wynagrodzeniem',
|
||||
['wash_money'] = 'wypierz pieniądze',
|
||||
['wash_money_amount'] = 'wartość do wyprania',
|
||||
['withdraw_amount'] = 'wartość wypłaty',
|
||||
['withdraw_society_money'] = 'wypłać społeczne pieniądze',
|
||||
['yes'] = 'tak',
|
||||
['you_have'] = 'masz ~g~%s$~s~ czekanie ~y~w pralni pieniędzmi~s~ (24h).',
|
||||
['you_have_laundered'] = '~r~Wyprałeś~s~ twoje pieniądze: ~g~$%s~s~',
|
||||
['you_have_hired'] = 'zatrudniłeś %s',
|
||||
['you_have_been_hired'] = 'zostałeś zatrudniony przez %s',
|
||||
['you_have_fired'] = 'zwolniłeś %s',
|
||||
['you_have_been_fired'] = 'zostałeś zwolniony %s',
|
||||
['you_have_promoted'] = 'awansowałeś %s na %s',
|
||||
['you_have_been_promoted'] = 'zostałeś awansowany',
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
Translations= {
|
||||
['actions'] = 'handlingar',
|
||||
['boss_menu'] = 'chefmeny',
|
||||
['money_generic'] = '%s SEK',
|
||||
['deposit_amount'] = 'insättningsbelopp',
|
||||
['deposit_society_money'] = 'insätt samhälls pengar',
|
||||
['do_you_want_to_recruit'] = 'vill du anställa %s?',
|
||||
['employee'] = 'anställd',
|
||||
['employee_list'] = 'anställningslista',
|
||||
['employee_management'] = 'medarbetarhantering',
|
||||
['fire'] = 'sparka',
|
||||
['grade'] = 'grade',
|
||||
['have_deposited'] = 'du har satt in ~r~%s SEK~s~',
|
||||
['have_withdrawn'] = 'du har tagit ut ~g~%s SEK~s~',
|
||||
['invalid_amount'] = 'ogiltigt belopp',
|
||||
['invalid_amount_max'] = 'den lönen är inte tillåten',
|
||||
['no'] = 'nej',
|
||||
['promote'] = 'befodra',
|
||||
['promote_employee'] = 'befodra %s',
|
||||
['recruit'] = 'rekrytera',
|
||||
['recruiting'] = 'rekrytering',
|
||||
['salary_amount'] = 'lön belopp',
|
||||
['salary_management'] = 'lönhantering',
|
||||
['wash_money'] = 'tvätta pengar',
|
||||
['wash_money_amount'] = 'belopp att tvätta',
|
||||
['withdraw_amount'] = 'Ta ut summan',
|
||||
['withdraw_society_money'] = 'ta ut samhällspengar',
|
||||
['yes'] = 'ja',
|
||||
['you_have'] = 'du har ~g~%s SEK~s~ som väntar på ~y~pengartvätt~s~ (24h).',
|
||||
['you_have_laundered'] = 'du har ~r~tvättat~s~ dina pengar: ~g~%s SEK~s~',
|
||||
['you_have_hired'] = 'du har anställt ~y~%s~s~',
|
||||
['you_have_been_hired'] = 'du har blivit anställd utav %s',
|
||||
['you_have_fired'] = 'du har ~r~sparkat~s~ ~y~%s~s~',
|
||||
['you_have_been_fired'] = 'du har blivit ~r~sparkad~s~ utav ~y~%s~s~',
|
||||
['you_have_promoted'] = 'du har befodrat ~y~%s~s~ till ~b~%s~s~',
|
||||
['you_have_been_promoted'] = 'du har blivit ~b~befodrad~s~',
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
USE `es_extended`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `society_moneywash` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`identifier` varchar(60) NOT NULL,
|
||||
`society` varchar(60) NOT NULL,
|
||||
`amount` int(11) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
@@ -0,0 +1,325 @@
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
AddEventHandler('esx:migrations:ensure', function(register)
|
||||
register('society')
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_society:registerSociety', function(name, label, account, datastore, inventory, data)
|
||||
|
||||
local found = false
|
||||
|
||||
local society = {
|
||||
name = name,
|
||||
label = label,
|
||||
account = account,
|
||||
datastore = datastore,
|
||||
inventory = inventory,
|
||||
data = data
|
||||
}
|
||||
|
||||
for i=1, #self.RegisteredSocieties, 1 do
|
||||
if self.RegisteredSocieties[i].name == name then
|
||||
found, self.RegisteredSocieties[i] = true, society
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
table.insert(self.RegisteredSocieties, society)
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_society:getSocieties', function(cb)
|
||||
cb(self.RegisteredSocieties)
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_society:getSociety', function(name, cb)
|
||||
cb(self.GetSociety(name))
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_society:withdrawMoney')
|
||||
AddEventHandler('esx_society:withdrawMoney', function(societyName, amount)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
local society = self.GetSociety(societyName)
|
||||
amount = ESX.Math.Round(tonumber(amount))
|
||||
|
||||
if xPlayer.job.name == society.name then
|
||||
TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function(account)
|
||||
if amount > 0 and account.money >= amount then
|
||||
account.removeMoney(amount)
|
||||
xPlayer.addMoney(amount)
|
||||
xPlayer.showNotification(_U('society:have_withdrawn', ESX.Math.GroupDigits(amount)))
|
||||
else
|
||||
xPlayer.showNotification(_U('society:invalid_amount'))
|
||||
end
|
||||
end)
|
||||
else
|
||||
print(('esx_society: %s attempted to call withdrawMoney!'):format(xPlayer.identifier))
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_society:depositMoney')
|
||||
AddEventHandler('esx_society:depositMoney', function(societyName, amount)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
local society = self.GetSociety(societyName)
|
||||
amount = ESX.Math.Round(tonumber(amount))
|
||||
|
||||
if xPlayer.job.name == society.name then
|
||||
if amount > 0 and xPlayer.getMoney() >= amount then
|
||||
TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function(account)
|
||||
xPlayer.removeMoney(amount)
|
||||
xPlayer.showNotification(_U('society:have_deposited', ESX.Math.GroupDigits(amount)))
|
||||
account.addMoney(amount)
|
||||
end)
|
||||
else
|
||||
xPlayer.showNotification(_U('society:invalid_amount'))
|
||||
end
|
||||
else
|
||||
print(('esx_society: %s attempted to call depositMoney!'):format(xPlayer.identifier))
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_society:washMoney')
|
||||
AddEventHandler('esx_society:washMoney', function(society, amount)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
local account = xPlayer.getAccount('black_money')
|
||||
amount = ESX.Math.Round(tonumber(amount))
|
||||
|
||||
if xPlayer.job.name == society then
|
||||
if amount and amount > 0 and account.money >= amount then
|
||||
xPlayer.removeAccountMoney('black_money', amount)
|
||||
|
||||
MySQL.Async.execute('INSERT INTO society_moneywash (identifier, society, amount) VALUES (@identifier, @society, @amount)', {
|
||||
['@identifier'] = xPlayer.identifier,
|
||||
['@society'] = society,
|
||||
['@amount'] = amount
|
||||
}, function(rowsChanged)
|
||||
xPlayer.showNotification(_U('society:you_have', ESX.Math.GroupDigits(amount)))
|
||||
end)
|
||||
else
|
||||
xPlayer.showNotification(_U('society:invalid_amount'))
|
||||
end
|
||||
else
|
||||
print(('esx_society: %s attempted to call washMoney!'):format(xPlayer.identifier))
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_society:putVehicleInGarage')
|
||||
AddEventHandler('esx_society:putVehicleInGarage', function(societyName, vehicle)
|
||||
local society = self.GetSociety(societyName)
|
||||
|
||||
TriggerEvent('esx_datastore:getSharedDataStore', society.datastore, function(store)
|
||||
local garage = store.get('garage') or {}
|
||||
table.insert(garage, vehicle)
|
||||
store.set('garage', garage)
|
||||
end)
|
||||
end)
|
||||
|
||||
RegisterServerEvent('esx_society:removeVehicleFromGarage')
|
||||
AddEventHandler('esx_society:removeVehicleFromGarage', function(societyName, vehicle)
|
||||
local society = self.GetSociety(societyName)
|
||||
|
||||
TriggerEvent('esx_datastore:getSharedDataStore', society.datastore, function(store)
|
||||
local garage = store.get('garage') or {}
|
||||
|
||||
for i=1, #garage, 1 do
|
||||
if garage[i].plate == vehicle.plate then
|
||||
table.remove(garage, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
store.set('garage', garage)
|
||||
end)
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:getSocietyMoney', function(source, cb, societyName)
|
||||
local society = self.GetSociety(societyName)
|
||||
|
||||
if society then
|
||||
|
||||
TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function(account)
|
||||
cb(account.money)
|
||||
end)
|
||||
else
|
||||
cb(0)
|
||||
end
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:getEmployees', function(source, cb, society)
|
||||
if Config.EnableESXIdentity then
|
||||
|
||||
MySQL.Async.fetchAll('SELECT firstname, lastname, identifier, job, job_grade FROM users WHERE job = @job ORDER BY job_grade DESC', {
|
||||
['@job'] = society
|
||||
}, function(results)
|
||||
local employees = {}
|
||||
|
||||
for i=1, #results, 1 do
|
||||
table.insert(employees, {
|
||||
name = results[i].firstname .. ' ' .. results[i].lastname,
|
||||
identifier = results[i].identifier,
|
||||
job = {
|
||||
name = results[i].job,
|
||||
label = self.Jobs[results[i].job].label,
|
||||
grade = results[i].job_grade,
|
||||
grade_name = self.Jobs[results[i].job].grades[tostring(results[i].job_grade)].name,
|
||||
grade_label = self.Jobs[results[i].job].grades[tostring(results[i].job_grade)].label
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
cb(employees)
|
||||
end)
|
||||
else
|
||||
MySQL.Async.fetchAll('SELECT name, identifier, job, job_grade FROM users WHERE job = @job ORDER BY job_grade DESC', {
|
||||
['@job'] = society
|
||||
}, function(result)
|
||||
local employees = {}
|
||||
|
||||
for i=1, #result, 1 do
|
||||
table.insert(employees, {
|
||||
name = result[i].name,
|
||||
identifier = result[i].identifier,
|
||||
job = {
|
||||
name = result[i].job,
|
||||
label = self.Jobs[result[i].job].label,
|
||||
grade = result[i].job_grade,
|
||||
grade_name = self.Jobs[result[i].job].grades[tostring(result[i].job_grade)].name,
|
||||
grade_label = self.Jobs[result[i].job].grades[tostring(result[i].job_grade)].label
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
cb(employees)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:getJob', function(source, cb, society)
|
||||
local job = json.decode(json.encode(self.Jobs[society]))
|
||||
local grades = {}
|
||||
|
||||
for k,v in pairs(job.grades) do
|
||||
table.insert(grades, v)
|
||||
end
|
||||
|
||||
table.sort(grades, function(a, b)
|
||||
return a.grade < b.grade
|
||||
end)
|
||||
|
||||
job.grades = grades
|
||||
|
||||
cb(job)
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:setJob', function(source, cb, identifier, job, grade, type)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
local isBoss = xPlayer.job.grade_name == 'boss'
|
||||
|
||||
if isBoss then
|
||||
local xTarget = ESX.GetPlayerFromIdentifier(identifier)
|
||||
|
||||
if xTarget then
|
||||
xTarget.setJob(job, grade)
|
||||
|
||||
if type == 'hire' then
|
||||
xTarget.showNotification(_U('society:you_have_been_hired', job))
|
||||
elseif type == 'promote' then
|
||||
xTarget.showNotification(_U('society:you_have_been_promoted'))
|
||||
elseif type == 'fire' then
|
||||
xTarget.showNotification(_U('society:you_have_been_fired', xTarget.getJob().label))
|
||||
end
|
||||
|
||||
cb()
|
||||
else
|
||||
MySQL.Async.execute('UPDATE users SET job = @job, job_grade = @job_grade WHERE identifier = @identifier', {
|
||||
['@job'] = job,
|
||||
['@job_grade'] = grade,
|
||||
['@identifier'] = identifier
|
||||
}, function(rowsChanged)
|
||||
cb()
|
||||
end)
|
||||
end
|
||||
else
|
||||
print(('esx_society: %s attempted to setJob'):format(xPlayer.identifier))
|
||||
cb()
|
||||
end
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:setJobSalary', function(source, cb, job, grade, salary)
|
||||
local xPlayer = ESX.GetPlayerFromId(source)
|
||||
|
||||
if xPlayer.job.name == job and xPlayer.job.grade_name == 'boss' then
|
||||
if salary <= Config.MaxSalary then
|
||||
MySQL.Async.execute('UPDATE job_grades SET salary = @salary WHERE job_name = @job_name AND grade = @grade', {
|
||||
['@salary'] = salary,
|
||||
['@job_name'] = job,
|
||||
['@grade'] = grade
|
||||
}, function(rowsChanged)
|
||||
self.Jobs[job].grades[tostring(grade)].salary = salary
|
||||
local xPlayers = ESX.GetPlayers()
|
||||
|
||||
for i=1, #xPlayers, 1 do
|
||||
local xTarget = ESX.GetPlayerFromId(xPlayers[i])
|
||||
|
||||
if xTarget.job.name == job and xTarget.job.grade == grade then
|
||||
xTarget.setJob(job, grade)
|
||||
end
|
||||
end
|
||||
|
||||
cb()
|
||||
end)
|
||||
else
|
||||
print(('esx_society: %s attempted to setJobSalary over config limit!'):format(xPlayer.identifier))
|
||||
cb()
|
||||
end
|
||||
else
|
||||
print(('esx_society: %s attempted to setJobSalary'):format(xPlayer.identifier))
|
||||
cb()
|
||||
end
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:getOnlinePlayers', function(source, cb)
|
||||
local xPlayers = ESX.GetPlayers()
|
||||
local players = {}
|
||||
|
||||
for i=1, #xPlayers, 1 do
|
||||
local xPlayer = ESX.GetPlayerFromId(xPlayers[i])
|
||||
table.insert(players, {
|
||||
source = xPlayer.source,
|
||||
identifier = xPlayer.identifier,
|
||||
name = xPlayer.name,
|
||||
job = xPlayer.job
|
||||
})
|
||||
end
|
||||
|
||||
cb(players)
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:getVehiclesInGarage', function(source, cb, societyName)
|
||||
local society = self.GetSociety(societyName)
|
||||
|
||||
TriggerEvent('esx_datastore:getSharedDataStore', society.datastore, function(store)
|
||||
local garage = store.get('garage') or {}
|
||||
cb(garage)
|
||||
end)
|
||||
end)
|
||||
|
||||
ESX.RegisterServerCallback('esx_society:isBoss', function(source, cb, job)
|
||||
cb(isPlayerBoss(source, job))
|
||||
end)
|
||||
|
||||
MySQL.ready(function()
|
||||
local result = MySQL.Sync.fetchAll('SELECT * FROM jobs', {})
|
||||
|
||||
for i=1, #result, 1 do
|
||||
self.Jobs[result[i].name] = result[i]
|
||||
self.Jobs[result[i].name].grades = {}
|
||||
end
|
||||
|
||||
local result2 = MySQL.Sync.fetchAll('SELECT * FROM job_grades', {})
|
||||
|
||||
for i=1, #result2, 1 do
|
||||
self.Jobs[result2[i].job_name].grades[tostring(result2[i].grade)] = result2[i]
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,5 @@
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
self.Init()
|
||||
|
||||
TriggerEvent('cron:runAt', 3, 0, self.WashMoneyCRON)
|
||||
@@ -0,0 +1,56 @@
|
||||
ESX.Modules['society'] = {}
|
||||
local self = ESX.Modules['society']
|
||||
|
||||
self.Jobs = {}
|
||||
self.RegisteredSocieties = {}
|
||||
|
||||
self.Init = function()
|
||||
|
||||
local translations = ESX.EvalFile(GetCurrentResourceName(), 'modules/society/data/locales/' .. Config.Locale .. '.lua')['Translations']
|
||||
LoadLocale('society', Config.Locale, translations)
|
||||
|
||||
end
|
||||
|
||||
self.GetSociety = function(name)
|
||||
for i=1, #self.RegisteredSocieties, 1 do
|
||||
if self.RegisteredSocieties[i].name == name then
|
||||
return self.RegisteredSocieties[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.isPlayerBoss = function(playerId, job)
|
||||
local xPlayer = ESX.GetPlayerFromId(playerId)
|
||||
|
||||
if xPlayer.job.name == job and xPlayer.job.grade_name == 'boss' then
|
||||
return true
|
||||
else
|
||||
print(('esx_society: %s attempted open a society boss menu!'):format(xPlayer.identifier))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
self.WashMoneyCRON = function(d, h, m)
|
||||
MySQL.Async.fetchAll('SELECT * FROM society_moneywash', {}, function(result)
|
||||
for i=1, #result, 1 do
|
||||
local society = self.GetSociety(result[i].society)
|
||||
local xPlayer = ESX.GetPlayerFromIdentifier(result[i].identifier)
|
||||
|
||||
-- add society money
|
||||
TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function(account)
|
||||
account.addMoney(result[i].amount)
|
||||
end)
|
||||
|
||||
-- send notification if player is online
|
||||
if xPlayer then
|
||||
xPlayer.showNotification(_U('society:you_have_laundered', ESX.Math.GroupDigits(result[i].amount)))
|
||||
end
|
||||
|
||||
MySQL.Async.execute('DELETE FROM society_moneywash WHERE id = @id', {
|
||||
['@id'] = result[i].id
|
||||
})
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user