├── .editorconfig
├── DATABASE.sql
├── LICENSE
├── README.md
├── client
├── common.lua
├── entityiter.lua
├── functions.lua
├── main.lua
├── modules
│ ├── death.lua
│ ├── scaleform.lua
│ └── streaming.lua
└── wrapper.lua
├── common
├── functions.lua
└── modules
│ ├── math.lua
│ └── table.lua
├── config.lua
├── config.weapons.lua
├── config_s.lua
├── fxmanifest.lua
├── html
├── css
│ └── app.css
├── fonts
│ ├── bankgothic.ttf
│ └── pdown.ttf
├── img
│ └── accounts
│ │ ├── bank.png
│ │ ├── black_money.png
│ │ └── money.png
├── js
│ ├── app.js
│ ├── mustache.min.js
│ └── wrapper.js
└── ui.html
├── locale.js
├── locale.lua
├── locales
└── en.lua
└── server
├── classes
└── player.lua
├── commands.lua
├── common.lua
├── functions.lua
├── main.lua
└── paycheck.lua
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_size = 4
5 | indent_style = tab
6 | end_of_line = crlf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
--------------------------------------------------------------------------------
/DATABASE.sql:
--------------------------------------------------------------------------------
1 | -- --------------------------------------------------------
2 | -- Host: localhost
3 | -- Versión del servidor: 10.5.4-MariaDB-log - mariadb.org binary distribution
4 | -- SO del servidor: Win64
5 | -- HeidiSQL Versión: 11.0.0.5919
6 | -- --------------------------------------------------------
7 |
8 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
9 | /*!40101 SET NAMES utf8 */;
10 | /*!50503 SET NAMES utf8mb4 */;
11 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
12 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
13 |
14 | -- Volcando estructura para tabla apzombies.users
15 | CREATE TABLE IF NOT EXISTS `users` (
16 | `id` int(11) NOT NULL AUTO_INCREMENT,
17 | `identifier` varchar(40) NOT NULL,
18 | `characterId` int(20) DEFAULT 1,
19 | `unlockCharacters` int(11) DEFAULT 0,
20 | `isVip` int(11) DEFAULT 0,
21 | `tutorial` int(11) NOT NULL DEFAULT 0,
22 | `accounts` longtext DEFAULT NULL,
23 | `group` varchar(50) DEFAULT 'user',
24 | `inventory` longtext DEFAULT NULL,
25 | `job` varchar(20) DEFAULT 'unemployed',
26 | `job_grade` int(11) DEFAULT 0,
27 | `job2` varchar(20) DEFAULT 'unemployed',
28 | `job_grade2` int(11) unsigned NOT NULL DEFAULT 0,
29 | `loadout` longtext DEFAULT NULL,
30 | `position` varchar(255) DEFAULT '{"heading":204.0,"x":-539.2,"y":-214.5,"z":38.65}',
31 | `firstname` varchar(50) DEFAULT NULL,
32 | `lastname` varchar(50) DEFAULT NULL,
33 | `sex` char(50) DEFAULT 'f',
34 | `dob` varchar(50) DEFAULT NULL,
35 | `height` varchar(50) DEFAULT NULL,
36 | `job_invitation` varchar(255) DEFAULT NULL,
37 | PRIMARY KEY (`identifier`,`id`) USING BTREE,
38 | KEY `id` (`id`)
39 | ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
40 |
41 | -- La exportación de datos fue deseleccionada.
42 |
43 | -- Volcando estructura para tabla nex_db.users_characters
44 | CREATE TABLE IF NOT EXISTS `users_characters` (
45 | `characterId` int(11) NOT NULL AUTO_INCREMENT,
46 | `identifier` varchar(255) NOT NULL,
47 | `isVip` int(11) NOT NULL DEFAULT 0,
48 | `inventory` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '{}',
49 | `accounts` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '{"bank":3000}',
50 | `job` varchar(20) NOT NULL DEFAULT 'unemployed',
51 | `job_grade` int(11) NOT NULL DEFAULT 0,
52 | `job2` varchar(20) NOT NULL DEFAULT 'unemployed',
53 | `job_grade2` int(11) NOT NULL DEFAULT 0,
54 | `loadout` longtext DEFAULT NULL,
55 | `position` varchar(255) DEFAULT '{"heading":204.0,"x":-539.2,"y":-214.5,"z":38.65}',
56 | `firstname` varchar(50) NOT NULL,
57 | `lastname` varchar(50) NOT NULL,
58 | `sex` char(50) NOT NULL DEFAULT 'f',
59 | `dob` varchar(50) NOT NULL,
60 | `height` varchar(50) NOT NULL,
61 | `job_invitation` varchar(255) DEFAULT NULL,
62 | `phone_number` varchar(10) DEFAULT NULL,
63 | PRIMARY KEY (`characterId`),
64 | KEY `charid` (`characterId`) USING BTREE,
65 | KEY `identifier` (`identifier`)
66 | ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;
67 |
68 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
69 | /*!40101 SET NAMES utf8 */;
70 | /*!50503 SET NAMES utf8mb4 */;
71 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
72 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
73 |
74 | -- Volcando estructura para tabla apzombies.items
75 | CREATE TABLE IF NOT EXISTS `items` (
76 | `name` varchar(50) NOT NULL,
77 | `label` varchar(50) NOT NULL,
78 | `weight` int(11) NOT NULL DEFAULT 1,
79 | `rare` tinyint(4) NOT NULL DEFAULT 0,
80 | `can_remove` tinyint(4) NOT NULL DEFAULT 1,
81 | PRIMARY KEY (`name`)
82 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
83 |
84 | -- La exportación de datos fue deseleccionada.
85 |
86 | -- Volcando estructura para tabla apzombies.jobs
87 | CREATE TABLE IF NOT EXISTS `jobs` (
88 | `name` varchar(50) NOT NULL,
89 | `label` varchar(50) DEFAULT NULL,
90 | `whitelisted` int(11) DEFAULT 0,
91 | PRIMARY KEY (`name`),
92 | KEY `name` (`name`)
93 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
94 |
95 | -- La exportación de datos fue deseleccionada.
96 |
97 | -- Volcando estructura para tabla apzombies.job_grades
98 | CREATE TABLE IF NOT EXISTS `job_grades` (
99 | `id` int(11) NOT NULL AUTO_INCREMENT,
100 | `job_name` varchar(50) DEFAULT NULL,
101 | `grade` int(11) NOT NULL,
102 | `name` varchar(50) NOT NULL,
103 | `label` varchar(50) NOT NULL,
104 | `salary` int(11) NOT NULL,
105 | PRIMARY KEY (`id`)
106 | ) ENGINE=InnoDB AUTO_INCREMENT=98 DEFAULT CHARSET=latin1;
107 |
108 |
109 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
110 | /*!40101 SET NAMES utf8 */;
111 | /*!50503 SET NAMES utf8mb4 */;
112 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
113 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
114 |
115 | -- Volcando estructura para tabla apzombies.jobs
116 | CREATE TABLE IF NOT EXISTS `jobs` (
117 | `name` varchar(50) NOT NULL,
118 | `label` varchar(50) DEFAULT NULL,
119 | `whitelisted` int(11) DEFAULT 0,
120 | PRIMARY KEY (`name`),
121 | KEY `name` (`name`)
122 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
123 |
124 | -- Volcando datos para la tabla apzombies.jobs: ~22 rows (aproximadamente)
125 | /*!40000 ALTER TABLE `jobs` DISABLE KEYS */;
126 | INSERT INTO `jobs` (`name`, `label`, `whitelisted`) VALUES ('unemployed', 'Desempleado', 0);
127 | /*!40000 ALTER TABLE `jobs` ENABLE KEYS */;
128 |
129 |
130 | -- Volcando datos para la tabla apzombies.job_grades: ~95 rows (aproximadamente)
131 | /*!40000 ALTER TABLE `job_grades` DISABLE KEYS */;
132 | INSERT INTO `job_grades` (`id`, `job_name`, `grade`, `name`, `label`, `salary`) VALUES
133 | (1, 'unemployed', 0, 'desempleado', 'Sin trabajo', 200);
134 | /*!40000 ALTER TABLE `job_grades` ENABLE KEYS */;
135 |
136 | /*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
137 | /*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
138 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Nexus Core
4 |
5 | Community Support NexCorp Discord: https://discord.gg/rmCv7UJVPD
6 | See the wiki: https://github.com/NexCorp/Core/wiki
7 |
8 | **What is?**
9 | ESX 1.2 Extended Version
10 |
11 | This version of the original kernel has been modified for the exclusive use of the servers **Nexus Life** *(closed*), **Goodlife RP** *(closed)*, **Aftermath AP**, **El Condado RP** and other servers of their same creators.
12 |
13 | Although this modification was private, the developers have chosen to release a (not final) version of a working kernel for certain purposes. We believe that the community does not value the work of developers very much,
14 | **always looking to steal the work of others**. To avoid this event again in our history, it has been launched, so that those who know what they are doing, can edit it, improve it and above all continue working on it, for those who want to make it stronger and more robust.
15 |
16 |
17 | ## Our history
18 | We were born from the cave of wolves, looking to innovate, but without wasting time, we found ESX, specifically version 1.2, which to our liking, was the best that would help us to easily modify and implement. We build a server at our discretion, based on the criticism and opinions of our community, which by the way, we are developers from Chile, although the **main director of this project has been AlexBanPer (Alejandro Martínez) in its entirety**. Although, we were not so well known in the world, we had our days of fame, although really everything is exhausted when small communities start dividing like cells exponentially and divide the same people, with 10, 20 or even 30 new servers every day.
19 |
20 | Well, let's stop with sad stories that probably few will read and let's go with what matters.
21 |
22 | 
23 |
24 | **Condition**
25 | These scripts were quickly converted from an in-house project to open source, so they are not well suited for third-party use yet. Improving this adaptation is one of the top development priorities, specifically:
26 |
27 | - Many of the scripts are dependent on each other.
28 | - Network functions are completely disabled with external connections.
29 | - Documentation for third parties (eg "how do I run this?")
30 | - Some scripts do not have a proper configuration file, so the source code must be modified.
31 |
32 | **Private Extensions**
33 |
34 | We are worked hard to make some scripts, sincerely these scripts are made with love. So, some scripts like **Nexus Anti Cheat** *(NAC)*, **Factions Manager** *(NFM)*, **Nexus Administration** *(NAD)*, **NAC Assistant** *[DiscordBot] (NAS)*, **Nexus SYNC** *(NESY)*, Nex Vehicles *(NEV)* and **Metabolism UI** *(NEMUI)* are private scripts for now...
35 |
36 | **Why?** Simply. This is our work, the majory are working in the server side, so, this can't be leaked easily. Contact with *AlexBanPer* for more information.
37 | Maybe in some time, this scripts may be released for open source.
38 |
39 | Remember, the **most feature of this is the possibility to create multi characters** in the same core (with some extensions as nex_characters)
40 |
41 | However, we want to publish and expand this resource further, so that everyone can undertake a new server or modify your actual.
42 |
43 |
44 | Important:
45 |
46 | : **IT IS POSSIBLE** to migrate **ANY** script from **ESX to NEX** (see below).
47 |
48 | 
49 |
50 | | SCRIPT NAME | VERSION | LANGUAGE | Description | Status
51 | |--|--|--| -- | -- |
52 | | nex_core | 2.0 | LUA, HTML, CSS & JS | Core of everything | Deployed Open Source
53 | | nex_administration | 1.0 | LUA | Main Menu for administration of characters, punishments and NAC features | Closed Source
54 | | nex_characters | 1.2 | LUA, HTML, CSS & JS | Character Manager | Work for deploy
55 | | nex_basic | 2.0 | LUA | Basic functions for RP (or any) server. Over 20 modular functions | Work for deploy
56 | | nex_hifi | 2.0 | LUA | Radio in game, (*movable with nex_factions*) With entity and sound tracking | Work for deploy
57 |
58 | See more in [Extensions for NexCore](https://github.com/NexCorp/Core/wiki/Extensions)
59 |
60 | 
61 |
62 | ----
63 | **Attention:** Using the core by itself will NOT allow you to create multiple characters, and you must wait for the launch of the nex_characters extension (full control of the characters) but you can develop for nex_core in the meantime.
64 |
65 | The core has been created by and for a Spanish community, so literally any native ESX translation file was omitted, any translation must be implemented in your native language, dear developer.
66 |
67 | ----
68 |
69 | **NEX Core offers stability**, coming from the previous versions of ESX, Nex Core was modified to create multiple characters from the server base, without the need to adapt other scripts, although yes, to create modifications to it, we must always think in two or more, no longer in one.
70 |
71 | This modification contemplates the following:
72 | - New administrative commands .
73 | - New systems totally rewritten for greater stability.
74 | - New synchronization systems.
75 | - New xPlayer functions.
76 | - New client / server functions.
77 | - New integrated notifications.
78 | - Fixes of functions that required stability.
79 | - Live reload of jobs.
80 | - Live reloading of the waiting queue.
81 | - 7 new types of logs for Discord.
82 | - (WIP) Client security for code injections
83 | - Automatic script start system.
84 | - Hard reset of all scripts without causing problems.
85 | - Multiple jobs for each character (WIP)
86 | - Some other admin and player commands.
87 | - Paycheck with bonuses and taxes for vips.
88 | - Much more content with mods for NEX
89 |
90 | 
91 |
92 | We will be working on a cautious WIKI, for all those who have no programming knowledge, however we will leave the simplest.
93 |
94 | **For each client side script:**
95 |
96 | 1. Add in `config_s.lua` -> `ConfigServer.SecureResources` the name of the resources.
97 | 2. In the client side, for e.g `main.lua` replace the common esx thread for:
98 |
99 | ```
100 | NEX = nil -- Can be ESX if you want
101 | Citizen.CreateThread(function()
102 | while NEX == nil do
103 | TriggerEvent('nexus:getNexusObject', GetCurrentResourceName(), function(obj)
104 | NEX = obj
105 | end)
106 | Citizen.Wait(50)
107 | end
108 | end)
109 | ```
110 |
111 | **For each server side script:**
112 |
113 | 1. You can hold the same code or change ESX variable to NEX, but you must change the event handler for:
114 | ```
115 | TriggerEvent('nexus:getNexusObject', function(obj) NEX = obj end)
116 | ```
117 | And ready! You are already working with NEX Core for your server, now we have to wait to install extensions.
118 |
119 | **We strongly recommend not installing nex core for production use, as nex_characters is required for full operation.**
120 |
--------------------------------------------------------------------------------
/client/common.lua:
--------------------------------------------------------------------------------
1 | AddEventHandler('nexus:getNexusObject', function(resourceName, cb)
2 | local data = {}
3 | Citizen.Wait(200)
4 | -- NEX.TriggerServerCallback('nexus:Core:CheckResourceName', function(accepted)
5 | -- if accepted then
6 | -- return cb(NEX)
7 | -- end
8 | -- end, resourceName)
9 | return cb(NEX)
10 | end)
11 |
12 | function getSharedObject()
13 | return NEX
14 | end
15 |
16 | RegisterNetEvent('nex:Core:triggerClientCallback')
17 | AddEventHandler('nex:Core:triggerClientCallback', function(name, requestId, ...)
18 | NEX.TriggerClientCallback(name, function(...)
19 | TriggerServerEvent('nex:Core:clientCallback', requestId, ...)
20 | end, ...)
21 | end)
--------------------------------------------------------------------------------
/client/entityiter.lua:
--------------------------------------------------------------------------------
1 | local entityEnumerator = {
2 | __gc = function(enum)
3 | if enum.destructor and enum.handle then
4 | enum.destructor(enum.handle)
5 | end
6 |
7 | enum.destructor = nil
8 | enum.handle = nil
9 | end
10 | }
11 |
12 | local function EnumerateEntities(initFunc, moveFunc, disposeFunc)
13 | return coroutine.wrap(function()
14 | local iter, id = initFunc()
15 | if not id or id == 0 then
16 | disposeFunc(iter)
17 | return
18 | end
19 |
20 | local enum = {handle = iter, destructor = disposeFunc}
21 | setmetatable(enum, entityEnumerator)
22 | local next = true
23 |
24 | repeat
25 | coroutine.yield(id)
26 | next, id = moveFunc(iter)
27 | until not next
28 |
29 | enum.destructor, enum.handle = nil, nil
30 | disposeFunc(iter)
31 | end)
32 | end
33 |
34 | function EnumerateEntitiesWithinDistance(entities, isPlayerEntities, coords, maxDistance)
35 | local nearbyEntities = {}
36 |
37 | if coords then
38 | coords = vector3(coords.x, coords.y, coords.z)
39 | else
40 | local playerPed = PlayerPedId()
41 | coords = GetEntityCoords(playerPed)
42 | end
43 |
44 | for k,entity in pairs(entities) do
45 | local distance = #(coords - GetEntityCoords(entity))
46 |
47 | if distance <= maxDistance then
48 | table.insert(nearbyEntities, isPlayerEntities and k or entity)
49 | end
50 | end
51 |
52 | return nearbyEntities
53 | end
54 |
55 | function EnumerateObjects()
56 | return EnumerateEntities(FindFirstObject, FindNextObject, EndFindObject)
57 | end
58 |
59 | function EnumeratePeds()
60 | return EnumerateEntities(FindFirstPed, FindNextPed, EndFindPed)
61 | end
62 |
63 | function EnumerateVehicles()
64 | return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
65 | end
66 |
67 | function EnumeratePickups()
68 | return EnumerateEntities(FindFirstPickup, FindNextPickup, EndFindPickup)
69 | end
70 |
--------------------------------------------------------------------------------
/client/main.lua:
--------------------------------------------------------------------------------
1 | local isPaused, isDead, pickups = false, false, {}
2 |
3 | Citizen.CreateThread(function()
4 | while true do
5 | Citizen.Wait(0)
6 |
7 | if NetworkIsPlayerActive(PlayerId()) then
8 | TriggerServerEvent('nex:Core:onPlayerJoined')
9 | break
10 | end
11 | end
12 | end)
13 |
14 | RegisterNetEvent('nex:Core:playerLoaded')
15 | AddEventHandler('nex:Core:playerLoaded', function(playerData)
16 | NEX.PlayerLoaded = true
17 | NEX.PlayerData = playerData
18 |
19 | Citizen.Wait(500)
20 |
21 | -- check if player is coming from loading screen
22 | if GetEntityModel(PlayerPedId()) == GetHashKey('PLAYER_ZERO') then
23 | local defaultModel = GetHashKey('mp_m_freemode_01')
24 | RequestModel(defaultModel)
25 |
26 | while not HasModelLoaded(defaultModel) do
27 | Citizen.Wait(10)
28 | end
29 |
30 | SetPlayerModel(PlayerId(), defaultModel)
31 | SetPedDefaultComponentVariation(PlayerPedId())
32 | --SetPedRandomComponentVariation(PlayerPedId(), true)
33 | SetModelAsNoLongerNeeded(defaultModel)
34 | end
35 |
36 | AddTextEntry('FE_THDR_GTAO', '~w~~h~'.. Config.ServerName ..' ~m~| ~w~CharId: ~c~#'.. playerData.charId ..' ~m~| ~w~DB: ~c~#'.. playerData.dbId)
37 |
38 | -- freeze the player
39 | FreezeEntityPosition(PlayerPedId(), true)
40 |
41 | -- enable PVP
42 | SetCanAttackFriendly(PlayerPedId(), true, false)
43 | NetworkSetFriendlyFireOption(true)
44 |
45 | -- disable wanted level
46 | ClearPlayerWantedLevel(PlayerId())
47 | SetMaxWantedLevel(0)
48 |
49 | if Config.EnableHud then
50 | for k,v in ipairs(playerData.accounts) do
51 | local accountTpl = '
{{money}}
'
52 | NEX.UI.HUD.RegisterElement('account_' .. v.name, k, 0, accountTpl, {money = NEX.Math.GroupDigits(v.money)})
53 | end
54 |
55 | local jobTpl = '{{job_label}} - {{grade_label}}
'
56 |
57 | if playerData.job.grade_label == '' or playerData.job.grade_label == playerData.job.label then
58 | jobTpl = '{{job_label}}
'
59 | end
60 |
61 | NEX.UI.HUD.RegisterElement('job', #playerData.accounts, 0, jobTpl, {
62 | job_label = playerData.job.label,
63 | grade_label = playerData.job.grade_label
64 | })
65 | end
66 |
67 | NEX.Game.Teleport(PlayerPedId(), {
68 | x = playerData.coords.x,
69 | y = playerData.coords.y,
70 | z = playerData.coords.z + 0.25,
71 | heading = playerData.coords.heading
72 | }, function()
73 | TriggerServerEvent('nex:Core:onPlayerSpawn')
74 | TriggerEvent('nex:Core:onPlayerSpawn')
75 | TriggerEvent('playerSpawned') -- compatibility with old scripts, will be removed soon
76 | TriggerEvent('nex:Core:restoreLoadout')
77 |
78 | Citizen.Wait(4000)
79 | --ShutdownLoadingScreen()
80 | --ShutdownLoadingScreenNui()
81 | FreezeEntityPosition(PlayerPedId(), false)
82 | DoScreenFadeIn(10000)
83 | StartServerSyncLoops()
84 | end)
85 |
86 | TriggerEvent('nex:Core:loadingScreenOff')
87 | end)
88 |
89 | RegisterNetEvent('nex:Core:setMaxWeight')
90 | AddEventHandler('nex:Core:setMaxWeight', function(newMaxWeight) NEX.PlayerData.maxWeight = newMaxWeight end)
91 |
92 | AddEventHandler('nex:Core:onPlayerSpawn', function() isDead = false end)
93 | AddEventHandler('nex:Core:onPlayerDeath', function() isDead = true end)
94 |
95 | -- AddEventHandler('skinchanger:modelLoaded', function()
96 | -- while not NEX.PlayerLoaded do
97 | -- Citizen.Wait(100)
98 | -- end
99 |
100 | -- TriggerEvent('nex:Core:restoreLoadout')
101 | -- end)
102 |
103 | AddEventHandler('nex:Core:restoreLoadout', function()
104 | local playerPed = PlayerPedId()
105 | local ammoTypes = {}
106 | RemoveAllPedWeapons(playerPed, true)
107 |
108 | for k,v in ipairs(NEX.PlayerData.loadout) do
109 | local weaponName = v.name
110 | local weaponHash = GetHashKey(weaponName)
111 |
112 | GiveWeaponToPed(playerPed, weaponHash, 0, false, false)
113 | SetPedWeaponTintIndex(playerPed, weaponHash, v.tintIndex)
114 |
115 | local ammoType = GetPedAmmoTypeFromWeapon(playerPed, weaponHash)
116 |
117 | for k2,v2 in ipairs(v.components) do
118 | local componentHash = NEX.GetWeaponComponent(weaponName, v2).hash
119 | GiveWeaponComponentToPed(playerPed, weaponHash, componentHash)
120 | end
121 |
122 | if not ammoTypes[ammoType] then
123 | AddAmmoToPed(playerPed, weaponHash, v.ammo)
124 | ammoTypes[ammoType] = true
125 | end
126 | end
127 | end)
128 |
129 | RegisterNetEvent('nex:Core:setAccountMoney')
130 | AddEventHandler('nex:Core:setAccountMoney', function(account)
131 | for k,v in ipairs(NEX.PlayerData.accounts) do
132 | if v.name == account.name then
133 | NEX.PlayerData.accounts[k] = account
134 | break
135 | end
136 | end
137 |
138 | if Config.EnableHud then
139 | NEX.UI.HUD.UpdateElement('account_' .. account.name, {
140 | money = NEX.Math.GroupDigits(account.money)
141 | })
142 | end
143 | end)
144 |
145 | RegisterNetEvent('nex:Core:addInventoryItem')
146 | AddEventHandler('nex:Core:addInventoryItem', function(item, count, showNotification)
147 | for k,v in ipairs(NEX.PlayerData.inventory) do
148 | if v.name == item then
149 | NEX.UI.ShowInventoryItemNotification(true, v.label, count - v.count)
150 | NEX.PlayerData.inventory[k].count = count
151 | break
152 | end
153 | end
154 |
155 | if showNotification then
156 | NEX.UI.ShowInventoryItemNotification(true, item, count)
157 | end
158 |
159 | -- if NEX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
160 | -- NEX.ShowInventory()
161 | -- end
162 | end)
163 |
164 | RegisterNetEvent('nex:Core:removeInventoryItem')
165 | AddEventHandler('nex:Core:removeInventoryItem', function(item, count, showNotification)
166 | for k,v in ipairs(NEX.PlayerData.inventory) do
167 | if v.name == item then
168 | NEX.UI.ShowInventoryItemNotification(false, v.label, v.count - count)
169 | NEX.PlayerData.inventory[k].count = count
170 | break
171 | end
172 | end
173 |
174 | if showNotification then
175 | NEX.UI.ShowInventoryItemNotification(false, item, count)
176 | end
177 |
178 | -- if NEX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
179 | -- NEX.ShowInventory()
180 | -- end
181 | end)
182 |
183 | RegisterNetEvent('nex:Core:setJob')
184 | AddEventHandler('nex:Core:setJob', function(job)
185 | NEX.PlayerData.job = job
186 | end)
187 |
188 | RegisterNetEvent('nex:Core:addWeapon')
189 | AddEventHandler('nex:Core:addWeapon', function(weaponName, ammo)
190 | local playerPed = PlayerPedId()
191 | local weaponHash = GetHashKey(weaponName)
192 |
193 | GiveWeaponToPed(playerPed, weaponHash, ammo, false, false)
194 | end)
195 |
196 | RegisterNetEvent('nex:Core:addWeaponComponent')
197 | AddEventHandler('nex:Core:addWeaponComponent', function(weaponName, weaponComponent)
198 | local playerPed = PlayerPedId()
199 | local weaponHash = GetHashKey(weaponName)
200 | local componentHash = NEX.GetWeaponComponent(weaponName, weaponComponent).hash
201 |
202 | GiveWeaponComponentToPed(playerPed, weaponHash, componentHash)
203 | end)
204 |
205 | RegisterNetEvent('nex:Core:setWeaponAmmo')
206 | AddEventHandler('nex:Core:setWeaponAmmo', function(weaponName, weaponAmmo)
207 | local playerPed = PlayerPedId()
208 | local weaponHash = GetHashKey(weaponName)
209 |
210 | SetPedAmmo(playerPed, weaponHash, weaponAmmo)
211 | end)
212 |
213 | RegisterNetEvent('nex:Core:setWeaponTint')
214 | AddEventHandler('nex:Core:setWeaponTint', function(weaponName, weaponTintIndex)
215 | local playerPed = PlayerPedId()
216 | local weaponHash = GetHashKey(weaponName)
217 |
218 | SetPedWeaponTintIndex(playerPed, weaponHash, weaponTintIndex)
219 | end)
220 |
221 | RegisterNetEvent('nex:Core:removeWeapon')
222 | AddEventHandler('nex:Core:removeWeapon', function(weaponName)
223 | local playerPed = PlayerPedId()
224 | local weaponHash = GetHashKey(weaponName)
225 |
226 | RemoveWeaponFromPed(playerPed, weaponHash)
227 | SetPedAmmo(playerPed, weaponHash, 0) -- remove leftover ammo
228 | end)
229 |
230 | RegisterNetEvent('nex:Core:removeWeaponComponent')
231 | AddEventHandler('nex:Core:removeWeaponComponent', function(weaponName, weaponComponent)
232 | local playerPed = PlayerPedId()
233 | local weaponHash = GetHashKey(weaponName)
234 | local componentHash = NEX.GetWeaponComponent(weaponName, weaponComponent).hash
235 |
236 | RemoveWeaponComponentFromPed(playerPed, weaponHash, componentHash)
237 | end)
238 |
239 | RegisterNetEvent('nex:Core:playFrontEndSound')
240 | AddEventHandler('nex:Core:playFrontEndSound', function(sound, soundset)
241 | PlaySoundFrontend(-1, sound, soundset, 1)
242 | end)
243 |
244 | RegisterNetEvent('nex:Core:teleport')
245 | AddEventHandler('nex:Core:teleport', function(coords)
246 | local playerPed = PlayerPedId()
247 |
248 | -- ensure decmial number
249 | coords.x = coords.x + 0.0
250 | coords.y = coords.y + 0.0
251 | coords.z = coords.z + 0.0
252 |
253 | NEX.Game.Teleport(playerPed, coords)
254 | end)
255 |
256 | -- RegisterNetEvent('nex:Core:setJob')
257 | -- AddEventHandler('nex:Core:setJob', function(job)
258 | -- if Config.EnableHud then
259 | -- NEX.UI.HUD.UpdateElement('job', {
260 | -- job_label = job.label,
261 | -- grade_label = job.grade_label
262 | -- })
263 | -- end
264 | -- end)
265 |
266 | RegisterNetEvent('nex:Core:spawnVehicle')
267 | AddEventHandler('nex:Core:spawnVehicle', function(vehicleName)
268 | local model = (type(vehicleName) == 'number' and vehicleName or GetHashKey(vehicleName))
269 |
270 | if IsModelInCdimage(model) then
271 | local playerPed = PlayerPedId()
272 | local playerCoords, playerHeading = GetEntityCoords(playerPed), GetEntityHeading(playerPed)
273 |
274 | NEX.Game.SpawnVehicle(model, playerCoords, playerHeading, function(vehicle)
275 | TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
276 | end)
277 | else
278 | TriggerEvent('chat:addMessage', {args = {'^1SYSTEM', 'Invalid vehicle model.'}})
279 | end
280 | end)
281 |
282 | RegisterNetEvent('nex:Core:createPickup')
283 | AddEventHandler('nex:Core:createPickup', function(pickupId, label, coords, type, name, components, tintIndex)
284 | local function setObjectProperties(object)
285 | SetEntityAsMissionEntity(object, true, false)
286 | PlaceObjectOnGroundProperly(object)
287 | FreezeEntityPosition(object, true)
288 | SetEntityCollision(object, false, true)
289 |
290 | pickups[pickupId] = {
291 | obj = object,
292 | label = label,
293 | inRange = false,
294 | coords = vector3(coords.x, coords.y, coords.z)
295 | }
296 | end
297 |
298 | if type == 'item_weapon' then
299 | local weaponHash = GetHashKey(name)
300 | NEX.Streaming.RequestWeaponAsset(weaponHash)
301 | local pickupObject = CreateWeaponObject(weaponHash, 50, coords.x, coords.y, coords.z, true, 1.0, 0)
302 | SetWeaponObjectTintIndex(pickupObject, tintIndex)
303 |
304 | for k,v in ipairs(components) do
305 | local component = NEX.GetWeaponComponent(name, v)
306 | GiveWeaponComponentToWeaponObject(pickupObject, component.hash)
307 | end
308 |
309 | setObjectProperties(pickupObject)
310 | else
311 | NEX.Game.SpawnLocalObject('prop_money_bag_01', coords, setObjectProperties)
312 | end
313 | end)
314 |
315 | RegisterNetEvent('nex:Core:createMissingPickups')
316 | AddEventHandler('nex:Core:createMissingPickups', function(missingPickups)
317 | for pickupId,pickup in pairs(missingPickups) do
318 | TriggerEvent('nex:Core:createPickup', pickupId, pickup.label, pickup.coords, pickup.type, pickup.name, pickup.components, pickup.tintIndex)
319 | end
320 | end)
321 |
322 | RegisterNetEvent('nex:Core:registerSuggestions')
323 | AddEventHandler('nex:Core:registerSuggestions', function(registeredCommands)
324 | for name,command in pairs(registeredCommands) do
325 | if command.suggestion then
326 | TriggerEvent('chat:addSuggestion', ('/%s'):format(name), command.suggestion.help, command.suggestion.arguments)
327 | end
328 | end
329 | end)
330 |
331 | RegisterNetEvent('nex:Core:removePickup')
332 | AddEventHandler('nex:Core:removePickup', function(pickupId)
333 | if pickups[pickupId] and pickups[pickupId].obj then
334 | NEX.Game.DeleteObject(pickups[pickupId].obj)
335 | pickups[pickupId] = nil
336 | end
337 | end)
338 |
339 | RegisterNetEvent('nex:Core:deleteVehicle')
340 | AddEventHandler('nex:Core:deleteVehicle', function(radius)
341 | local playerPed = PlayerPedId()
342 |
343 | if radius and tonumber(radius) then
344 | radius = tonumber(radius) + 0.01
345 | local vehicles = NEX.Game.GetVehiclesInArea(GetEntityCoords(playerPed), radius)
346 |
347 | for k,entity in ipairs(vehicles) do
348 | local attempt = 0
349 |
350 | while not NetworkHasControlOfEntity(entity) and attempt < 100 and DoesEntityExist(entity) do
351 | Citizen.Wait(100)
352 | NetworkRequestControlOfEntity(entity)
353 | attempt = attempt + 1
354 | end
355 |
356 | if DoesEntityExist(entity) and NetworkHasControlOfEntity(entity) then
357 | NEX.Game.DeleteVehicle(entity)
358 | end
359 | end
360 | else
361 | local vehicle, attempt = NEX.Game.GetVehicleInDirection(), 0
362 |
363 | if IsPedInAnyVehicle(playerPed, true) then
364 | vehicle = GetVehiclePedIsIn(playerPed, false)
365 | end
366 |
367 | while not NetworkHasControlOfEntity(vehicle) and attempt < 100 and DoesEntityExist(vehicle) do
368 | Citizen.Wait(100)
369 | NetworkRequestControlOfEntity(vehicle)
370 | attempt = attempt + 1
371 | end
372 |
373 | if DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle) then
374 | NEX.Game.DeleteVehicle(vehicle)
375 | end
376 | end
377 | end)
378 |
379 | RegisterNetEvent("nex:Core:runSpawnCommand")
380 | AddEventHandler("nex:Core:runSpawnCommand", function(model, livery)
381 | Citizen.CreateThread(function()
382 |
383 | local hash = GetHashKey(model)
384 |
385 | if not IsModelAVehicle(hash) then return end
386 | if not IsModelInCdimage(hash) or not IsModelValid(hash) then return end
387 |
388 | RequestModel(hash)
389 |
390 | while not HasModelLoaded(hash) do
391 | Citizen.Wait(0)
392 | end
393 |
394 | local localped = PlayerPedId()
395 | local coords = GetOffsetFromEntityInWorldCoords(PlayerPedId(), 1.5, 5.0, 0.0)
396 |
397 | local heading = GetEntityHeading(localped)
398 | local vehicle = CreateVehicle(hash, coords, heading, true, false)
399 |
400 | SetVehicleModKit(vehicle, 0)
401 | SetVehicleMod(vehicle, 11, 3, false)
402 | SetVehicleMod(vehicle, 12, 2, false)
403 | SetVehicleMod(vehicle, 13, 2, false)
404 | SetVehicleMod(vehicle, 15, 3, false)
405 | SetVehicleMod(vehicle, 16, 4, false)
406 |
407 |
408 | if model == "pol1" then
409 | SetVehicleExtra(vehicle, 5, 0)
410 | end
411 |
412 | if model == "police" then
413 | SetVehicleWheelType(vehicle, 2)
414 | SetVehicleMod(vehicle, 23, 10, false)
415 | SetVehicleColours(vehicle, 0, false)
416 | SetVehicleExtraColours(vehicle, 0, false)
417 | end
418 |
419 | if model == "pol7" then
420 | SetVehicleColours(vehicle,0)
421 | SetVehicleExtraColours(vehicle,0)
422 | end
423 |
424 | if model == "pol5" or model == "pol6" then
425 | SetVehicleExtra(vehicle, 1, -1)
426 | end
427 |
428 | SetModelAsNoLongerNeeded(hash)
429 |
430 | SetVehicleDirtLevel(vehicle, 0)
431 | SetVehicleWindowTint(vehicle, 0)
432 |
433 | if livery ~= nil then
434 | SetVehicleLivery(vehicle, tonumber(livery))
435 | end
436 | end)
437 | end)
438 |
439 | -- Pause menu disables HUD display
440 | if Config.EnableHud then
441 | -- Citizen.CreateThread(function()
442 | -- -- while true do
443 | -- -- Citizen.Wait(300)
444 |
445 | -- -- if IsPauseMenuActive() and not isPaused then
446 | -- -- isPaused = true
447 | -- -- NEX.UI.HUD.SetDisplay(0.0)
448 | -- -- elseif not IsPauseMenuActive() and isPaused then
449 | -- -- isPaused = false
450 | -- -- NEX.UI.HUD.SetDisplay(1.0)
451 | -- -- end
452 | -- -- end
453 | -- end)
454 |
455 | AddEventHandler('nex:Core:loadingScreenOff', function()
456 | NEX.UI.HUD.SetDisplay(1.0)
457 | end)
458 | end
459 |
460 | function StartServerSyncLoops()
461 | -- keep track of ammo
462 | -- Citizen.CreateThread(function()
463 | -- while true do
464 | -- Citizen.Wait(5)
465 |
466 | -- if isDead then
467 | -- Citizen.Wait(500)
468 | -- else
469 | -- local playerPed = PlayerPedId()
470 |
471 | -- if IsPedShooting(playerPed) then
472 | -- local _,weaponHash = GetCurrentPedWeapon(playerPed, true)
473 | -- local weapon = NEX.GetWeaponFromHash(weaponHash)
474 |
475 | -- if weapon then
476 | -- local ammoCount = GetAmmoInPedWeapon(playerPed, weaponHash)
477 | -- TriggerServerEvent('nex:Core:updateWeaponAmmo', weapon.name, ammoCount)
478 | -- end
479 | -- end
480 | -- end
481 | -- end
482 | -- end)
483 |
484 | -- sync current player coords with server
485 | Citizen.CreateThread(function()
486 | local previousCoords = vector3(NEX.PlayerData.coords.x, NEX.PlayerData.coords.y, NEX.PlayerData.coords.z)
487 |
488 | while true do
489 | Citizen.Wait(5000)
490 | local playerPed = PlayerPedId()
491 |
492 | if DoesEntityExist(playerPed) then
493 | local playerCoords = GetEntityCoords(playerPed)
494 | local distance = #(playerCoords - previousCoords)
495 |
496 | if distance > 1 then
497 | previousCoords = playerCoords
498 | local playerHeading = NEX.Math.Round(GetEntityHeading(playerPed), 1)
499 | local formattedCoords = {x = NEX.Math.Round(playerCoords.x, 1), y = NEX.Math.Round(playerCoords.y, 1), z = NEX.Math.Round(playerCoords.z, 1), heading = playerHeading}
500 | TriggerServerEvent('nex:Core:updateCoords', formattedCoords)
501 | end
502 | end
503 | end
504 | end)
505 | end
506 |
507 | -- Citizen.CreateThread(function()
508 | -- while true do
509 | -- Citizen.Wait(0)
510 |
511 | -- if IsControlJustReleased(0, 289) then
512 | -- if IsInputDisabled(0) and not isDead and not NEX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
513 | -- NEX.ShowInventory()
514 | -- end
515 | -- end
516 | -- end
517 | -- end)
518 |
519 | -- Pickups
520 | -- Citizen.CreateThread(function()
521 | -- while true do
522 | -- Citizen.Wait(5)
523 | -- local playerPed = PlayerPedId()
524 | -- local playerCoords, letSleep = GetEntityCoords(playerPed), true
525 | -- local closestPlayer, closestDistance = NEX.Game.GetClosestPlayer(playerCoords)
526 |
527 | -- for pickupId,pickup in pairs(pickups) do
528 | -- local distance = #(playerCoords - pickup.coords)
529 |
530 | -- if distance < 5 then
531 | -- local label = pickup.label
532 | -- letSleep = false
533 |
534 | -- if distance < 1 then
535 | -- if IsControlJustReleased(0, 38) then
536 | -- if IsPedOnFoot(playerPed) and (closestDistance == -1 or closestDistance > 3) and not pickup.inRange then
537 | -- pickup.inRange = true
538 |
539 | -- local dict, anim = 'weapons@first_person@aim_rng@generic@projectile@sticky_bomb@', 'plant_floor'
540 | -- NEX.Streaming.RequestAnimDict(dict)
541 | -- TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false)
542 | -- Citizen.Wait(1000)
543 | -- -- Check here for pickups system work with Nex Core
544 | -- TriggerServerEvent('nex:Core:onPickup', pickupId)
545 | -- PlaySoundFrontend(-1, 'PICK_UP', 'HUD_FRONTEND_DEFAULT_SOUNDSET', false)
546 | -- end
547 | -- end
548 |
549 | -- label = ('%s~n~%s'):format(label, _U('threw_pickup_prompt'))
550 | -- end
551 |
552 | -- NEX.Game.Utils.DrawText3D({
553 | -- x = pickup.coords.x,
554 | -- y = pickup.coords.y,
555 | -- z = pickup.coords.z + 0.25
556 | -- }, label, 1.2, 2)
557 | -- elseif pickup.inRange then
558 | -- pickup.inRange = false
559 | -- end
560 | -- end
561 |
562 | -- if letSleep then
563 | -- Citizen.Wait(500)
564 | -- end
565 | -- end
566 | -- end)
567 |
568 |
569 | -- [[ NATIVE TEXTS ]]
570 | AddTextEntry("PM_PANE_LEAVE", "~b~Log off ~w~from ~r~"..Config.ServerName)
571 | AddTextEntry("PM_PANE_QUIT", "~w~Get out of ~o~FiveM")
--------------------------------------------------------------------------------
/client/modules/death.lua:
--------------------------------------------------------------------------------
1 | Citizen.CreateThread(function()
2 | local isDead = false
3 |
4 | while true do
5 | Citizen.Wait(5)
6 | local player = PlayerId()
7 |
8 | if NetworkIsPlayerActive(player) then
9 | local playerPed = PlayerPedId()
10 |
11 | if IsPedFatallyInjured(playerPed) and not isDead then
12 | isDead = true
13 |
14 | local killerEntity, deathCause = GetPedSourceOfDeath(playerPed), GetPedCauseOfDeath(playerPed)
15 | local killerClientId = NetworkGetPlayerIndexFromPed(killerEntity)
16 |
17 | if killerEntity ~= playerPed and killerClientId and NetworkIsPlayerActive(killerClientId) then
18 | PlayerKilledByPlayer(GetPlayerServerId(killerClientId), killerClientId, deathCause)
19 | else
20 | PlayerKilled(deathCause)
21 | end
22 |
23 | elseif not IsPedFatallyInjured(playerPed) then
24 | isDead = false
25 | end
26 | end
27 | end
28 | end)
29 |
30 | function PlayerKilledByPlayer(killerServerId, killerClientId, deathCause)
31 | local victimCoords = GetEntityCoords(PlayerPedId())
32 | local killerCoords = GetEntityCoords(GetPlayerPed(killerClientId))
33 | local distance = #(victimCoords - killerCoords)
34 |
35 | local data = {
36 | victimCoords = {x = NEX.Math.Round(victimCoords.x, 1), y = NEX.Math.Round(victimCoords.y, 1), z = NEX.Math.Round(victimCoords.z, 1)},
37 | killerCoords = {x = NEX.Math.Round(killerCoords.x, 1), y = NEX.Math.Round(killerCoords.y, 1), z = NEX.Math.Round(killerCoords.z, 1)},
38 |
39 | killedByPlayer = true,
40 | deathCause = deathCause,
41 | distance = NEX.Math.Round(distance, 1),
42 |
43 | killerServerId = killerServerId,
44 | killerClientId = killerClientId
45 | }
46 |
47 | TriggerEvent('nex:Core:onPlayerDeath', data)
48 | TriggerServerEvent('nex:Core:onPlayerDeath', data)
49 | end
50 |
51 | function PlayerKilled(deathCause)
52 | local playerPed = PlayerPedId()
53 | local victimCoords = GetEntityCoords(playerPed)
54 |
55 | local data = {
56 | victimCoords = {x = NEX.Math.Round(victimCoords.x, 1), y = NEX.Math.Round(victimCoords.y, 1), z = NEX.Math.Round(victimCoords.z, 1)},
57 |
58 | killedByPlayer = false,
59 | deathCause = deathCause
60 | }
61 |
62 | TriggerEvent('nex:Core:onPlayerDeath', data)
63 | TriggerServerEvent('nex:Core:onPlayerDeath', data)
64 | end
65 |
--------------------------------------------------------------------------------
/client/modules/scaleform.lua:
--------------------------------------------------------------------------------
1 | NEX.Scaleform.ShowFreemodeMessage = function(title, msg, sec)
2 | local scaleform = NEX.Scaleform.Utils.RequestScaleformMovie('MP_BIG_MESSAGE_FREEMODE')
3 |
4 | BeginScaleformMovieMethod(scaleform, 'SHOW_SHARD_WASTED_MP_MESSAGE')
5 | PushScaleformMovieMethodParameterString(title)
6 | PushScaleformMovieMethodParameterString(msg)
7 | EndScaleformMovieMethod()
8 |
9 | while sec > 0 do
10 | Citizen.Wait(1)
11 | sec = sec - 0.01
12 |
13 | DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255)
14 | end
15 |
16 | SetScaleformMovieAsNoLongerNeeded(scaleform)
17 | end
18 |
19 | NEX.Scaleform.ShowBreakingNews = function(title, msg, bottom, sec)
20 | local scaleform = NEX.Scaleform.Utils.RequestScaleformMovie('BREAKING_NEWS')
21 |
22 | BeginScaleformMovieMethod(scaleform, 'SET_TEXT')
23 | PushScaleformMovieMethodParameterString(msg)
24 | PushScaleformMovieMethodParameterString(bottom)
25 | EndScaleformMovieMethod()
26 |
27 | BeginScaleformMovieMethod(scaleform, 'SET_SCROLL_TEXT')
28 | PushScaleformMovieMethodParameterInt(0) -- top ticker
29 | PushScaleformMovieMethodParameterInt(0) -- Since this is the first string, start at 0
30 | PushScaleformMovieMethodParameterString(title)
31 |
32 | EndScaleformMovieMethod()
33 |
34 | BeginScaleformMovieMethod(scaleform, 'DISPLAY_SCROLL_TEXT')
35 | PushScaleformMovieMethodParameterInt(0) -- Top ticker
36 | PushScaleformMovieMethodParameterInt(0) -- Index of string
37 |
38 | EndScaleformMovieMethod()
39 |
40 | while sec > 0 do
41 | Citizen.Wait(1)
42 | sec = sec - 0.01
43 |
44 | DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255)
45 | end
46 |
47 | SetScaleformMovieAsNoLongerNeeded(scaleform)
48 | end
49 |
50 | NEX.Scaleform.ShowPopupWarning = function(title, msg, bottom, sec)
51 | local scaleform = NEX.Scaleform.Utils.RequestScaleformMovie('POPUP_WARNING')
52 |
53 | BeginScaleformMovieMethod(scaleform, 'SHOW_POPUP_WARNING')
54 |
55 | PushScaleformMovieMethodParameterFloat(500.0) -- black background
56 | PushScaleformMovieMethodParameterString(title)
57 | PushScaleformMovieMethodParameterString(msg)
58 | PushScaleformMovieMethodParameterString(bottom)
59 | --PushScaleformMovieMethodParameterBool(true)
60 |
61 | EndScaleformMovieMethod()
62 |
63 | while sec > 0 do
64 | Citizen.Wait(1)
65 | sec = sec - 0.01
66 |
67 | DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255)
68 | end
69 |
70 | SetScaleformMovieAsNoLongerNeeded(scaleform)
71 | end
72 |
73 | NEX.Scaleform.ShowTrafficMovie = function(sec)
74 | local scaleform = NEX.Scaleform.Utils.RequestScaleformMovie('TRAFFIC_CAM')
75 |
76 | BeginScaleformMovieMethod(scaleform, 'PLAY_CAM_MOVIE')
77 |
78 | EndScaleformMovieMethod()
79 |
80 | while sec > 0 do
81 | Citizen.Wait(1)
82 | sec = sec - 0.01
83 |
84 | DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255)
85 | end
86 |
87 | SetScaleformMovieAsNoLongerNeeded(scaleform)
88 | end
89 |
90 | NEX.Scaleform.Utils.RequestScaleformMovie = function(movie)
91 | local scaleform = RequestScaleformMovie(movie)
92 |
93 | while not HasScaleformMovieLoaded(scaleform) do
94 | Citizen.Wait(0)
95 | end
96 |
97 | return scaleform
98 | end
99 |
--------------------------------------------------------------------------------
/client/modules/streaming.lua:
--------------------------------------------------------------------------------
1 | function NEX.Streaming.RequestModel(modelHash, cb)
2 | modelHash = (type(modelHash) == 'number' and modelHash or GetHashKey(modelHash))
3 |
4 | if not HasModelLoaded(modelHash) and IsModelInCdimage(modelHash) then
5 | RequestModel(modelHash)
6 |
7 | while not HasModelLoaded(modelHash) do
8 | Citizen.Wait(1)
9 | end
10 | end
11 |
12 | if cb ~= nil then
13 | cb()
14 | end
15 | end
16 |
17 | function NEX.Streaming.RequestStreamedTextureDict(textureDict, cb)
18 | if not HasStreamedTextureDictLoaded(textureDict) then
19 | RequestStreamedTextureDict(textureDict)
20 |
21 | while not HasStreamedTextureDictLoaded(textureDict) do
22 | Citizen.Wait(1)
23 | end
24 | end
25 |
26 | if cb ~= nil then
27 | cb()
28 | end
29 | end
30 |
31 | function NEX.Streaming.RequestNamedPtfxAsset(assetName, cb)
32 | if not HasNamedPtfxAssetLoaded(assetName) then
33 | RequestNamedPtfxAsset(assetName)
34 |
35 | while not HasNamedPtfxAssetLoaded(assetName) do
36 | Citizen.Wait(1)
37 | end
38 | end
39 |
40 | if cb ~= nil then
41 | cb()
42 | end
43 | end
44 |
45 | function NEX.Streaming.RequestAnimSet(animSet, cb)
46 | if not HasAnimSetLoaded(animSet) then
47 | RequestAnimSet(animSet)
48 |
49 | while not HasAnimSetLoaded(animSet) do
50 | Citizen.Wait(1)
51 | end
52 | end
53 |
54 | if cb ~= nil then
55 | cb()
56 | end
57 | end
58 |
59 | function NEX.Streaming.RequestAnimDict(animDict, cb)
60 | if not HasAnimDictLoaded(animDict) then
61 | RequestAnimDict(animDict)
62 |
63 | while not HasAnimDictLoaded(animDict) do
64 | Citizen.Wait(1)
65 | end
66 | end
67 |
68 | if cb ~= nil then
69 | cb()
70 | end
71 | end
72 |
73 | function NEX.Streaming.RequestWeaponAsset(weaponHash, cb)
74 | if not HasWeaponAssetLoaded(weaponHash) then
75 | RequestWeaponAsset(weaponHash)
76 |
77 | while not HasWeaponAssetLoaded(weaponHash) do
78 | Citizen.Wait(1)
79 | end
80 | end
81 |
82 | if cb ~= nil then
83 | cb()
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/client/wrapper.lua:
--------------------------------------------------------------------------------
1 | local Chunks = {}
2 |
3 | RegisterNUICallback('__chunk', function(data, cb)
4 | Chunks[data.id] = Chunks[data.id] or ''
5 | Chunks[data.id] = Chunks[data.id] .. data.chunk
6 |
7 | if data['end'] then
8 | local msg = json.decode(Chunks[data.id])
9 | TriggerEvent(GetCurrentResourceName() .. ':message:' .. data.__type, msg)
10 | Chunks[data.id] = nil
11 | end
12 |
13 | cb('')
14 | end)
15 |
--------------------------------------------------------------------------------
/common/functions.lua:
--------------------------------------------------------------------------------
1 | local Charset = {}
2 | NEX.Intervals = {}
3 |
4 | for i = 48, 57 do table.insert(Charset, string.char(i)) end
5 | for i = 65, 90 do table.insert(Charset, string.char(i)) end
6 | for i = 97, 122 do table.insert(Charset, string.char(i)) end
7 |
8 | NEX.GetRandomString = function(length)
9 | math.randomseed(GetGameTimer())
10 |
11 | if length > 0 then
12 | return NEX.GetRandomString(length - 1) .. Charset[math.random(1, #Charset)]
13 | else
14 | return ''
15 | end
16 | end
17 |
18 | NEX.GetConfig = function()
19 | return Config
20 | end
21 |
22 | NEX.GetWeapon = function(weaponName)
23 | weaponName = string.upper(weaponName)
24 |
25 | for k,v in ipairs(Config.Weapons) do
26 | if v.name == weaponName then
27 | return k, v
28 | end
29 | end
30 | end
31 |
32 | NEX.GetWeaponFromHash = function(weaponHash)
33 | for k,v in ipairs(Config.Weapons) do
34 | if GetHashKey(v.name) == weaponHash then
35 | return v
36 | end
37 | end
38 | end
39 |
40 | NEX.GetWeaponList = function()
41 | return Config.Weapons
42 | end
43 |
44 | NEX.GetWeaponLabel = function(weaponName)
45 | weaponName = string.upper(weaponName)
46 |
47 | for k,v in ipairs(Config.Weapons) do
48 | if v.name == weaponName then
49 | return v.label
50 | end
51 | end
52 | end
53 |
54 | NEX.GetWeaponComponent = function(weaponName, weaponComponent)
55 | weaponName = string.upper(weaponName)
56 | local weapons = Config.Weapons
57 |
58 | for k,v in ipairs(Config.Weapons) do
59 | if v.name == weaponName then
60 | for k2,v2 in ipairs(v.components) do
61 | if v2.name == weaponComponent then
62 | return v2
63 | end
64 | end
65 | end
66 | end
67 | end
68 |
69 | NEX.DumpTable = function(table, nb)
70 | if nb == nil then
71 | nb = 0
72 | end
73 |
74 | if type(table) == 'table' then
75 | local s = ''
76 | for i = 1, nb + 1, 1 do
77 | s = s .. " "
78 | end
79 |
80 | s = '{\n'
81 | for k,v in pairs(table) do
82 | if type(k) ~= 'number' then k = '"'..k..'"' end
83 | for i = 1, nb, 1 do
84 | s = s .. " "
85 | end
86 | s = s .. '['..k..'] = ' .. NEX.DumpTable(v, nb + 1) .. ',\n'
87 | end
88 |
89 | for i = 1, nb, 1 do
90 | s = s .. " "
91 | end
92 |
93 | return s .. '}'
94 | else
95 | return tostring(table)
96 | end
97 | end
98 |
99 | NEX.Round = function(value, numDecimalPlaces)
100 | return NEX.Math.Round(value, numDecimalPlaces)
101 | end
102 |
103 | NEX.ClearInterval = function(ID)
104 | if NEX.Intervals[ID] ~= nil then
105 | NEX.Intervals[ID] = nil
106 | end
107 | end
108 |
109 | NEX.SetInterval = function(ms, cb)
110 | local i = 0
111 | while NEX.Intervals[i] ~= nil do i = i + 1 end
112 | NEX.Intervals[i] = true
113 | Citizen.CreateThread(function()
114 | while true do
115 | Citizen.Wait(ms)
116 | if NEX.Intervals[i] ~= nil then
117 | cb()
118 | else
119 | break
120 | end
121 | end
122 | end)
123 | return i
124 | end
--------------------------------------------------------------------------------
/common/modules/math.lua:
--------------------------------------------------------------------------------
1 | NEX.Math = {}
2 |
3 | NEX.Math.Round = function(value, numDecimalPlaces)
4 | if numDecimalPlaces then
5 | local power = 10^numDecimalPlaces
6 | return math.floor((value * power) + 0.5) / (power)
7 | else
8 | return math.floor(value + 0.5)
9 | end
10 | end
11 |
12 | -- credit http://richard.warburton.it
13 | NEX.Math.GroupDigits = function(value)
14 | local left,num,right = string.match(value,'^([^%d]*%d)(%d*)(.-)$')
15 |
16 | return left..(num:reverse():gsub('(%d%d%d)','%1' .. _U('locale_digit_grouping_symbol')):reverse())..right
17 | end
18 |
19 | NEX.Math.Trim = function(value)
20 | if value then
21 | return (string.gsub(value, "^%s*(.-)%s*$", "%1"))
22 | else
23 | return nil
24 | end
25 | end
--------------------------------------------------------------------------------
/common/modules/table.lua:
--------------------------------------------------------------------------------
1 | NEX.Table = {}
2 |
3 | -- nil proof alternative to #table
4 | function NEX.Table.SizeOf(t)
5 | local count = 0
6 |
7 | for _,_ in pairs(t) do
8 | count = count + 1
9 | end
10 |
11 | return count
12 | end
13 |
14 | function NEX.Table.Contains(table, element)
15 | for _, value in pairs(table) do
16 | if value == element then
17 | return true
18 | end
19 | end
20 | return false
21 | end
22 |
23 | function NEX.Table.Set(t)
24 | local set = {}
25 | for k,v in ipairs(t) do set[v] = true end
26 | return set
27 | end
28 |
29 | function NEX.Table.IndexOf(t, value)
30 | for i=1, #t, 1 do
31 | if t[i] == value then
32 | return i
33 | end
34 | end
35 |
36 | return -1
37 | end
38 |
39 | function NEX.Table.LastIndexOf(t, value)
40 | for i=#t, 1, -1 do
41 | if t[i] == value then
42 | return i
43 | end
44 | end
45 |
46 | return -1
47 | end
48 |
49 | function NEX.Table.Find(t, cb)
50 | for i=1, #t, 1 do
51 | if cb(t[i]) then
52 | return t[i]
53 | end
54 | end
55 |
56 | return nil
57 | end
58 |
59 | function NEX.Table.FindIndex(t, cb)
60 | for i=1, #t, 1 do
61 | if cb(t[i]) then
62 | return i
63 | end
64 | end
65 |
66 | return -1
67 | end
68 |
69 | function NEX.Table.Filter(t, cb)
70 | local newTable = {}
71 |
72 | for i=1, #t, 1 do
73 | if cb(t[i]) then
74 | table.insert(newTable, t[i])
75 | end
76 | end
77 |
78 | return newTable
79 | end
80 |
81 | function NEX.Table.Map(t, cb)
82 | local newTable = {}
83 |
84 | for i=1, #t, 1 do
85 | newTable[i] = cb(t[i], i)
86 | end
87 |
88 | return newTable
89 | end
90 |
91 | function NEX.Table.Reverse(t)
92 | local newTable = {}
93 |
94 | for i=#t, 1, -1 do
95 | table.insert(newTable, t[i])
96 | end
97 |
98 | return newTable
99 | end
100 |
101 | function NEX.Table.Clone(t)
102 | if type(t) ~= 'table' then return t end
103 |
104 | local meta = getmetatable(t)
105 | local target = {}
106 |
107 | for k,v in pairs(t) do
108 | if type(v) == 'table' then
109 | target[k] = NEX.Table.Clone(v)
110 | else
111 | target[k] = v
112 | end
113 | end
114 |
115 | setmetatable(target, meta)
116 |
117 | return target
118 | end
119 |
120 | function NEX.Table.Concat(t1, t2)
121 | local t3 = NEX.Table.Clone(t1)
122 |
123 | for i=1, #t2, 1 do
124 | table.insert(t3, t2[i])
125 | end
126 |
127 | return t3
128 | end
129 |
130 | function NEX.Table.Join(t, sep)
131 | local sep = sep or ','
132 | local str = ''
133 |
134 | for i=1, #t, 1 do
135 | if i > 1 then
136 | str = str .. sep
137 | end
138 |
139 | str = str .. t[i]
140 | end
141 |
142 | return str
143 | end
144 |
145 | -- Credit: https://stackoverflow.com/a/15706820
146 | -- Description: sort function for pairs
147 | function NEX.Table.Sort(t, order)
148 | -- collect the keys
149 | local keys = {}
150 |
151 | for k,_ in pairs(t) do
152 | keys[#keys + 1] = k
153 | end
154 |
155 | -- if order function given, sort by it by passing the table and keys a, b,
156 | -- otherwise just sort the keys
157 | if order then
158 | table.sort(keys, function(a,b)
159 | return order(t, a, b)
160 | end)
161 | else
162 | table.sort(keys)
163 | end
164 |
165 | -- return the iterator function
166 | local i = 0
167 |
168 | return function()
169 | i = i + 1
170 | if keys[i] then
171 | return keys[i], t[keys[i]]
172 | end
173 | end
174 | end
--------------------------------------------------------------------------------
/config.lua:
--------------------------------------------------------------------------------
1 | Config = {}
2 | Config.Locale = 'en'
3 |
4 | Config.ServerName = "Capital City"
5 |
6 | Config.Accounts = {
7 | bank = _U('account_bank'),
8 | black_money = _U('account_black_money'),
9 | money = _U('account_money'),
10 | points = 'NEX-Points'
11 | }
12 |
13 | Config.StartingAccountMoney = {bank = 3000, money=2000, points = 0}
14 |
15 | Config.EnableSocietyPayouts = false -- pay from the society account that the player is employed at? Requirement: nex_factions
16 | Config.EnableHud = false -- enable the default hud? Display current job and accounts (black, bank & cash)
17 | Config.MaxWeight = 2000 -- the max inventory weight without backpack
18 | Config.PaycheckInterval = 20 * 60000 -- how often to recieve pay checks in milliseconds
19 | Config.EnableDebug = true
20 |
21 | -- CUSTOM CORE CONFIG
22 | Config.EnablePayCommand = true
23 |
24 | Config.Tax = 0.16 -- salary * tax
25 | Config.EnableTax = false
26 | Config.VipTiers = { -- VIP Tier => percent
27 | [1] = 0.1,
28 | [2] = 0.2,
29 | [3] = 0.3,
30 | [4] = 0.4,
31 | [5] = 0.5,
32 | [6] = 0.6
33 | }
34 |
35 | Config.VipTierDefault = 0.1
36 | Config.SendTaxToMazeBankSociety = false -- Use for store money taxes on a 'virtual bank' || You must have a nex_factions extension
37 |
38 | ---- MUST BE CONFIGURED
39 | --[[
40 | Paycheck Tax : boolean
41 | Max Characters per user : int
42 | modular VIP system for tax : table?
43 | ]]
--------------------------------------------------------------------------------
/config.weapons.lua:
--------------------------------------------------------------------------------
1 | Config.DefaultWeaponTints = {
2 | [0] = _U('tint_default'),
3 | [1] = _U('tint_green'),
4 | [2] = _U('tint_gold'),
5 | [3] = _U('tint_pink'),
6 | [4] = _U('tint_army'),
7 | [5] = _U('tint_lspd'),
8 | [6] = _U('tint_orange'),
9 | [7] = _U('tint_platinum')
10 | }
11 |
12 | Config.Weapons = {
13 | {
14 | name = 'WEAPON_PISTOL',
15 | label = _U('weapon_pistol'),
16 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
17 | tints = Config.DefaultWeaponTints,
18 | components = {
19 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_PISTOL_CLIP_01')},
20 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_PISTOL_CLIP_02')},
21 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
22 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP_02')},
23 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_PISTOL_VARMOD_LUXE')}
24 | }
25 | },
26 |
27 | {
28 | name = 'WEAPON_COMBATPISTOL',
29 | label = _U('weapon_combatpistol'),
30 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
31 | tints = Config.DefaultWeaponTints,
32 | components = {
33 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_COMBATPISTOL_CLIP_01')},
34 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_COMBATPISTOL_CLIP_02')},
35 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
36 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')},
37 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_COMBATPISTOL_VARMOD_LOWRIDER')}
38 | }
39 | },
40 |
41 | {
42 | name = 'WEAPON_APPISTOL',
43 | label = _U('weapon_appistol'),
44 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
45 | tints = Config.DefaultWeaponTints,
46 | components = {
47 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_APPISTOL_CLIP_01')},
48 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_APPISTOL_CLIP_02')},
49 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
50 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')},
51 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_APPISTOL_VARMOD_LUXE')}
52 | }
53 | },
54 |
55 | {
56 | name = 'WEAPON_PISTOL50',
57 | label = _U('weapon_pistol50'),
58 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
59 | tints = Config.DefaultWeaponTints,
60 | components = {
61 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_PISTOL50_CLIP_01')},
62 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_PISTOL50_CLIP_02')},
63 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
64 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
65 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_PISTOL50_VARMOD_LUXE')}
66 | }
67 | },
68 |
69 | {
70 | name = 'WEAPON_SNSPISTOL',
71 | label = _U('weapon_snspistol'),
72 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
73 | tints = Config.DefaultWeaponTints,
74 | components = {
75 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_SNSPISTOL_CLIP_01')},
76 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_SNSPISTOL_CLIP_02')},
77 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_SNSPISTOL_VARMOD_LOWRIDER')}
78 | }
79 | },
80 |
81 | {
82 | name = 'WEAPON_HEAVYPISTOL',
83 | label = _U('weapon_heavypistol'),
84 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
85 | tints = Config.DefaultWeaponTints,
86 | components = {
87 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_HEAVYPISTOL_CLIP_01')},
88 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_HEAVYPISTOL_CLIP_02')},
89 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
90 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')},
91 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_HEAVYPISTOL_VARMOD_LUXE')}
92 | }
93 | },
94 |
95 | {
96 | name = 'WEAPON_VINTAGEPISTOL',
97 | label = _U('weapon_vintagepistol'),
98 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
99 | tints = Config.DefaultWeaponTints,
100 | components = {
101 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_VINTAGEPISTOL_CLIP_01')},
102 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_VINTAGEPISTOL_CLIP_02')},
103 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')}
104 | }
105 | },
106 |
107 | {
108 | name = 'WEAPON_MACHINEPISTOL',
109 | label = _U('weapon_machinepistol'),
110 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')},
111 | tints = Config.DefaultWeaponTints,
112 | components = {
113 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_MACHINEPISTOL_CLIP_01')},
114 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_MACHINEPISTOL_CLIP_02')},
115 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_MACHINEPISTOL_CLIP_03')},
116 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')}
117 | }
118 | },
119 |
120 | {name = 'WEAPON_REVOLVER', label = _U('weapon_revolver'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')}},
121 | {name = 'WEAPON_MARKSMANPISTOL', label = _U('weapon_marksmanpistol'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')}},
122 | {name = 'WEAPON_DOUBLEACTION', label = _U('weapon_doubleaction'), components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_PISTOL')}},
123 |
124 | {
125 | name = 'WEAPON_SMG',
126 | label = _U('weapon_smg'),
127 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SMG')},
128 | tints = Config.DefaultWeaponTints,
129 | components = {
130 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_SMG_CLIP_01')},
131 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_SMG_CLIP_02')},
132 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_SMG_CLIP_03')},
133 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
134 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MACRO_02')},
135 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_PI_SUPP')},
136 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_SMG_VARMOD_LUXE')}
137 | }
138 | },
139 |
140 | {
141 | name = 'WEAPON_ASSAULTSMG',
142 | label = _U('weapon_assaultsmg'),
143 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SMG')},
144 | tints = Config.DefaultWeaponTints,
145 | components = {
146 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_ASSAULTSMG_CLIP_01')},
147 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_ASSAULTSMG_CLIP_02')},
148 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
149 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MACRO')},
150 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
151 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_ASSAULTSMG_VARMOD_LOWRIDER')}
152 | }
153 | },
154 |
155 | {
156 | name = 'WEAPON_MICROSMG',
157 | label = _U('weapon_microsmg'),
158 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SMG')},
159 | tints = Config.DefaultWeaponTints,
160 | components = {
161 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_MICROSMG_CLIP_01')},
162 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_MICROSMG_CLIP_02')},
163 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_PI_FLSH')},
164 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MACRO')},
165 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
166 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_MICROSMG_VARMOD_LUXE')}
167 | }
168 | },
169 |
170 | {
171 | name = 'WEAPON_MINISMG',
172 | label = _U('weapon_minismg'),
173 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SMG')},
174 | tints = Config.DefaultWeaponTints,
175 | components = {
176 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_MINISMG_CLIP_01')},
177 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_MINISMG_CLIP_02')}
178 | }
179 | },
180 |
181 | {
182 | name = 'WEAPON_COMBATPDW',
183 | label = _U('weapon_combatpdw'),
184 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SMG')},
185 | tints = Config.DefaultWeaponTints,
186 | components = {
187 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_COMBATPDW_CLIP_01')},
188 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_COMBATPDW_CLIP_02')},
189 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_COMBATPDW_CLIP_03')},
190 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
191 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
192 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_SMALL')}
193 | }
194 | },
195 |
196 | {
197 | name = 'WEAPON_PUMPSHOTGUN',
198 | label = _U('weapon_pumpshotgun'),
199 | ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')},
200 | tints = Config.DefaultWeaponTints,
201 | components = {
202 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
203 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_SR_SUPP')},
204 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_PUMPSHOTGUN_VARMOD_LOWRIDER')}
205 | }
206 | },
207 |
208 | {
209 | name = 'WEAPON_SAWNOFFSHOTGUN',
210 | label = _U('weapon_sawnoffshotgun'),
211 | ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')},
212 | tints = Config.DefaultWeaponTints,
213 | components = {
214 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_SAWNOFFSHOTGUN_VARMOD_LUXE')}
215 | }
216 | },
217 |
218 | {
219 | name = 'WEAPON_ASSAULTSHOTGUN',
220 | label = _U('weapon_assaultshotgun'),
221 | ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')},
222 | tints = Config.DefaultWeaponTints,
223 | components = {
224 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_ASSAULTSHOTGUN_CLIP_01')},
225 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_ASSAULTSHOTGUN_CLIP_02')},
226 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
227 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP')},
228 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')}
229 | }
230 | },
231 |
232 | {
233 | name = 'WEAPON_BULLPUPSHOTGUN',
234 | label = _U('weapon_bullpupshotgun'),
235 | ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')},
236 | tints = Config.DefaultWeaponTints,
237 | components = {
238 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
239 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
240 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')}
241 | }
242 | },
243 |
244 | {
245 | name = 'WEAPON_HEAVYSHOTGUN',
246 | label = _U('weapon_heavyshotgun'),
247 | ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')},
248 | tints = Config.DefaultWeaponTints,
249 | components = {
250 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_HEAVYSHOTGUN_CLIP_01')},
251 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_HEAVYSHOTGUN_CLIP_02')},
252 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_HEAVYSHOTGUN_CLIP_03')},
253 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
254 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
255 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')}
256 | }
257 | },
258 |
259 | {name = 'WEAPON_DBSHOTGUN', label = _U('weapon_dbshotgun'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')}},
260 | {name = 'WEAPON_AUTOSHOTGUN', label = _U('weapon_autoshotgun'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_shells'), hash = GetHashKey('AMMO_SHOTGUN')}},
261 | {name = 'WEAPON_MUSKET', label = _U('weapon_musket'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SHOTGUN')}},
262 |
263 | {
264 | name = 'WEAPON_ASSAULTRIFLE',
265 | label = _U('weapon_assaultrifle'),
266 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
267 | tints = Config.DefaultWeaponTints,
268 | components = {
269 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_ASSAULTRIFLE_CLIP_01')},
270 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_ASSAULTRIFLE_CLIP_02')},
271 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_ASSAULTRIFLE_CLIP_03')},
272 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
273 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MACRO')},
274 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
275 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
276 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_ASSAULTRIFLE_VARMOD_LUXE')}
277 | }
278 | },
279 |
280 | {
281 | name = 'WEAPON_CARBINERIFLE',
282 | label = _U('weapon_carbinerifle'),
283 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
284 | tints = Config.DefaultWeaponTints,
285 | components = {
286 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_CARBINERIFLE_CLIP_01')},
287 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_CARBINERIFLE_CLIP_02')},
288 | {name = 'clip_box', label = _U('component_clip_box'), hash = GetHashKey('COMPONENT_CARBINERIFLE_CLIP_03')},
289 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
290 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MEDIUM')},
291 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP')},
292 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
293 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_CARBINERIFLE_VARMOD_LUXE')}
294 | }
295 | },
296 |
297 | {
298 | name = 'WEAPON_ADVANCEDRIFLE',
299 | label = _U('weapon_advancedrifle'),
300 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
301 | tints = Config.DefaultWeaponTints,
302 | components = {
303 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_ADVANCEDRIFLE_CLIP_01')},
304 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_ADVANCEDRIFLE_CLIP_02')},
305 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
306 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_SMALL')},
307 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP')},
308 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_ADVANCEDRIFLE_VARMOD_LUXE')}
309 | }
310 | },
311 |
312 | {
313 | name = 'WEAPON_SPECIALCARBINE',
314 | label = _U('weapon_specialcarbine'),
315 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
316 | tints = Config.DefaultWeaponTints,
317 | components = {
318 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_SPECIALCARBINE_CLIP_01')},
319 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_SPECIALCARBINE_CLIP_02')},
320 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_SPECIALCARBINE_CLIP_03')},
321 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
322 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MEDIUM')},
323 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
324 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
325 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_SPECIALCARBINE_VARMOD_LOWRIDER')}
326 | }
327 | },
328 |
329 | {
330 | name = 'WEAPON_BULLPUPRIFLE',
331 | label = _U('weapon_bullpuprifle'),
332 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
333 | tints = Config.DefaultWeaponTints,
334 | components = {
335 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_BULLPUPRIFLE_CLIP_01')},
336 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_BULLPUPRIFLE_CLIP_02')},
337 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
338 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_SMALL')},
339 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP')},
340 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
341 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_BULLPUPRIFLE_VARMOD_LOW')}
342 | }
343 | },
344 |
345 | {
346 | name = 'WEAPON_COMPACTRIFLE',
347 | label = _U('weapon_compactrifle'),
348 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RIFLE')},
349 | tints = Config.DefaultWeaponTints,
350 | components = {
351 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_COMPACTRIFLE_CLIP_01')},
352 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_COMPACTRIFLE_CLIP_02')},
353 | {name = 'clip_drum', label = _U('component_clip_drum'), hash = GetHashKey('COMPONENT_COMPACTRIFLE_CLIP_03')}
354 | }
355 | },
356 |
357 | {
358 | name = 'WEAPON_MG',
359 | label = _U('weapon_mg'),
360 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_MG')},
361 | tints = Config.DefaultWeaponTints,
362 | components = {
363 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_MG_CLIP_01')},
364 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_MG_CLIP_02')},
365 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_SMALL_02')},
366 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_MG_VARMOD_LOWRIDER')}
367 | }
368 | },
369 |
370 | {
371 | name = 'WEAPON_COMBATMG',
372 | label = _U('weapon_combatmg'),
373 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_MG')},
374 | tints = Config.DefaultWeaponTints,
375 | components = {
376 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_COMBATMG_CLIP_01')},
377 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_COMBATMG_CLIP_02')},
378 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_MEDIUM')},
379 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
380 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_COMBATMG_VARMOD_LOWRIDER')}
381 | }
382 | },
383 |
384 | {
385 | name = 'WEAPON_GUSENBERG',
386 | label = _U('weapon_gusenberg'),
387 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_MG')},
388 | tints = Config.DefaultWeaponTints,
389 | components = {
390 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_GUSENBERG_CLIP_01')},
391 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_GUSENBERG_CLIP_02')},
392 | }
393 | },
394 |
395 | {
396 | name = 'WEAPON_SNIPERRIFLE',
397 | label = _U('weapon_sniperrifle'),
398 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SNIPER')},
399 | tints = Config.DefaultWeaponTints,
400 | components = {
401 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_LARGE')},
402 | {name = 'scope_advanced', label = _U('component_scope_advanced'), hash = GetHashKey('COMPONENT_AT_SCOPE_MAX')},
403 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP_02')},
404 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_SNIPERRIFLE_VARMOD_LUXE')}
405 | }
406 | },
407 |
408 | {
409 | name = 'WEAPON_HEAVYSNIPER',
410 | label = _U('weapon_heavysniper'),
411 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SNIPER')},
412 | tints = Config.DefaultWeaponTints,
413 | components = {
414 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_LARGE')},
415 | {name = 'scope_advanced', label = _U('component_scope_advanced'), hash = GetHashKey('COMPONENT_AT_SCOPE_MAX')}
416 | }
417 | },
418 |
419 | {
420 | name = 'WEAPON_MARKSMANRIFLE',
421 | label = _U('weapon_marksmanrifle'),
422 | ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_SNIPER')},
423 | tints = Config.DefaultWeaponTints,
424 | components = {
425 | {name = 'clip_default', label = _U('component_clip_default'), hash = GetHashKey('COMPONENT_MARKSMANRIFLE_CLIP_01')},
426 | {name = 'clip_extended', label = _U('component_clip_extended'), hash = GetHashKey('COMPONENT_MARKSMANRIFLE_CLIP_02')},
427 | {name = 'flashlight', label = _U('component_flashlight'), hash = GetHashKey('COMPONENT_AT_AR_FLSH')},
428 | {name = 'scope', label = _U('component_scope'), hash = GetHashKey('COMPONENT_AT_SCOPE_LARGE_FIXED_ZOOM')},
429 | {name = 'suppressor', label = _U('component_suppressor'), hash = GetHashKey('COMPONENT_AT_AR_SUPP')},
430 | {name = 'grip', label = _U('component_grip'), hash = GetHashKey('COMPONENT_AT_AR_AFGRIP')},
431 | {name = 'luxary_finish', label = _U('component_luxary_finish'), hash = GetHashKey('COMPONENT_MARKSMANRIFLE_VARMOD_LUXE')}
432 | }
433 | },
434 |
435 | {name = 'WEAPON_MINIGUN', label = _U('weapon_minigun'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_MINIGUN')}},
436 | {name = 'WEAPON_RAILGUN', label = _U('weapon_railgun'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rounds'), hash = GetHashKey('AMMO_RAILGUN')}},
437 | {name = 'WEAPON_STUNGUN', label = _U('weapon_stungun'), tints = Config.DefaultWeaponTints, components = {}},
438 | {name = 'WEAPON_RPG', label = _U('weapon_rpg'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rockets'), hash = GetHashKey('AMMO_RPG')}},
439 | {name = 'WEAPON_HOMINGLAUNCHER', label = _U('weapon_hominglauncher'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_rockets'), hash = GetHashKey('AMMO_HOMINGLAUNCHER')}},
440 | {name = 'WEAPON_GRENADELAUNCHER', label = _U('weapon_grenadelauncher'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_grenadelauncher'), hash = GetHashKey('AMMO_GRENADELAUNCHER')}},
441 | {name = 'WEAPON_COMPACTLAUNCHER', label = _U('weapon_compactlauncher'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_grenadelauncher'), hash = GetHashKey('AMMO_GRENADELAUNCHER')}},
442 | {name = 'WEAPON_FLAREGUN', label = _U('weapon_flaregun'), tints = Config.DefaultWeaponTints, components = {}, ammo = {label = _U('ammo_flaregun'), hash = GetHashKey('AMMO_FLAREGUN')}},
443 | {name = 'WEAPON_FIREEXTINGUISHER', label = _U('weapon_fireextinguisher'), components = {}, ammo = {label = _U('ammo_charge'), hash = GetHashKey('AMMO_FIREEXTINGUISHER')}},
444 | {name = 'WEAPON_PETROLCAN', label = _U('weapon_petrolcan'), components = {}, ammo = {label = _U('ammo_petrol'), hash = GetHashKey('AMMO_PETROLCAN')}},
445 | {name = 'WEAPON_FIREWORK', label = _U('weapon_firework'), components = {}, ammo = {label = _U('ammo_firework'), hash = GetHashKey('AMMO_FIREWORK')}},
446 | {name = 'WEAPON_FLASHLIGHT', label = _U('weapon_flashlight'), components = {}},
447 | {name = 'GADGET_PARACHUTE', label = _U('gadget_parachute'), components = {}},
448 | {name = 'WEAPON_KNUCKLE', label = _U('weapon_knuckle'), components = {}},
449 | {name = 'WEAPON_HATCHET', label = _U('weapon_hatchet'), components = {}},
450 | {name = 'WEAPON_MACHETE', label = _U('weapon_machete'), components = {}},
451 | {name = 'WEAPON_SWITCHBLADE', label = _U('weapon_switchblade'), components = {}},
452 | {name = 'WEAPON_BOTTLE', label = _U('weapon_bottle'), components = {}},
453 | {name = 'WEAPON_DAGGER', label = _U('weapon_dagger'), components = {}},
454 | {name = 'WEAPON_POOLCUE', label = _U('weapon_poolcue'), components = {}},
455 | {name = 'WEAPON_WRENCH', label = _U('weapon_wrench'), components = {}},
456 | {name = 'WEAPON_BATTLEAXE', label = _U('weapon_battleaxe'), components = {}},
457 | {name = 'WEAPON_KNIFE', label = _U('weapon_knife'), components = {}},
458 | {name = 'WEAPON_NIGHTSTICK', label = _U('weapon_nightstick'), components = {}},
459 | {name = 'WEAPON_HAMMER', label = _U('weapon_hammer'), components = {}},
460 | {name = 'WEAPON_BAT', label = _U('weapon_bat'), components = {}},
461 | {name = 'WEAPON_GOLFCLUB', label = _U('weapon_golfclub'), components = {}},
462 | {name = 'WEAPON_CROWBAR', label = _U('weapon_crowbar'), components = {}},
463 |
464 | {name = 'WEAPON_GRENADE', label = _U('weapon_grenade'), components = {}, ammo = {label = _U('ammo_grenade'), hash = GetHashKey('AMMO_GRENADE')}},
465 | {name = 'WEAPON_SMOKEGRENADE', label = _U('weapon_smokegrenade'), components = {}, ammo = {label = _U('ammo_smokebomb'), hash = GetHashKey('AMMO_SMOKEGRENADE')}},
466 | {name = 'WEAPON_STICKYBOMB', label = _U('weapon_stickybomb'), components = {}, ammo = {label = _U('ammo_stickybomb'), hash = GetHashKey('AMMO_STICKYBOMB')}},
467 | {name = 'WEAPON_PIPEBOMB', label = _U('weapon_pipebomb'), components = {}, ammo = {label = _U('ammo_pipebomb'), hash = GetHashKey('AMMO_PIPEBOMB')}},
468 | {name = 'WEAPON_BZGAS', label = _U('weapon_bzgas'), components = {}, ammo = {label = _U('ammo_bzgas'), hash = GetHashKey('AMMO_BZGAS')}},
469 | {name = 'WEAPON_MOLOTOV', label = _U('weapon_molotov'), components = {}, ammo = {label = _U('ammo_molotov'), hash = GetHashKey('AMMO_MOLOTOV')}},
470 | {name = 'WEAPON_PROXMINE', label = _U('weapon_proxmine'), components = {}, ammo = {label = _U('ammo_proxmine'), hash = GetHashKey('AMMO_PROXMINE')}},
471 | {name = 'WEAPON_SNOWBALL', label = _U('weapon_snowball'), components = {}, ammo = {label = _U('ammo_snowball'), hash = GetHashKey('AMMO_SNOWBALL')}},
472 | {name = 'WEAPON_BALL', label = _U('weapon_ball'), components = {}, ammo = {label = _U('ammo_ball'), hash = GetHashKey('AMMO_BALL')}},
473 | {name = 'WEAPON_FLARE', label = _U('weapon_flare'), components = {}, ammo = {label = _U('ammo_flare'), hash = GetHashKey('AMMO_FLARE')}}
474 | }
475 |
--------------------------------------------------------------------------------
/config_s.lua:
--------------------------------------------------------------------------------
1 | ConfigServer = {}
2 | ConfigServer.SecureResources = {
3 | "nex_menu_default",
4 | "nex_menu_dialog",
5 | "nex_characters",
6 | "nex_identificator"
7 | }
8 |
9 | ConfigServer.DiscordWebhookImage = "https://images-ext-2.discordapp.net/external/05w3zIVuaUzJS6zPgq1FuOmG4kif6_NCPQQVHS864mw/https/images-ext-2.discordapp.net/external/PN4jUr9A0-7sD4iKtfJVB3MeTVaGQMhUaihqjp3qFRc/https/cdn.probot.io/HkWlJsRlXU.gif"
10 | ConfigServer.DiscordWebhooks = {
11 | ['STAFF'] = nil, --STAFF LOGS WEBHOOK
12 | ['ECONOMY'] = nil, --ECONOMY LOGS WEBHOOK
13 | ['ACTION'] = nil, --PLAYER ACTIONS LOGS WEBHOOK
14 | ['INVENTORY'] = nil, --INVENTORY ACTIONS LOGS WEBHOOK
15 | ['PUNISH'] = nil, --PUNISHMENTS LOGS WEBHOOK
16 | ['CHAT'] = nil, --CHAT (me/do/help channels and others) LOGS WEBHOOK
17 | ['PLAYER'] = nil --PLAYER INTEGRITY LOGS WEBHOOK
18 | }
--------------------------------------------------------------------------------
/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 |
3 | game 'gta5'
4 |
5 | description 'NEX Core'
6 |
7 | version '1.0.0'
8 |
9 | server_scripts {
10 | '@async/async.lua',
11 | '@mysql-async/lib/MySQL.lua',
12 |
13 | 'locale.lua',
14 | 'locales/en.lua',
15 |
16 | 'config.lua',
17 | 'config_s.lua',
18 | 'config.weapons.lua',
19 |
20 | 'server/common.lua',
21 | 'server/classes/player.lua',
22 | 'server/functions.lua',
23 | 'server/paycheck.lua',
24 | 'server/main.lua',
25 | 'server/commands.lua',
26 |
27 | 'common/modules/math.lua',
28 | 'common/modules/table.lua',
29 | 'common/functions.lua'
30 | }
31 |
32 | client_scripts {
33 | 'locale.lua',
34 | 'locales/en.lua',
35 |
36 | 'config.lua',
37 | 'config.weapons.lua',
38 |
39 | 'client/common.lua',
40 | 'client/entityiter.lua',
41 | 'client/functions.lua',
42 | 'client/wrapper.lua',
43 | 'client/main.lua',
44 |
45 | 'client/modules/death.lua',
46 | 'client/modules/scaleform.lua',
47 | 'client/modules/streaming.lua',
48 |
49 | 'common/modules/math.lua',
50 | 'common/modules/table.lua',
51 | 'common/functions.lua'
52 | }
53 |
54 | ui_page {
55 | 'html/ui.html'
56 | }
57 |
58 | files {
59 | 'locale.js',
60 | 'html/ui.html',
61 |
62 | 'html/css/app.css',
63 |
64 | 'html/js/mustache.min.js',
65 | 'html/js/wrapper.js',
66 | 'html/js/app.js',
67 |
68 | 'html/fonts/pdown.ttf',
69 | 'html/fonts/bankgothic.ttf',
70 |
71 | 'html/img/accounts/bank.png',
72 | 'html/img/accounts/black_money.png',
73 | 'html/img/accounts/money.png'
74 | }
75 |
76 | exports {
77 | 'getNexusObject'
78 | }
79 |
80 | server_exports {
81 | 'getNexusObject'
82 | }
83 |
84 | exports {
85 | 'DoShortHudText',
86 | 'DoHudText',
87 | 'SendAlert',
88 | 'DoLongHudText',
89 | 'DoCustomHudText',
90 | 'PersistentHudText',
91 | }
92 |
93 | dependencies {
94 | 'mysql-async',
95 | 'async'
96 | }
97 |
--------------------------------------------------------------------------------
/html/css/app.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
2 |
3 | body {
4 | background-color: transparent !important;
5 | overflow: hidden; /* Hide scrollbars */
6 | }
7 |
8 | @font-face {
9 | font-family: 'Pricedown';
10 | src: url('../fonts/pdown.ttf');
11 | }
12 |
13 | @font-face {
14 | font-family: 'bankgothic';
15 | src: url('../fonts/bankgothic.ttf');
16 | }
17 |
18 | html {
19 | overflow: hidden;
20 | }
21 |
22 | #hud {
23 | opacity: 0;
24 | position: absolute;
25 | font-family: 'Pricedown';
26 | font-size: 35px;
27 | color: white;
28 | padding: 4px;
29 | text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000,
30 | 1px 1px 0 #000;
31 | text-align: right;
32 | top: 80;
33 | right: 40;
34 | }
35 |
36 | #inventory_notifications {
37 | font-family: bankgothic;
38 | position: absolute;
39 | right: 10%;
40 | bottom: 40;
41 | font-size: 0.9em;
42 | font-weight: bold;
43 | color: rgb(242, 241, 241);
44 | border-radius: 1px;
45 | }
46 |
47 | .notify {
48 | margin-top: 5px;
49 | background-color: #2c2c2c21;
50 | padding: 8px 15px 8px 15px;
51 | text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000,
52 | 1px 1px 0 #000;
53 | border-radius: 7px;
54 | }
55 |
56 | /*
57 | position: fixed;
58 | right: 10%;
59 | bottom: -50px;
60 | background-color: #323232;
61 | padding: 12px 24px 17px 24px;
62 | vertical-align: middle;
63 | color: #fff;
64 | box-shadow: 0 7px 18px rgba(0,0,0,0.2);
65 | border-radius: 1px;
66 | */
67 |
68 | .menu {
69 | font-family: 'Open Sans', sans-serif;
70 | min-width: 400px;
71 | min-height: 250px;
72 | color: #fff;
73 | position: absolute;
74 | left: 40;
75 | top: 0;
76 | }
77 |
78 | .menu .head {
79 | font-family: 'Open Sans', sans-serif;
80 | font-size: 28px;
81 | padding: 10px;
82 | background: #1a1a1a;
83 | border-bottom: 3px solid #bc1635;
84 | border-radius: 10px 10px 0 0;
85 | -webkit-border-radius: 10px 10px 0 0;
86 | -moz-border-radius: 10px 10px 0 0;
87 | -o-border-radius: 10px 10px 0 0;
88 | box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28);
89 | -webkit-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28);
90 | -moz-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28);
91 | -o-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28);
92 | box-shadow: 1px 1px 10px 4px rgba(0, 0, 0, 0.4);
93 | }
94 |
95 | .menu .head span {
96 | font-family: 'Pricedown';
97 | font-size: 28px;
98 | padding-left: 15px;
99 | padding-top: 6px;
100 | }
101 |
102 | .menu .menu-items .menu-item {
103 | font-family: 'Open Sans', sans-serif;
104 | font-size: 14px;
105 | height: 40px;
106 | display: block;
107 | background-color: #f1f1f1;
108 | box-shadow: inset 1px 0px 0px 1px #b8b8b8;
109 | height: 32px;
110 | line-height: 32px;
111 | color: #3a3a3a;
112 | text-align: center;
113 | }
114 |
115 | .menu .menu-items .menu-item.selected {
116 | background-color: #ccc;
117 | }
118 |
119 | @keyframes slideInRight {
120 | from {
121 | -webkit-transform: translate3d(100%, 0, 0);
122 | transform: translate3d(100%, 0, 0);
123 | visibility: visible;
124 | }
125 |
126 | to {
127 | -webkit-transform: translate3d(0, 0, 0);
128 | transform: translate3d(0, 0, 0);
129 | }
130 | }
131 |
132 | .template,
133 | .notification {
134 | display: none;
135 | font-family: 'Poppins', sans-serif;
136 | }
137 |
138 | .notif-container {
139 | margin-top: 53px;
140 | width: 25%; /* was 20% */
141 | position: absolute;
142 |
143 | right: 2%; /* was 15% */
144 | display: flex;
145 | flex-flow: row;
146 | flex-wrap: wrap;
147 | }
148 |
149 | .notifheader {
150 | margin-top: -1%;
151 | font: caption;
152 | font-size: 17px;
153 | font-weight: bold;
154 | }
155 |
156 | .notification {
157 | animation-name: slideInRight;
158 | animation-duration: 1s;
159 | animation-iteration-count: 1;
160 | width: 375px;
161 | height: auto;
162 | padding: 10px;
163 | padding-bottom: 0px;
164 | margin-top: -1px;
165 | font-family: 'Poppins', sans-serif;
166 | margin: 5px;
167 | font: caption;
168 | font-size: 14px;
169 | }
170 |
171 | .success {
172 | background-color: rgba(0, 255, 0, 0.5);
173 | box-shadow: -4px 0px 0px 0px rgb(0, 255, 0) inset;
174 | color: #ffffff;
175 | }
176 |
177 | .inform {
178 | background-color: rgba(49, 108, 163, 0.5);
179 | box-shadow: -4px 0px 0px 0px rgb(0, 183, 255) inset;
180 | color: #ffffff;
181 | }
182 |
183 | .error {
184 | background-color: rgba(255, 0, 0, 0.5);
185 | box-shadow: -4px 0px 0px 0px rgb(255, 0, 0) inset;
186 | color: #ffffff;
187 | }
188 |
--------------------------------------------------------------------------------
/html/fonts/bankgothic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NexCorp/Core/04c316dbf4ac804020c6b1b49bc76e69f2a96992/html/fonts/bankgothic.ttf
--------------------------------------------------------------------------------
/html/fonts/pdown.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NexCorp/Core/04c316dbf4ac804020c6b1b49bc76e69f2a96992/html/fonts/pdown.ttf
--------------------------------------------------------------------------------
/html/img/accounts/bank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NexCorp/Core/04c316dbf4ac804020c6b1b49bc76e69f2a96992/html/img/accounts/bank.png
--------------------------------------------------------------------------------
/html/img/accounts/black_money.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NexCorp/Core/04c316dbf4ac804020c6b1b49bc76e69f2a96992/html/img/accounts/black_money.png
--------------------------------------------------------------------------------
/html/img/accounts/money.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NexCorp/Core/04c316dbf4ac804020c6b1b49bc76e69f2a96992/html/img/accounts/money.png
--------------------------------------------------------------------------------
/html/js/app.js:
--------------------------------------------------------------------------------
1 | (() => {
2 |
3 | NEX = {};
4 |
5 | NEX.CreateNotification = function(data) {
6 | var $notification = $(document.createElement('div'));
7 | $notification.addClass('notification').addClass(data.type);
8 |
9 | var text = "General Alert"
10 |
11 | if (data.title !== null && data.title !== undefined){
12 | text = data.title
13 | }else{
14 | if (data.type === "success") {
15 | text = "Success!"
16 | } else if (data.type === "inform" || data.type === "info") {
17 | text = "Information:"
18 | } else {
19 | text = "Whoops!"
20 | }
21 | }
22 |
23 | $notification.html('\
24 | \
25 | \
26 | ' + data.text + '
');
27 | $notification.fadeIn();
28 | if (data.style !== undefined) {
29 | Object.keys(data.style).forEach(function(css) {
30 | $notification.css(css, data.style[css])
31 | });
32 | }
33 |
34 |
35 | return $notification;
36 | }
37 |
38 | NEX.ShowNotif = function(data) {
39 | if (data.persist === undefined) {
40 | var $notification = NEX.CreateNotification(data);
41 | $('.notif-container').append($notification);
42 | setTimeout(function() {
43 | $.when($notification.fadeOut()).done(function() {
44 | $notification.remove()
45 | });
46 | }, data.length != null ? (data.length + 1000) : 2500);
47 | } else {
48 | if (data.persist.toUpperCase() == 'START') {
49 | if (persistentNotifs[data.id] === undefined) {
50 | var $notification = NEX.CreateNotification(data);
51 | $('.notif-container').append($notification);
52 | persistentNotifs[data.id] = $notification;
53 | } else {
54 | let $notification = $(persistentNotifs[data.id])
55 | $notification.addClass('notification').addClass(data.type);
56 | $notification.html(data.text);
57 |
58 | if (data.style !== undefined) {
59 | Object.keys(data.style).forEach(function(css) {
60 | $notification.css(css, data.style[css])
61 | });
62 | }
63 | }
64 | } else if (data.persist.toUpperCase() == 'END') {
65 | let $notification = $(persistentNotifs[data.id]);
66 | $.when($notification.fadeOut()).done(function() {
67 | $notification.remove();
68 | delete persistentNotifs[data.id];
69 | });
70 | }
71 | }
72 | }
73 |
74 | NEX.HUDElements = [];
75 |
76 | NEX.setHUDDisplay = function (opacity) {
77 | $('#hud').css('opacity', opacity);
78 | };
79 |
80 | NEX.insertHUDElement = function (name, index, priority, html, data) {
81 | NEX.HUDElements.push({
82 | name: name,
83 | index: index,
84 | priority: priority,
85 | html: html,
86 | data: data
87 | });
88 |
89 | NEX.HUDElements.sort((a, b) => {
90 | return a.index - b.index || b.priority - a.priority;
91 | });
92 | };
93 |
94 | NEX.updateHUDElement = function (name, data) {
95 | for (let i = 0; i < NEX.HUDElements.length; i++) {
96 | if (NEX.HUDElements[i].name == name) {
97 | NEX.HUDElements[i].data = data;
98 | }
99 | }
100 |
101 | NEX.refreshHUD();
102 | };
103 |
104 | NEX.deleteHUDElement = function (name) {
105 | for (let i = 0; i < NEX.HUDElements.length; i++) {
106 | if (NEX.HUDElements[i].name == name) {
107 | NEX.HUDElements.splice(i, 1);
108 | }
109 | }
110 |
111 | NEX.refreshHUD();
112 | };
113 |
114 | NEX.refreshHUD = function () {
115 | $('#hud').html('');
116 |
117 | for (let i = 0; i < NEX.HUDElements.length; i++) {
118 | let html = Mustache.render(NEX.HUDElements[i].html, NEX.HUDElements[i].data);
119 | $('#hud').append(html);
120 | }
121 | };
122 |
123 | NEX.inventoryNotification = function (add, label, count) {
124 | let notif = '';
125 |
126 | if (add) {
127 | notif += '+';
128 | } else {
129 | notif += '-';
130 | }
131 |
132 | if (count) {
133 | notif += count + ' ' + label;
134 | } else {
135 | notif += ' ' + label;
136 | }
137 |
138 | let elem = $('' + notif + '
');
139 | $('#inventory_notifications').append(elem);
140 |
141 | $(elem).delay(3000).fadeOut(1000, function () {
142 | elem.remove();
143 | });
144 | };
145 |
146 | window.onData = (data) => {
147 | switch (data.action) {
148 | case 'setHUDDisplay': {
149 | NEX.setHUDDisplay(data.opacity);
150 | break;
151 | }
152 |
153 | case 'insertHUDElement': {
154 | NEX.insertHUDElement(data.name, data.index, data.priority, data.html, data.data);
155 | break;
156 | }
157 |
158 | case 'updateHUDElement': {
159 | NEX.updateHUDElement(data.name, data.data);
160 | break;
161 | }
162 |
163 | case 'deleteHUDElement': {
164 | NEX.deleteHUDElement(data.name);
165 | break;
166 | }
167 |
168 | case 'inventoryNotification': {
169 | NEX.inventoryNotification(data.add, data.item, data.count);
170 | }
171 | }
172 | };
173 |
174 | window.onload = function (e) {
175 | window.addEventListener('message', (event) => {
176 | NEX.ShowNotif(event.data);
177 | onData(event.data);
178 | });
179 | };
180 |
181 | })();
182 |
--------------------------------------------------------------------------------
/html/js/mustache.min.js:
--------------------------------------------------------------------------------
1 | (function defineMustache(global,factory){if(typeof exports==="object"&&exports&&typeof exports.nodeName!=="string"){factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],factory)}else{global.Mustache={};factory(global.Mustache)}})(this,function mustacheFactory(mustache){var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function eos(){return this.tail===""};Scanner.prototype.scan=function scan(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function scanUntil(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function push(view){return new Context(view,this)};Context.prototype.lookup=function lookup(name){var cache=this.cache;var value;if(cache.hasOwnProperty(name)){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index")value=this.renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this.unescapedValue(token,context);else if(symbol==="name")value=this.escapedValue(token,context);else if(symbol==="text")value=this.rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype.renderSection=function renderSection(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;j {
2 |
3 | let NEXWrapper = {};
4 | NEXWrapper.MessageSize = 1024;
5 | NEXWrapper.messageId = 0;
6 |
7 | window.SendMessage = function (namespace, type, msg) {
8 |
9 | NEXWrapper.messageId = (NEXWrapper.messageId < 65535) ? NEXWrapper.messageId + 1 : 0;
10 | const str = JSON.stringify(msg);
11 |
12 | for (let i = 0; i < str.length; i++) {
13 |
14 | let count = 0;
15 | let chunk = '';
16 |
17 | while (count < NEXWrapper.MessageSize && i < str.length) {
18 |
19 | chunk += str[i];
20 |
21 | count++;
22 | i++;
23 | }
24 |
25 | i--;
26 |
27 | const data = {
28 | __type: type,
29 | id: NEXWrapper.messageId,
30 | chunk: chunk
31 | }
32 |
33 | if (i == str.length - 1)
34 | data.end = true;
35 |
36 | $.post('https://' + namespace + '/__chunk', JSON.stringify(data));
37 |
38 | }
39 |
40 | }
41 |
42 | })()
43 |
--------------------------------------------------------------------------------
/html/ui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/locale.js:
--------------------------------------------------------------------------------
1 | var locale = [];
2 |
3 | /**
4 | * Similar to the concept of gettext, this function returns the
5 | * localized string for the parsed string. The function supports
6 | * wrapping.
7 | *
8 | * @param {string} args The string we want localized
9 | * @return {string} Returns the localized string
10 | *
11 | */
12 | function _U() {
13 | var args = arguments;
14 | var string = args[0];
15 |
16 | // Was a string specified?
17 | if (!string) {
18 | console.log('locale.js: no string was parsed');
19 | return 'locale.js: no string was parsed';
20 | }
21 |
22 | // Has the locale file been set?
23 | if (locale.length == 0) {
24 | console.log('locale.js: no locale has been set');
25 | return 'locale.js: no locale has been set';
26 | }
27 |
28 | // Does the translation exist?
29 | if (!locale[string]) {
30 | console.log('locale.js: translation [{0}] does not exist'.format(string));
31 | return 'locale.js: translation [{0}] does not exist'.format(string);
32 | }
33 |
34 | // Do we need to format the string?
35 | if (args.length == 1) {
36 | return capitalize(locale[string]);
37 | } else {
38 | return formatString(args);
39 | }
40 | }
41 |
42 | function formatString(args) {
43 | var string = capitalize(locale[args[0]]);
44 |
45 | for (var i = 1; i < args.length; i++) {
46 | string = string.replace(/%s/, args[i]);
47 | }
48 |
49 | return string;
50 | }
51 |
52 | function capitalize(string) {
53 | return string[0].toUpperCase() + string.slice(1);
54 | }
55 |
56 | // https://stackoverflow.com/a/35359503
57 | String.prototype.format = function () {
58 | var args = arguments;
59 | return this.replace(/{(\d+)}/g, function (match, number) {
60 | return typeof args[number] != 'undefined'
61 | ? args[number]
62 | : match
63 | ;
64 | });
65 | };
66 |
--------------------------------------------------------------------------------
/locale.lua:
--------------------------------------------------------------------------------
1 | Locales = {}
2 |
3 | function _(str, ...) -- Translate string
4 |
5 | if Locales[Config.Locale] ~= nil then
6 |
7 | if Locales[Config.Locale][str] ~= nil then
8 | return string.format(Locales[Config.Locale][str], ...)
9 | else
10 | return 'Translation [' .. Config.Locale .. '][' .. str .. '] does not exist'
11 | end
12 |
13 | else
14 | return 'Locale [' .. Config.Locale .. '] does not exist'
15 | end
16 |
17 | end
18 |
19 | function _U(str, ...) -- Translate string first char uppercase
20 | return tostring(_(str, ...):gsub("^%l", string.upper))
21 | end
22 |
--------------------------------------------------------------------------------
/locales/en.lua:
--------------------------------------------------------------------------------
1 | Locales['en'] = {
2 | -- Inventory
3 | ['inventory'] = 'inventory %s / %s',
4 | ['use'] = 'use',
5 | ['give'] = 'give',
6 | ['remove'] = 'remove',
7 | ['return'] = 'return',
8 | ['give_to'] = 'give to',
9 | ['amount'] = 'amount',
10 | ['giveammo'] = 'give ammo',
11 | ['amountammo'] = 'ammunition',
12 | ['noammo'] = 'you dont have enough ammo!',
13 | ['gave_item'] = 'you have given ~y~%sx~s~ ~b~%s~s~ to ~y~%s~s~',
14 | ['received_item'] = 'you have recieved ~y~%sx~s~ ~b~%s~s~ from ~b~%s~s~',
15 | ['gave_weapon'] = 'you have given weapon: ~b~%s~s~ to ~y~%s~s~',
16 | ['gave_weapon_ammo'] = 'you have given ~o~%sx %s~s~ for ~b~%s~s~ to ~y~%s~s~',
17 | ['gave_weapon_withammo'] = 'you have given ~b~%s~s~ with ~o~%sx %s~s~ to ~y~%s~s~',
18 | ['gave_weapon_hasalready'] = '~y~%s~s~ already has ~y~%s~s~',
19 | ['gave_weapon_noweapon'] = '~y~%s~s~ does not have that weapon',
20 | ['received_weapon'] = 'you have recieved ~b~%s~s~ from ~b~%s~s~',
21 | ['received_weapon_ammo'] = 'you have recieved ~o~%sx %s~s~ for your ~b~%s~s~ from ~b~%s~s~',
22 | ['received_weapon_withammo'] = 'you have recieved ~b~%s~s~ with ~o~%sx %s~s~ from ~b~%s~s~',
23 | ['received_weapon_hasalready'] = '~b~%s~s~ has tried to give ~y~%s~s~, but you already have one',
24 | ['received_weapon_noweapon'] = '~b~%s~s~ has tried to give ammunition for ~y~%s~s~, but you dont have one',
25 | ['gave_account_money'] = 'you have given ~g~$%s~s~ (%s) to ~y~%s~s~',
26 | ['received_account_money'] = 'you have recieved ~g~$%s~s~ (%s) from ~b~%s~s~',
27 | ['amount_invalid'] = 'amount invalid',
28 | ['players_nearby'] = 'there are no players nearby',
29 | ['ex_inv_lim'] = 'Impossible action, ~y~%s~s~ has a full inventory.',
30 | ['imp_invalid_quantity'] = 'Impossible action, invalid quantity.',
31 | ['imp_invalid_amount'] = 'Impossible action, invalid amount.',
32 | ['threw_standard'] = 'You have thrown ~y~%sx~s~ ~b~%s~s~',
33 | ['threw_account'] = 'You have thrown ~g~$%s~s~ ~b~%s~s~',
34 | ['threw_weapon'] = 'You have thrown ~y~1x~s~ ~b~%s~s~',
35 | ['threw_weapon_ammo'] = 'You have thrown ~y~1x~s~ ~b~%s~s~ with ~o~%sx~s~ bullets',
36 | ['threw_weapon_already'] = 'You are already carrying this weapon',
37 | ['threw_cannot_pickup'] = 'You were unable to carry this item because your inventory is full!',
38 | ['threw_pickup_prompt'] = 'press ~y~E~s~ to pickup',
39 |
40 | -- Key mapping
41 | ['keymap_showinventory'] = 'Show inventory',
42 |
43 | -- Salary related
44 | ['received_salary'] = 'Final salary: ~g~$%s~s~ \nTAX: ~g~$%s\n~s~Bonus: ~g~$%s',
45 | ['received_help'] = 'You have received your wellfare check: ~g~$%s~s~',
46 | ['company_nomoney'] = 'The company you work for is too poor to pay you',
47 | ['received_paycheck'] = 'Check received',
48 | ['bank'] = 'maze Bank',
49 | ['account_bank'] = 'Bank',
50 | ['account_black_money'] = 'Dirty money',
51 | ['account_money'] = 'Money',
52 |
53 | ['act_imp'] = 'Impossible Action',
54 | ['in_vehicle'] = 'you cannot give someone anything while in a vehicle',
55 |
56 | -- Commands
57 | ['command_car'] = 'Spawning a Vehicle',
58 | ['command_car_car'] = 'vehicle spawn name or hash',
59 | ['command_cardel'] = 'Delete the nearest vehicle',
60 | ['command_cardel_radius'] = 'optional, remove all vehicles within the specified radius',
61 | ['command_clear'] = 'Clear chat',
62 | ['command_clearall'] = 'Clear chat for all players',
63 | ['command_clearinventory'] = 'Empty all players inventory',
64 | ['command_clearloadout'] = 'clear a players loadout',
65 | ['command_giveaccountmoney'] = 'Give money to the account',
66 | ['command_giveaccountmoney_account'] = 'Account name valid',
67 | ['command_giveaccountmoney_amount'] = 'Amount to add',
68 | ['command_giveaccountmoney_invalid'] = 'Invalid account name',
69 | ['command_giveitem'] = 'Give an item to a player',
70 | ['command_giveitem_item'] = 'Object name',
71 | ['command_giveitem_count'] = 'Number of objects',
72 | ['command_giveweapon'] = 'Give a player a weapon',
73 | ['command_giveweapon_weapon'] = 'Name of the weapon',
74 | ['command_giveweapon_ammo'] = 'Ammo reload',
75 | ['command_giveweapon_hasalready'] = 'This player already has this weapon',
76 | ['command_giveweaponcomponent'] = 'Give the weapon component',
77 | ['command_giveweaponcomponent_component'] = 'Component name',
78 | ['command_giveweaponcomponent_invalid'] = 'Invalid component',
79 | ['command_giveweaponcomponent_hasalready'] = 'The player already has this component',
80 | ['command_giveweaponcomponent_missingweapon'] = 'The player already has this weapon',
81 | ['command_save'] = 'Save the player to the database',
82 | ['command_saveall'] = 'Add all players to the database',
83 | ['command_setaccountmoney'] = 'Enter the amount of money',
84 | ['command_setaccountmoney_amount'] = 'Amount of money to give',
85 | ['command_setcoords'] = 'Teleport to coordinates',
86 | ['command_setcoords_x'] = 'x axis',
87 | ['command_setcoords_y'] = 'y axis',
88 | ['command_setcoords_z'] = 'z axis',
89 | ['command_setjob'] = 'Give the player a job',
90 | ['command_setjob_job'] = 'Name of the job',
91 | ['command_setjob_grade'] = 'Job rank',
92 | ['command_setjob_invalid'] = 'job, degree, or both are invalid',
93 | ['command_setgroup'] = 'Enter the players group',
94 | ['command_setgroup_group'] = 'Group name',
95 | ['commanderror_argumentmismatch'] = 'argument count discrepancy (Passed %s, are required %s)',
96 | ['commanderror_argumentmismatch_number'] = 'Argument #%s type mismatch (passed string, desired number)',
97 | ['commanderror_invaliditem'] = 'Invalid object name',
98 | ['commanderror_invalidweapon'] = 'Invalid weapon',
99 | ['commanderror_console'] = 'This command cannot be executed in the console',
100 | ['commanderror_invalidcommand'] = '^3%s^0 is not a valid command!',
101 | ['commanderror_invalidplayerid'] = 'There is no online player matching the given id',
102 | ['commandgeneric_playerid'] = 'Player ID',
103 |
104 | -- Locale settings
105 | ['locale_digit_grouping_symbol'] = ',',
106 | ['locale_currency'] = '$%s',
107 |
108 | -- Weapons
109 | ['weapon_knife'] = 'Knife',
110 | ['weapon_nightstick'] = 'Nightstick',
111 | ['weapon_hammer'] = 'Hammer',
112 | ['weapon_bat'] = 'Bat',
113 | ['weapon_golfclub'] = 'Golf club',
114 | ['weapon_crowbar'] = 'Crowbar',
115 | ['weapon_pistol'] = 'Pistol',
116 | ['weapon_combatpistol'] = 'Combat Pistol',
117 | ['weapon_appistol'] = 'AP Gun',
118 | ['weapon_pistol50'] = 'Pistol .50',
119 | ['weapon_microsmg'] = 'Micro Smg',
120 | ['weapon_smg'] = 'SMG',
121 | ['weapon_assaultsmg'] = 'Assault SMG',
122 | ['weapon_assaultrifle'] = 'Assault Rifle',
123 | ['weapon_carbinerifle'] = 'Carbine Rifle',
124 | ['weapon_advancedrifle'] = 'Advanced Rifle',
125 | ['weapon_mg'] = 'Machine Gun',
126 | ['weapon_combatmg'] = 'Combat Machine Gun',
127 | ['weapon_pumpshotgun'] = 'Pump Shotgun',
128 | ['weapon_sawnoffshotgun'] = 'Sawn-off Shotgun',
129 | ['weapon_assaultshotgun'] = 'Assault Shotgun',
130 | ['weapon_bullpupshotgun'] = 'Bullpup Shotgun',
131 | ['weapon_stungun'] = 'Taser',
132 | ['weapon_sniperrifle'] = 'Sniper Rifle',
133 | ['weapon_heavysniper'] = 'Heavy Sniper Rifle',
134 | ['weapon_grenadelauncher'] = 'Grenade Launcher',
135 | ['weapon_rpg'] = 'Missile Launcher',
136 | ['weapon_minigun'] = 'Minigun',
137 | ['weapon_grenade'] = 'Grenade',
138 | ['weapon_stickybomb'] = 'C4',
139 | ['weapon_smokegrenade'] = 'Smoke Grenade',
140 | ['weapon_bzgas'] = 'Tear Gas',
141 | ['weapon_molotov'] = 'Molotov',
142 | ['weapon_fireextinguisher'] = 'Fire Extinguisher',
143 | ['weapon_petrolcan'] = 'Petrol Can',
144 | ['weapon_ball'] = 'Ball',
145 | ['weapon_snspistol'] = 'Small Gun',
146 | ['weapon_bottle'] = 'Bottle',
147 | ['weapon_gusenberg'] = 'Thompson Machine Gun',
148 | ['weapon_specialcarbine'] = 'Special Carbine',
149 | ['weapon_heavypistol'] = 'Heavy Pistol',
150 | ['weapon_bullpuprifle'] = 'Semi-auto Rifle',
151 | ['weapon_dagger'] = 'Dagger',
152 | ['weapon_vintagepistol'] = 'Vintage Pistol',
153 | ['weapon_firework'] = 'Firework Launcher',
154 | ['weapon_musket'] = 'Musket',
155 | ['weapon_heavyshotgun'] = 'Heavy Shotgun',
156 | ['weapon_marksmanrifle'] = 'Marksman Rifle',
157 | ['weapon_hominglauncher'] = 'Homing Missile Launcher',
158 | ['weapon_proxmine'] = 'Proximity Mine',
159 | ['weapon_snowball'] = 'Snowball',
160 | ['weapon_flaregun'] = 'Flaregun',
161 | ['weapon_combatpdw'] = 'Combat PDW',
162 | ['weapon_marksmanpistol'] = 'Marksman Pistol',
163 | ['weapon_knuckle'] = 'Iron Fists',
164 | ['weapon_hatchet'] = 'Hatchet',
165 | ['weapon_railgun'] = 'Railgun',
166 | ['weapon_machete'] = 'Machete',
167 | ['weapon_machinepistol'] = 'Machine Pistol',
168 | ['weapon_switchblade'] = 'Switchblade',
169 | ['weapon_revolver'] = 'Revolver',
170 | ['weapon_dbshotgun'] = 'Double Barrel Shotgun',
171 | ['weapon_compactrifle'] = 'Compact Rifle',
172 | ['weapon_autoshotgun'] = 'Auto Shotgun',
173 | ['weapon_battleaxe'] = 'Battleaxe',
174 | ['weapon_compactlauncher'] = 'Compact Launcher',
175 | ['weapon_minismg'] = 'Mini SMG',
176 | ['weapon_pipebomb'] = 'Pipebomb',
177 | ['weapon_poolcue'] = 'Pool Cue',
178 | ['weapon_wrench'] = 'Wrench',
179 | ['weapon_flashlight'] = 'Flashlight',
180 | ['gadget_parachute'] = 'Parachute',
181 | ['weapon_flare'] = 'Flare',
182 | ['weapon_doubleaction'] = 'Double-action Revolver',
183 |
184 | -- Weapon Components
185 | ['component_clip_default'] = 'Factory Charger',
186 | ['component_clip_extended'] = 'Extender Charger',
187 | ['component_clip_drum'] = 'Drum Loader',
188 | ['component_clip_box'] = 'Box Loader',
189 | ['component_flashlight'] = 'Flashlight',
190 | ['component_scope'] = 'Scope',
191 | ['component_scope_advanced'] = 'Advanced Scope',
192 | ['component_suppressor'] = 'Silencer',
193 | ['component_grip'] = 'Grip',
194 | ['component_luxary_finish'] = 'Luxury Finish',
195 |
196 |
197 | -- Weapon Ammo
198 | ['ammo_rounds'] = 'Round(s)',
199 | ['ammo_shells'] = 'Shell(s)',
200 | ['ammo_charge'] = 'Charge',
201 | ['ammo_petrol'] = 'Gallons of gasoline',
202 | ['ammo_firework'] = 'Firework(s)',
203 | ['ammo_rockets'] = 'Rocket(s)',
204 | ['ammo_grenadelauncher'] = 'Grenade(s)',
205 | ['ammo_grenade'] = 'Grenade(s)',
206 | ['ammo_stickybomb'] = 'Bomb(s)',
207 | ['ammo_pipebomb'] = 'Bomb(s)',
208 | ['ammo_smokebomb'] = 'Bomb(s)',
209 | ['ammo_molotov'] = 'Molotov Cocktail(s)',
210 | ['ammo_proxmine'] = 'Mine(s)',
211 | ['ammo_bzgas'] = 'Gas(s)',
212 | ['ammo_ball'] = 'Ball(s)',
213 | ['ammo_snowball'] = 'Snowball',
214 | ['ammo_flare'] = 'Flare(s)',
215 | ['ammo_flaregun'] = 'Flare(s)',
216 |
217 | -- Weapon Tints
218 | ['tint_default'] = 'Common camouflage',
219 | ['tint_green'] = 'Green Camouflage',
220 | ['tint_gold'] = 'Gold Camouflage',
221 | ['tint_pink'] = 'Pink Camouflage',
222 | ['tint_army'] = 'Navel Camouflage',
223 | ['tint_lspd'] = 'Police Camouflage',
224 | ['tint_orange'] = 'Orange Camouflage',
225 | ['tint_platinum'] = 'Platinum Camouflage',
226 | }
227 |
--------------------------------------------------------------------------------
/server/classes/player.lua:
--------------------------------------------------------------------------------
1 | function CreateExtendedPlayer(dbId, playerId, charId, identifier, group, accounts, inventory, weight, job, job2, loadout, name, coords, firstname, lastname, dob, height, unlockCharacters, tutorial, vip, sex, jobInv)
2 | local self = {}
3 |
4 | self.dbId = dbId
5 | self.charId = charId
6 | self.accounts = accounts
7 | self.coords = coords
8 | self.group = group
9 | self.identifier = identifier
10 | self.inventory = inventory
11 | self.job = job
12 | self.job2 = job2
13 | self.loadout = loadout
14 | self.name = name
15 | self.playerId = playerId
16 | self.source = playerId
17 | self.variables = {}
18 | self.weight = weight
19 | self.maxWeight = Config.MaxWeight
20 | self.firstname = firstname
21 | self.lastname = lastname
22 | self.dob = dob
23 | self.height = height
24 | self.tutorial = tutorial
25 | self.vip = vip
26 | self.sex = sex
27 | self.jobInvitation = jobInv
28 |
29 | self.unlockCharacters = unlockCharacters or 0
30 | self.switchState = false
31 | self.readyForPlay = false
32 |
33 | ExecuteCommand(('add_principal identifier.license:%s group.%s'):format(self.identifier, self.group))
34 |
35 | self.setVIP = function(value)
36 | local vipId = tonumber(value)
37 | if vipId >= 0 and vipId <= 6 then
38 | self.vip = vipId
39 | else
40 | self.vip = 0
41 | end
42 | end
43 |
44 | self.getVip = function()
45 | return self.vip
46 | end
47 |
48 | self.isVip = function()
49 | return self.vip
50 | end
51 |
52 | self.isTutorialPassed = function()
53 | return self.tutorial
54 | end
55 |
56 | self.setTutorialStatus = function(value)
57 | self.tutorial = value
58 | end
59 |
60 | self.getDBId = function()
61 | return self.dbId
62 | end
63 |
64 | self.getUnlockedCharacters = function()
65 | return self.unlockCharacters
66 | end
67 |
68 | self.setUnlockedCharacters = function(value)
69 | self.unlockCharacters = value
70 | end
71 |
72 | self.addUnlockedCharacters = function(value)
73 | self.unlockCharacters = self.unlockCharacters + value
74 | end
75 |
76 | self.removeUnlockedCharacters = function(value)
77 | self.unlockCharacters = self.unlockCharacters- 1
78 | end
79 |
80 | self.getCharacterId = function()
81 | return self.charId
82 | end
83 |
84 | self.setCharacterId = function(charId)
85 | self.charId = charId
86 | end
87 |
88 | self.setGameData = function()
89 | return {
90 |
91 | setName = function(firstname, lastname)
92 | self.firstItem = firstItem
93 | self.lastname = lastname
94 | end,
95 |
96 | setFirstname = function(newValue)
97 | self.firstname = newValue
98 | end,
99 |
100 | setLastname = function(newValue)
101 | self.lastname = newValue
102 | end,
103 |
104 | setDob = function(newValue)
105 | self.dob = newValue
106 | end,
107 |
108 | setHeight = function(newValue)
109 | self.height = newValue
110 | end,
111 |
112 | setSex = function(newValue)
113 | self.sex = newValue
114 | end
115 | }
116 | end
117 |
118 | self.getGameData = function()
119 | return {
120 | getFirstname = function()
121 | return self.firstname
122 | end,
123 |
124 | getLastname = function()
125 | return self.lastname
126 | end,
127 |
128 | getFullName = function()
129 | return self.firstname .. " " .. self.lastname
130 | end,
131 |
132 | getDob = function()
133 | return {
134 | getFullDate = function()
135 | return self.dob
136 | end,
137 |
138 | getAge = function()
139 | return 0
140 | end
141 | }
142 | end,
143 |
144 | getHeight = function()
145 | return self.height
146 | end,
147 |
148 | getSex = function()
149 | return self.sex
150 | end
151 | }
152 | end
153 |
154 | self.triggerEvent = function(eventName, ...)
155 | TriggerClientEvent(eventName, self.source, ...)
156 | end
157 |
158 | self.PrepareForCharacterSwitching = function()
159 | self.switchState = true
160 | self.triggerEvent("nex:characters:prepareForSwitching")
161 | end
162 |
163 | self.SetPlayerSwitchState = function(state)
164 | self.switchState = state
165 | end
166 |
167 | self.IsPlayerSwitchInProgress = function()
168 | return self.switchState
169 | end
170 |
171 | self.IsPlayerReadyForPlay = function()
172 | return self.readyForPlay
173 | end
174 |
175 | self.SetPlayerReadyForPlay = function(toggle)
176 | self.readyForPlay = toggle
177 | end
178 |
179 | self.setCoords = function(coords, heading)
180 | self.updateCoords(coords, heading)
181 | self.triggerEvent('nex:Core:teleport', coords)
182 | end
183 |
184 | self.updateCoords = function(coords, heading)
185 | self.coords = {x = NEX.Math.Round(coords.x, 1), y = NEX.Math.Round(coords.y, 1), z = NEX.Math.Round(coords.z, 1), heading = NEX.Math.Round(heading or 0.0, 1)}
186 | end
187 |
188 | self.getCoords = function(vector)
189 | if vector then
190 | return vector3(self.coords.x, self.coords.y, self.coords.z)
191 | else
192 | return self.coords
193 | end
194 | end
195 |
196 | self.kick = function(reason)
197 | DropPlayer(self.source, reason)
198 | end
199 |
200 | self.setPoints = function(money)
201 | money = NEX.Math.Round(money)
202 | self.setAccountMoney('points', money)
203 | end
204 |
205 | self.getPoints = function()
206 | return self.getAccount('points').money
207 | end
208 |
209 | self.addPoints = function(money)
210 | money = NEX.Math.Round(money)
211 | self.addAccountMoney('points', money)
212 | end
213 |
214 | self.removePoints = function(money)
215 | money = NEX.Math.Round(money)
216 | self.removeAccountMoney('points', money)
217 | end
218 |
219 | self.setMoney = function(money)
220 | money = NEX.Math.Round(money)
221 | self.setAccountMoney('money', money)
222 | end
223 |
224 | self.getMoney = function()
225 | return self.getAccount('money').money
226 | end
227 |
228 | self.addMoney = function(money)
229 | money = NEX.Math.Round(money)
230 | self.addAccountMoney('money', money)
231 | end
232 |
233 | self.removeMoney = function(money)
234 | money = NEX.Math.Round(money)
235 | self.removeAccountMoney('money', money)
236 | end
237 |
238 | self.getBankMoney = function()
239 | return self.getAccount('bank').money
240 | end
241 |
242 | self.addBankMoney = function(money)
243 | money = NEX.Math.Round(money)
244 | self.addAccountMoney('bank', money)
245 | end
246 |
247 | self.removeBankMoney = function(money)
248 | money = NEX.Math.Round(money)
249 | self.removeAccountMoney('bank', money)
250 | end
251 |
252 |
253 | self.getBlackMoney = function()
254 | return self.getAccount('black_money').money
255 | end
256 |
257 | self.addBlackMoney = function(money)
258 | money = NEX.Math.Round(money)
259 | self.addAccountMoney('black_money', money)
260 | end
261 |
262 | self.removeBlackMoney = function(money)
263 | money = NEX.Math.Round(money)
264 | self.removeAccountMoney('black_money', money)
265 | end
266 |
267 |
268 | self.getIdentifier = function()
269 | return self.identifier
270 | end
271 |
272 | self.setGroup = function(newGroup)
273 | ExecuteCommand(('remove_principal identifier.license:%s group.%s'):format(self.identifier, self.group))
274 | self.group = newGroup
275 | ExecuteCommand(('add_principal identifier.license:%s group.%s'):format(self.identifier, self.group))
276 | end
277 |
278 | self.getGroup = function()
279 | return self.group
280 | end
281 |
282 | self.set = function(k, v)
283 | self.variables[k] = v
284 | end
285 |
286 | self.get = function(k)
287 | return self.variables[k]
288 | end
289 |
290 | self.getAccounts = function(minimal)
291 | if minimal then
292 | local minimalAccounts = {}
293 |
294 | for k,v in ipairs(self.accounts) do
295 | minimalAccounts[v.name] = v.money
296 | end
297 |
298 | return minimalAccounts
299 | else
300 | return self.accounts
301 | end
302 | end
303 |
304 | self.getAccount = function(account)
305 | for k,v in ipairs(self.accounts) do
306 | if v.name == account then
307 | return v
308 | end
309 | end
310 | end
311 |
312 | self.getInventory = function(minimal)
313 | if minimal then
314 | local minimalInventory = {}
315 |
316 | for k,v in ipairs(self.inventory) do
317 | if v.count > 0 then
318 | minimalInventory[v.name] = v.count
319 | end
320 | end
321 |
322 | return minimalInventory
323 | else
324 | return self.inventory
325 | end
326 | end
327 |
328 | self.getJob = function()
329 | return self.job
330 | end
331 |
332 | self.getJob2 = function()
333 | return self.job2
334 | end
335 |
336 | self.getLoadout = function(minimal)
337 | if minimal then
338 | local minimalLoadout = {}
339 |
340 | for k,v in ipairs(self.loadout) do
341 | minimalLoadout[v.name] = {ammo = v.ammo}
342 | if v.tintIndex > 0 then minimalLoadout[v.name].tintIndex = v.tintIndex end
343 |
344 | if #v.components > 0 then
345 | local components = {}
346 |
347 | for k2,component in ipairs(v.components) do
348 | if component ~= 'clip_default' then
349 | table.insert(components, component)
350 | end
351 | end
352 |
353 | if #components > 0 then
354 | minimalLoadout[v.name].components = components
355 | end
356 | end
357 | end
358 |
359 | return minimalLoadout
360 | else
361 | return self.loadout
362 | end
363 | end
364 |
365 | self.getName = function()
366 | return self.name
367 | end
368 |
369 | self.setName = function(newName)
370 | self.name = newName
371 | end
372 |
373 | self.setAccountMoney = function(accountName, money)
374 | if money >= 0 then
375 | local account = self.getAccount(accountName)
376 |
377 | if account then
378 | local prevMoney = account.money
379 | local newMoney = NEX.Math.Round(money)
380 | account.money = newMoney
381 |
382 | self.triggerEvent('nex:Core:setAccountMoney', account)
383 | end
384 | end
385 | end
386 |
387 | self.addAccountMoney = function(accountName, money)
388 | if money > 0 then
389 | local account = self.getAccount(accountName)
390 |
391 | if account then
392 | local newMoney = account.money + NEX.Math.Round(money)
393 | account.money = newMoney
394 |
395 | self.triggerEvent('nex:Core:setAccountMoney', account)
396 | end
397 | end
398 | end
399 |
400 | self.removeAccountMoney = function(accountName, money)
401 | if money > 0 then
402 | local account = self.getAccount(accountName)
403 |
404 | if account then
405 | local newMoney = account.money - NEX.Math.Round(money)
406 | account.money = newMoney
407 |
408 | self.triggerEvent('nex:Core:setAccountMoney', account)
409 | end
410 | end
411 | end
412 |
413 | self.getInventoryItem = function(name)
414 | for k,v in ipairs(self.inventory) do
415 | if v.name == name then
416 | return v
417 | end
418 | end
419 |
420 | return
421 | end
422 |
423 | self.addInventoryItem = function(name, count)
424 | local item = self.getInventoryItem(name)
425 |
426 | if item then
427 | count = NEX.Math.Round(count)
428 | item.count = item.count + count
429 | self.weight = self.weight + (item.weight * count)
430 |
431 | TriggerEvent('nex:Core:onAddInventoryItem', self.source, item.name, item.count)
432 | self.triggerEvent('nex:Core:addInventoryItem', item.name, item.count)
433 | end
434 | end
435 |
436 | self.removeInventoryItem = function(name, count)
437 | local item = self.getInventoryItem(name)
438 |
439 | if item then
440 | count = NEX.Math.Round(count)
441 | local newCount = item.count - count
442 |
443 | if newCount >= 0 then
444 | item.count = newCount
445 | self.weight = self.weight - (item.weight * count)
446 |
447 | TriggerEvent('nex:Core:onRemoveInventoryItem', self.source, item.name, item.count)
448 | self.triggerEvent('nex:Core:removeInventoryItem', item.name, item.count)
449 | end
450 | end
451 | end
452 |
453 | self.playFrontEndSound = function(sound, soundset)
454 | self.triggerEvent('nex:Core:playFrontEndSound', sound, soundset)
455 | end
456 |
457 | self.setInventoryItem = function(name, count)
458 | local item = self.getInventoryItem(name)
459 |
460 | if item and count >= 0 then
461 | count = NEX.Math.Round(count)
462 |
463 | if count > item.count then
464 | self.addInventoryItem(item.name, count - item.count)
465 | else
466 | self.removeInventoryItem(item.name, item.count - count)
467 | end
468 | end
469 | end
470 |
471 | self.getWeight = function()
472 | return self.weight
473 | end
474 |
475 | self.getMaxWeight = function()
476 | return self.maxWeight
477 | end
478 |
479 | self.canCarryItem = function(name, count)
480 | local currentWeight, itemWeight = self.weight, NEX.Items[name].weight
481 | local newWeight = currentWeight + (itemWeight * count)
482 |
483 | return newWeight <= self.maxWeight
484 | end
485 |
486 | self.canSwapItem = function(firstItem, firstItemCount, testItem, testItemCount)
487 | local firstItemObject = self.getInventoryItem(firstItem)
488 | local testItemObject = self.getInventoryItem(testItem)
489 |
490 | if firstItemObject.count >= firstItemCount then
491 | local weightWithoutFirstItem = NEX.Math.Round(self.weight - (firstItemObject.weight * firstItemCount))
492 | local weightWithTestItem = NEX.Math.Round(weightWithoutFirstItem + (testItemObject.weight * testItemCount))
493 |
494 | return weightWithTestItem <= self.maxWeight
495 | end
496 |
497 | return false
498 | end
499 |
500 | self.setMaxWeight = function(newWeight)
501 | self.maxWeight = newWeight
502 | self.triggerEvent('nex:Core:setMaxWeight', self.maxWeight)
503 | end
504 |
505 | self.setJob = function(category, job, grade)
506 | if category > 0 and category < 3 then
507 | grade = tostring(grade)
508 | local lastJob = json.decode(json.encode(self.job))
509 |
510 | if NEX.DoesJobExist(job, grade) then
511 | local jobObject, gradeObject = NEX.Jobs[job], NEX.Jobs[job].grades[grade]
512 |
513 | if category == 1 then
514 | self.job.id = jobObject.id
515 | self.job.name = jobObject.name
516 | self.job.label = jobObject.label
517 |
518 | self.job.grade = tonumber(grade)
519 | self.job.grade_name = gradeObject.name
520 | self.job.grade_label = gradeObject.label
521 | self.job.grade_salary = gradeObject.salary
522 | else
523 | self.job2.id = jobObject.id
524 | self.job2.name = jobObject.name
525 | self.job2.label = jobObject.label
526 |
527 | self.job2.grade = tonumber(grade)
528 | self.job2.grade_name = gradeObject.name
529 | self.job2.grade_label = gradeObject.label
530 | self.job2.grade_salary = gradeObject.salary
531 | end
532 |
533 | TriggerEvent('nex:Core:setJob', self.source, self.job, lastJob)
534 | self.triggerEvent('nex:Core:setJob', self.job)
535 | else
536 | print(('[NexCore] [^3WARNING^7] Ignoring invalid .setJob() usage for "%s"'):format(self.identifier))
537 | end
538 | else
539 | print(('[NexCore] [^3WARNING^7] INVALID JOB ID IN .setJob() usage for "%s"'):format(self.identifier))
540 | end
541 | end
542 |
543 | self.addWeapon = function(weaponName, ammo)
544 | if not self.hasWeapon(weaponName) then
545 | local weaponLabel = NEX.GetWeaponLabel(weaponName)
546 |
547 | table.insert(self.loadout, {
548 | name = weaponName,
549 | ammo = ammo,
550 | label = weaponLabel,
551 | components = {},
552 | tintIndex = 0
553 | })
554 |
555 | self.triggerEvent('nex:Core:addWeapon', weaponName, ammo)
556 | self.triggerEvent('nex:Core:addInventoryItem', weaponLabel, false, true)
557 | end
558 | end
559 |
560 | self.addWeaponComponent = function(weaponName, weaponComponent)
561 | local loadoutNum, weapon = self.getWeapon(weaponName)
562 |
563 | if weapon then
564 | local component = NEX.GetWeaponComponent(weaponName, weaponComponent)
565 |
566 | if component then
567 | if not self.hasWeaponComponent(weaponName, weaponComponent) then
568 | table.insert(self.loadout[loadoutNum].components, weaponComponent)
569 | self.triggerEvent('nex:Core:addWeaponComponent', weaponName, weaponComponent)
570 | self.triggerEvent('nex:Core:addInventoryItem', component.label, false, true)
571 | end
572 | end
573 | end
574 | end
575 |
576 | self.addWeaponAmmo = function(weaponName, ammoCount)
577 | local loadoutNum, weapon = self.getWeapon(weaponName)
578 |
579 | if weapon then
580 | weapon.ammo = weapon.ammo + ammoCount
581 | self.triggerEvent('nex:Core:setWeaponAmmo', weaponName, weapon.ammo)
582 | end
583 | end
584 |
585 | self.updateWeaponAmmo = function(weaponName, ammoCount)
586 | local loadoutNum, weapon = self.getWeapon(weaponName)
587 |
588 | if weapon then
589 | if ammoCount < weapon.ammo then
590 | weapon.ammo = ammoCount
591 | end
592 | end
593 | end
594 |
595 | self.setWeaponTint = function(weaponName, weaponTintIndex)
596 | local loadoutNum, weapon = self.getWeapon(weaponName)
597 |
598 | if weapon then
599 | local weaponNum, weaponObject = NEX.GetWeapon(weaponName)
600 |
601 | if weaponObject.tints and weaponObject.tints[weaponTintIndex] then
602 | self.loadout[loadoutNum].tintIndex = weaponTintIndex
603 | self.triggerEvent('nex:Core:setWeaponTint', weaponName, weaponTintIndex)
604 | self.triggerEvent('nex:Core:addInventoryItem', weaponObject.tints[weaponTintIndex], false, true)
605 | end
606 | end
607 | end
608 |
609 | self.getWeaponTint = function(weaponName)
610 | local loadoutNum, weapon = self.getWeapon(weaponName)
611 |
612 | if weapon then
613 | return weapon.tintIndex
614 | end
615 |
616 | return 0
617 | end
618 |
619 | self.removeWeapon = function(weaponName)
620 | local weaponLabel
621 |
622 | for k,v in ipairs(self.loadout) do
623 | if v.name == weaponName then
624 | weaponLabel = v.label
625 |
626 | for k2,v2 in ipairs(v.components) do
627 | self.removeWeaponComponent(weaponName, v2)
628 | end
629 |
630 | table.remove(self.loadout, k)
631 | break
632 | end
633 | end
634 |
635 | if weaponLabel then
636 | self.triggerEvent('nex:Core:removeWeapon', weaponName)
637 | self.triggerEvent('nex:Core:removeInventoryItem', weaponLabel, false, true)
638 | end
639 | end
640 |
641 | self.removeWeaponComponent = function(weaponName, weaponComponent)
642 | local loadoutNum, weapon = self.getWeapon(weaponName)
643 |
644 | if weapon then
645 | local component = NEX.GetWeaponComponent(weaponName, weaponComponent)
646 |
647 | if component then
648 | if self.hasWeaponComponent(weaponName, weaponComponent) then
649 | for k,v in ipairs(self.loadout[loadoutNum].components) do
650 | if v == weaponComponent then
651 | table.remove(self.loadout[loadoutNum].components, k)
652 | break
653 | end
654 | end
655 |
656 | self.triggerEvent('nex:Core:removeWeaponComponent', weaponName, weaponComponent)
657 | self.triggerEvent('nex:Core:removeInventoryItem', component.label, false, true)
658 | end
659 | end
660 | end
661 | end
662 |
663 | self.removeWeaponAmmo = function(weaponName, ammoCount)
664 | local loadoutNum, weapon = self.getWeapon(weaponName)
665 |
666 | if weapon then
667 | weapon.ammo = weapon.ammo - ammoCount
668 | self.triggerEvent('nex:Core:setWeaponAmmo', weaponName, weapon.ammo)
669 | end
670 | end
671 |
672 | self.hasWeaponComponent = function(weaponName, weaponComponent)
673 | local loadoutNum, weapon = self.getWeapon(weaponName)
674 |
675 | if weapon then
676 | for k,v in ipairs(weapon.components) do
677 | if v == weaponComponent then
678 | return true
679 | end
680 | end
681 |
682 | return false
683 | else
684 | return false
685 | end
686 | end
687 |
688 | self.hasWeapon = function(weaponName)
689 | for k,v in ipairs(self.loadout) do
690 | if v.name == weaponName then
691 | return true
692 | end
693 | end
694 |
695 | return false
696 | end
697 |
698 | self.getWeapon = function(weaponName)
699 | for k,v in ipairs(self.loadout) do
700 | if v.name == weaponName then
701 | return k, v
702 | end
703 | end
704 |
705 | return
706 | end
707 |
708 | self.showNotification = function(msg)
709 | self.triggerEvent('nex:Core:showNotification', msg)
710 | end
711 |
712 | self.showHelpNotification = function(msg, thisFrame, beep, duration)
713 | self.triggerEvent('nex:Core:showHelpNotification', msg, thisFrame, beep, duration)
714 | end
715 |
716 | self.sendAlert = function(data)
717 | self.triggerEvent('nex:Core:SendAlert', data)
718 | end
719 |
720 | self.PersistentHudText = function(data)
721 | self.triggerEvent('nex:Core::PersistentHudText')
722 | end
723 |
724 | return self
725 | end
726 |
--------------------------------------------------------------------------------
/server/commands.lua:
--------------------------------------------------------------------------------
1 | NEX.RegisterCommand('tp', 'admin', function(xPlayer, args, showError)
2 | local currentCoords = xPlayer.getCoords(true)
3 | NEX.RegisterLog(xPlayer.source, "ACTION", "Command: /tp\nTeleport [".. currentCoords.x .. " " .. currentCoords.y .. " " .. currentCoords.z .."] a [".. args.x .. " " .. args.y .. " " .. args.z .."]" )
4 | xPlayer.setCoords({x = args.x, y = args.y, z = args.z})
5 |
6 | end, false, {help = _U('command_setcoords'), validate = true, arguments = {
7 | {name = 'x', help = _U('command_setcoords_x'), type = 'number'},
8 | {name = 'y', help = _U('command_setcoords_y'), type = 'number'},
9 | {name = 'z', help = _U('command_setcoords_z'), type = 'number'}
10 | }})
11 |
12 | NEX.RegisterCommand('reloadjobs', 'admin', function(xPlayer, args, showError)
13 | NEX.ReloadJobs()
14 | xPlayer.sendAlert({
15 | type = "success",
16 | title = "Reloaded Jobs!",
17 | text = "The system will start soon for everyone...",
18 | length = 4000,
19 | style = {}
20 | })
21 | end, false, {help = 'Reload the job database.', validate = true, arguments = {}})
22 |
23 | NEX.RegisterCommand('reloadqueue', 'admin', function(xPlayer, args, showError)
24 | TriggerEvent('QueueNex:RefreshList')
25 | xPlayer.sendAlert({
26 | type = "success",
27 | title = "Priority Queue Reloaded!",
28 | text = "The system will start soon for everyone...",
29 | length = 4000,
30 | style = {}
31 | })
32 | end, false, {help = 'Reload priority queue.', validate = true, arguments = {}})
33 |
34 |
35 |
36 | -- NEX.RegisterCommand('changecharacter', 'admin', function(xPlayer, args, showError)
37 | -- xPlayer.setCoords({x = args.x, y = args.y, z = args.z})
38 | -- end, false, {help = _U('command_setcoords'), validate = true, arguments = {
39 | -- {name = 'x', help = _U('command_setcoords_x'), type = 'number'},
40 | -- {name = 'y', help = _U('command_setcoords_y'), type = 'number'},
41 | -- {name = 'z', help = _U('command_setcoords_z'), type = 'number'}
42 | -- }})
43 |
44 | -- NEX.RegisterCommand('changecharacterto', 'admin', function(xPlayer, args, showError)
45 | -- xPlayer.setCoords({x = args.x, y = args.y, z = args.z})
46 | -- end, false, {help = _U('command_setcoords'), validate = true, arguments = {
47 | -- {name = 'x', help = _U('command_setcoords_x'), type = 'number'},
48 | -- {name = 'y', help = _U('command_setcoords_y'), type = 'number'},
49 | -- {name = 'z', help = _U('command_setcoords_z'), type = 'number'}
50 | -- }})
51 |
52 | NEX.RegisterCommand('setjob', 'admin', function(xPlayer, args, showError)
53 |
54 | -- Temp fix for 'console' commands use
55 | if not xPlayer then
56 | xPlayer = {}
57 | xPlayer.source = nil
58 | end
59 |
60 | if NEX.DoesJobExist(args.job, args.grade) then
61 | if args.category == 1 or args.category == 2 then
62 | args.playerId.setJob(args.category, args.job, args.grade)
63 | local data = {
64 | type = "success",
65 | title = "Job Changed!",
66 | text = "New job to the player! " .. args.playerId.source .. " a " .. args.job .. " [".. args.category .."]",
67 | length = 4000,
68 | style = {}
69 | }
70 | xPlayer.sendAlert(data)
71 | NEX.RegisterLog(xPlayer.source, "ACTION", "Command: /setjob\nChange the job #".. args.category .." from DB: "..args.playerId.dbId.." to " .. "(".. args.job .." [".. args.grade .."])")
72 | else
73 | showError("There is no category, try 1 or 2.")
74 | end
75 | else
76 | showError(_U('command_setjob_invalid'))
77 | end
78 | end, true, {help = _U('command_setjob'), validate = true, arguments = {
79 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
80 | {name = "category", help = "Job Category", type = "number"},
81 | {name = 'job', help = _U('command_setjob_job'), type = 'string'},
82 | {name = 'grade', help = _U('command_setjob_grade'), type = 'number'}
83 | }})
84 |
85 | NEX.RegisterCommand('car', 'admin', function(xPlayer, args, showError)
86 | xPlayer.triggerEvent('nex:Core:runSpawnCommand', args.car)
87 | end, false, {help = _U('command_car'), validate = false, arguments = {
88 | {name = 'car', help = _U('command_car_car'), type = 'any'}
89 | }})
90 |
91 | NEX.RegisterCommand({'cardel', 'dv'}, 'admin', function(xPlayer, args, showError)
92 | xPlayer.triggerEvent('nex:Core:deleteVehicle', args.radius)
93 | end, false, {help = _U('command_cardel'), validate = false, arguments = {
94 | {name = 'radius', help = _U('command_cardel_radius'), type = 'any'}
95 | }})
96 |
97 | NEX.RegisterCommand('setaccountmoney', 'admin', function(xPlayer, args, showError)
98 |
99 | -- Temp fix for 'console' commands use
100 | if not xPlayer then
101 | xPlayer = {}
102 | xPlayer.source = nil
103 | end
104 |
105 | if args.playerId.getAccount(args.account) then
106 | args.playerId.setAccountMoney(args.account, args.amount)
107 | NEX.RegisterLog(xPlayer.source, "ACTION", "Set money:\nReceives: " .. args.playerId.getName() .. "(".. args.playerId.charId .." [".. args.playerId.dbId .."]) [Bill: " .. args.account .. " ($".. args.amount ..")]")
108 | else
109 | showError(_U('command_giveaccountmoney_invalid'))
110 | end
111 | end, true, {help = _U('command_setaccountmoney'), validate = true, arguments = {
112 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
113 | {name = 'account', help = _U('command_giveaccountmoney_account'), type = 'string'},
114 | {name = 'amount', help = _U('command_setaccountmoney_amount'), type = 'number'}
115 | }})
116 |
117 | NEX.RegisterCommand('giveaccountmoney', 'admin', function(xPlayer, args, showError)
118 |
119 | -- Temp fix for 'console' commands use
120 | if not xPlayer then
121 | xPlayer = {}
122 | xPlayer.source = nil
123 | end
124 |
125 | if args.playerId.getAccount(args.account) then
126 | args.playerId.addAccountMoney(args.account, args.amount)
127 | NEX.RegisterLog(xPlayer.source, "ACTION", "Add money:\nReceives: " .. args.playerId.getName() .. "(".. args.playerId.charId .." [".. args.playerId.dbId .."]) [Bill: " .. args.account .. " ($".. args.amount ..")]")
128 |
129 | else
130 | showError(_U('command_giveaccountmoney_invalid'))
131 | end
132 | end, true, {help = _U('command_giveaccountmoney'), validate = true, arguments = {
133 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
134 | {name = 'account', help = _U('command_giveaccountmoney_account'), type = 'string'},
135 | {name = 'amount', help = _U('command_giveaccountmoney_amount'), type = 'number'}
136 | }})
137 |
138 | NEX.RegisterCommand('giveitem', 'admin', function(xPlayer, args, showError)
139 | --args.playerId.addInventoryItem(args.item, args.count)
140 |
141 | -- Temp fix for 'console' commands use
142 | if not xPlayer then
143 | xPlayer = {}
144 | xPlayer.source = nil
145 | end
146 |
147 | TriggerClientEvent('player:receiveItem', args.playerId.source, args.item, args.count)
148 | NEX.RegisterLog(xPlayer.source, "ACTION", "Delivery Item:\nReceuves: " .. args.playerId.getName() .. "(".. args.playerId.charId .." [".. args.playerId.dbId .."]) [Item: " .. args.item .. " ($".. args.count ..")]")
149 |
150 | end, true, {help = _U('command_giveitem'), validate = true, arguments = {
151 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
152 | {name = 'item', help = _U('command_giveitem_item'), type = 'item'},
153 | {name = 'count', help = _U('command_giveitem_count'), type = 'number'}
154 | }})
155 |
156 | -- NEX.RegisterCommand('giveweapon', 'admin', function(xPlayer, args, showError)
157 | -- if args.playerId.hasWeapon(args.weapon) then
158 | -- showError(_U('command_giveweapon_hasalready'))
159 | -- else
160 | -- xPlayer.addInventoryItem(args.weapon, 1)
161 | -- --xPlayer.addWeapon(args.weapon, args.ammo)
162 | -- end
163 | -- end, true, {help = _U('command_giveweapon'), validate = true, arguments = {
164 | -- {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
165 | -- {name = 'weapon', help = _U('command_giveweapon_weapon'), type = 'item'},
166 | -- {name = 'ammo', help = _U('command_giveweapon_ammo'), type = 'number'}
167 | -- }})
168 |
169 | NEX.RegisterCommand('giveweaponcomponent', 'admin', function(xPlayer, args, showError)
170 | if args.playerId.hasWeapon(args.weaponName) then
171 | local component = NEX.GetWeaponComponent(args.weaponName, args.componentName)
172 |
173 | if component then
174 | if xPlayer.hasWeaponComponent(args.weaponName, args.componentName) then
175 | showError(_U('command_giveweaponcomponent_hasalready'))
176 | else
177 | xPlayer.addWeaponComponent(args.weaponName, args.componentName)
178 | end
179 | else
180 | showError(_U('command_giveweaponcomponent_invalid'))
181 | end
182 | else
183 | showError(_U('command_giveweaponcomponent_missingweapon'))
184 | end
185 | end, true, {help = _U('command_giveweaponcomponent'), validate = true, arguments = {
186 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
187 | {name = 'weaponName', help = _U('command_giveweapon_weapon'), type = 'weapon'},
188 | {name = 'componentName', help = _U('command_giveweaponcomponent_component'), type = 'string'}
189 | }})
190 |
191 | NEX.RegisterCommand({'clear', 'cls'}, 'user', function(xPlayer, args, showError)
192 | xPlayer.triggerEvent('chat:clear')
193 | end, false, {help = _U('command_clear')})
194 |
195 | NEX.RegisterCommand({'clearall', 'clsall'}, 'admin', function(xPlayer, args, showError)
196 | TriggerClientEvent('chat:clear', -1)
197 | end, false, {help = _U('command_clearall')})
198 |
199 | NEX.RegisterCommand('clearinventory', 'admin', function(xPlayer, args, showError)
200 | for k,v in ipairs(args.playerId.inventory) do
201 | if v.count > 0 then
202 | args.playerId.setInventoryItem(v.name, 0)
203 | end
204 | end
205 | end, true, {help = _U('command_clearinventory'), validate = true, arguments = {
206 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'}
207 | }})
208 |
209 | NEX.RegisterCommand('clearloadout', 'admin', function(xPlayer, args, showError)
210 | for k,v in ipairs(args.playerId.loadout) do
211 | args.playerId.removeWeapon(v.name)
212 | end
213 | end, true, {help = _U('command_clearloadout'), validate = true, arguments = {
214 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'}
215 | }})
216 |
217 | NEX.RegisterCommand('setgroup', 'admin', function(xPlayer, args, showError)
218 | args.playerId.setGroup(args.group)
219 |
220 | -- Temp fix for 'console' commands use
221 | if not xPlayer then
222 | xPlayer = {}
223 | xPlayer.source = nil
224 | end
225 |
226 | NEX.RegisterLog(xPlayer.source, "ACTION", "Command: /setgroup\nAssign the group of: " .. args.playerId.getName() .. " [".. args.playerId.dbId .."]" .. " to " .. args.group)
227 | end, true, {help = _U('command_setgroup'), validate = true, arguments = {
228 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'},
229 | {name = 'group', help = _U('command_setgroup_group'), type = 'string'},
230 | }})
231 |
232 | NEX.RegisterCommand('save', 'admin', function(xPlayer, args, showError)
233 | NEX.SavePlayer(args.playerId)
234 | end, true, {help = _U('command_save'), validate = true, arguments = {
235 | {name = 'playerId', help = _U('commandgeneric_playerid'), type = 'player'}
236 | }})
237 |
238 | NEX.RegisterCommand('saveall', 'admin', function(xPlayer, args, showError)
239 | NEX.SavePlayers()
240 | end, true, {help = _U('command_saveall')})
241 |
242 |
243 | NEX.RegisterCommand('menu', 'admin', function(xPlayer, args, showError)
244 | TriggerClientEvent('nex_admin:client:openMenu', xPlayer.source, xPlayer.getGroup(), xPlayer)
245 | end, true, {help = 'Activate Admin Menu'})
246 |
247 | NEX.RegisterCommand('hud', 'user', function(xPlayer, args, showError)
248 | TriggerClientEvent('nex:UI:setVisible', xPlayer.source)
249 | end, true, {help = 'Activate / Deactivate the HUD'})
250 |
251 |
252 | --- BANKING
253 |
254 | if Config.EnablePayCommand then
255 |
256 | NEX.RegisterCommand('pay', 'user', function(xPlayer, args, showError)
257 |
258 | local amount = args.monto
259 | local targetPlayer = args.paypal
260 |
261 | if xPlayer.getMoney() >= amount and xPlayer.getMoney() > 0 then
262 | if xPlayer.charId ~= targetPlayer.charId then
263 | TriggerClientEvent('banking:client:CheckDistance', xPlayer.source, targetPlayer.source, amount)
264 |
265 | NEX.RegisterLog(xPlayer.source, "ECONOMY", "(Pay) Give Money:\nReceives: " .. targetPlayer.getName() .. "(".. targetPlayer.charId .." [".. targetPlayer.dbId .."]) ($".. amount ..")]")
266 |
267 | else
268 | local data = {
269 | type = "error",
270 | title = "Whoops!",
271 | text = "Life is a bycycle, but is it worth getting on?",
272 | length = 4000,
273 | style = {}
274 | }
275 | xPlayer.sendAlert(data)
276 | end
277 | else
278 | local data = {
279 | type = "error",
280 | title = "Whoops!",
281 | text = "Make sure you have enough money or enter a larger amount to pay.",
282 | length = 4000,
283 | style = {}
284 | }
285 | xPlayer.sendAlert(data)
286 | end
287 |
288 | end, true, {help = _U('command_setgroup'), validate = true, arguments = {
289 | {name = 'paypal', help = _U('commandgeneric_playerid'), type = 'player'},
290 | {name = 'monto', help = _U('command_setgroup_group'), type = 'number'},
291 | }})
292 |
293 | end
--------------------------------------------------------------------------------
/server/common.lua:
--------------------------------------------------------------------------------
1 | NEX = {}
2 | NEX.Players = {}
3 | NEX.UsableItemsCallbacks = {}
4 | NEX.Items = {}
5 | NEX.ServerCallbacks = {}
6 | NEX.ClientCallbacks = {}
7 | NEX.ServerEvents = {}
8 | NEX.TimeoutCount = -1
9 | NEX.CancelledTimeouts = {}
10 | NEX.Pickups = {}
11 | NEX.PickupId = 0
12 | NEX.Jobs = {}
13 | NEX.RegisteredCommands = {}
14 | NEX.DevMode = true
15 | NEX.RegisterResources = ConfigServer.SecureResources
16 |
17 | NEX.Webhooks = ConfigServer.DiscordWebhooks
18 |
19 | NEX.ReloadJobs = function()
20 | MySQL.Async.fetchAll('SELECT * FROM jobs', {}, function(jobs)
21 | for k,v in ipairs(jobs) do
22 | NEX.Jobs[v.name] = v
23 | NEX.Jobs[v.name].grades = {}
24 | end
25 |
26 | MySQL.Async.fetchAll('SELECT * FROM job_grades', {}, function(jobGrades)
27 | for k,v in ipairs(jobGrades) do
28 | if NEX.Jobs[v.job_name] then
29 | NEX.Jobs[v.job_name].grades[tostring(v.grade)] = v
30 | else
31 | print(('[NEX Nexus Version] [^3WARNING^7] Ignoring job grades for "%s" due to missing job'):format(v.job_name))
32 | end
33 | end
34 |
35 | for k2,v2 in pairs(NEX.Jobs) do
36 | if NEX.Table.SizeOf(v2.grades) == 0 then
37 | NEX.Jobs[v2.name] = nil
38 | print(('[NEX Nexus Version] [^3WARNING^7] Ignoring job "%s" due to no job grades found'):format(v2.name))
39 | end
40 | end
41 | end)
42 | end)
43 | end
44 |
45 | AddEventHandler('nexus:getNexusObject', function(cb)
46 | cb(NEX)
47 | end)
48 |
49 | function getSharedObject()
50 | return NEX
51 | end
52 |
53 | MySQL.ready(function()
54 | MySQL.Async.fetchAll('SELECT * FROM items', {}, function(result)
55 | for k,v in ipairs(result) do
56 | NEX.Items[v.name] = {
57 | label = v.label,
58 | weight = v.weight,
59 | rare = v.rare,
60 | canRemove = v.can_remove
61 | }
62 | end
63 | end)
64 |
65 | NEX.ReloadJobs()
66 |
67 | print('[NexCore] [^2INFO^7] NEX Nexus Version Initialized')
68 | end)
69 |
70 | RegisterServerEvent('nex:Core:clientLog')
71 | AddEventHandler('nex:Core:clientLog', function(msg)
72 | if Config.EnableDebug then
73 | print(('[NexCore] [^2TRACE^7] %s^7'):format(msg))
74 | end
75 | end)
76 |
77 | RegisterServerEvent('nex:Core:triggerServerEvent')
78 | AddEventHandler('nex:Core:triggerServerEvent', function(name, requestId, ...)
79 | local playerId = source
80 | NEX.TriggerServerEvent(name, playerId, requestId, ...)
81 | end)
82 |
83 | RegisterServerEvent('nex:Core:triggerServerCallback')
84 | AddEventHandler('nex:Core:triggerServerCallback', function(name, requestId, ...)
85 | local playerId = source
86 |
87 | NEX.TriggerServerCallback(name, requestId, playerId, function(...)
88 | TriggerClientEvent('nex:Core:serverCallback', playerId, requestId, ...)
89 | end, ...)
90 | end)
91 |
92 | AddEventHandler('onResourceStart', function(resourceName)
93 | if (GetCurrentResourceName() == resourceName) then
94 | Citizen.Wait(3000)
95 | for k, script in pairs(NEX.RegisterResources) do
96 | print('[NexCore] [^2INFO^7] Ensuring ' .. script .. '...')
97 | ExecuteCommand("ensure " .. script)
98 | Citizen.Wait(1000)
99 | end
100 | end
101 | end)
102 |
--------------------------------------------------------------------------------
/server/functions.lua:
--------------------------------------------------------------------------------
1 | NEX.Trace = function(msg)
2 | if Config.EnableDebug then
3 | print(('[NexCore] [^2TRACE^7] %s^7'):format(msg))
4 | end
5 | end
6 |
7 | NEX.SetTimeout = function(msec, cb)
8 | local id = NEX.TimeoutCount + 1
9 |
10 | SetTimeout(msec, function()
11 | if NEX.CancelledTimeouts[id] then
12 | NEX.CancelledTimeouts[id] = nil
13 | else
14 | cb()
15 | end
16 | end)
17 |
18 | NEX.TimeoutCount = id
19 |
20 | return id
21 | end
22 |
23 | NEX.RegisterCommand = function(name, group, cb, allowConsole, suggestion)
24 | if type(name) == 'table' then
25 | for k,v in ipairs(name) do
26 | NEX.RegisterCommand(v, group, cb, allowConsole, suggestion)
27 | end
28 |
29 | return
30 | end
31 |
32 | if NEX.RegisteredCommands[name] then
33 | print(('[NexCore] [^3WARNING^7] An command "%s" is already registered, overriding command'):format(name))
34 |
35 | if NEX.RegisteredCommands[name].suggestion then
36 | TriggerClientEvent('chat:removeSuggestion', -1, ('/%s'):format(name))
37 | end
38 | end
39 |
40 | if suggestion then
41 | if not suggestion.arguments then suggestion.arguments = {} end
42 | if not suggestion.help then suggestion.help = '' end
43 |
44 | TriggerClientEvent('chat:addSuggestion', -1, ('/%s'):format(name), suggestion.help, suggestion.arguments)
45 | end
46 |
47 | NEX.RegisteredCommands[name] = {group = group, cb = cb, allowConsole = allowConsole, suggestion = suggestion}
48 |
49 | RegisterCommand(name, function(playerId, args, rawCommand)
50 | local command = NEX.RegisteredCommands[name]
51 |
52 | if not command.allowConsole and playerId == 0 then
53 | print(('[NexCore] [^3WARNING^7] %s'):format(_U('commanderror_console')))
54 | else
55 | local xPlayer, error = NEX.GetPlayerFromId(playerId), nil
56 |
57 | if command.suggestion then
58 | if command.suggestion.validate then
59 | if #args ~= #command.suggestion.arguments then
60 | error = _U('commanderror_argumentmismatch', #args, #command.suggestion.arguments)
61 | end
62 | end
63 |
64 | if not error and command.suggestion.arguments then
65 | local newArgs = {}
66 |
67 | for k,v in ipairs(command.suggestion.arguments) do
68 | if v.type then
69 | if v.type == 'number' then
70 | local newArg = tonumber(args[k])
71 |
72 | if newArg then
73 | newArgs[v.name] = newArg
74 | else
75 | error = _U('commanderror_argumentmismatch_number', k)
76 | end
77 | elseif v.type == "multistring" then
78 | newArgs[v.name] = args
79 | elseif v.type == 'player' or v.type == 'playerId' then
80 | local targetPlayer = tonumber(args[k])
81 |
82 | if args[k] == 'me' then targetPlayer = playerId end
83 |
84 | if targetPlayer then
85 | local xTargetPlayer = NEX.GetPlayerFromId(targetPlayer)
86 |
87 | if xTargetPlayer then
88 | if v.type == 'player' then
89 | newArgs[v.name] = xTargetPlayer
90 | else
91 | newArgs[v.name] = targetPlayer
92 | end
93 | else
94 | error = _U('commanderror_invalidplayerid')
95 | end
96 | else
97 | error = _U('commanderror_argumentmismatch_number', k)
98 | end
99 | elseif v.type == 'string' then
100 | newArgs[v.name] = args[k]
101 | elseif v.type == 'item' then
102 | newArgs[v.name] = args[k]
103 | elseif v.type == 'weapon' then
104 | if NEX.GetWeapon(args[k]) then
105 | newArgs[v.name] = string.upper(args[k])
106 | else
107 | error = _U('commanderror_invalidweapon')
108 | end
109 | elseif v.type == 'any' then
110 | newArgs[v.name] = args[k]
111 | end
112 | end
113 |
114 | if error then break end
115 | end
116 |
117 | args = newArgs
118 | end
119 | end
120 |
121 | if error then
122 | if playerId == 0 then
123 | print(('[NexCore] [^3WARNING^7] %s^7'):format(error))
124 | else
125 | local data = {
126 | type = "error",
127 | title = "Command Whoops!",
128 | text = error,
129 | length = 3000,
130 | style = {}
131 | }
132 | xPlayer.sendAlert(data)
133 | --xPlayer.triggerEvent('chat:addMessage', {args = {'^1SYSTEM', error}})
134 | end
135 | else
136 | cb(xPlayer or false, args, function(msg)
137 | if playerId == 0 then
138 | print(('[NexCore] [^3WARNING^7] %s^7'):format(msg))
139 | end
140 | end)
141 | end
142 | end
143 | end, true)
144 |
145 | if type(group) == 'table' then
146 | for k,v in ipairs(group) do
147 | ExecuteCommand(('add_ace group.%s command.%s allow'):format(v, name))
148 | end
149 | else
150 | ExecuteCommand(('add_ace group.%s command.%s allow'):format(group, name))
151 | end
152 | end
153 |
154 | NEX.ClearTimeout = function(id)
155 | NEX.CancelledTimeouts[id] = true
156 | end
157 |
158 | NEX.RegisterServerEvent = function(name, cb)
159 | print("Registry => ", name)
160 | NEX.ServerEvents[name] = cb
161 | end
162 |
163 | NEX.TriggerClientCallback = function(source, name, cb, ...)
164 | local playerId = tostring(source)
165 |
166 | if NEX.ClientCallbacks == nil then
167 | NEX.ClientCallbacks = {}
168 | end
169 |
170 | if NEX.ClientCallbacks[playerId] == nil then
171 | NEX.ClientCallbacks[playerId] = {}
172 | NEX.ClientCallbacks[playerId]['CurrentRequestId'] = 0
173 | end
174 |
175 | NEX.ClientCallbacks[playerId][tostring(NEX.ClientCallbacks[playerId]['CurrentRequestId'])] = cb
176 |
177 | TriggerClientEvent('nex:Core:triggerClientCallback', source, name, NEX.ClientCallbacks[playerId]['CurrentRequestId'], ...)
178 |
179 | if NEX.ClientCallbacks[playerId]['CurrentRequestId'] < 65535 then
180 | NEX.ClientCallbacks[playerId]['CurrentRequestId'] = NEX.ClientCallbacks[playerId]['CurrentRequestId'] + 1
181 | else
182 | NEX.ClientCallbacks[playerId]['CurrentRequestId'] = 0
183 | end
184 | end
185 |
186 | NEX.TriggerServerEvent = function(name, source, ...)
187 | if NEX.ServerEvents ~= nil and NEX.ServerEvents[name] ~= nil then
188 | NEX.ServerEvents[name](source, ...)
189 | else
190 | print("[NexCore] [^3WARNING^7] TriggerServerEvent => '" .. name .. "' not found.")
191 | end
192 | end
193 |
194 | NEX.RegisterServerCallback = function(name, cb)
195 | NEX.ServerCallbacks[name] = cb
196 | end
197 |
198 | NEX.TriggerServerCallback = function(name, requestId, source, cb, ...)
199 | Citizen.Wait(30) -- fix event spam?
200 | if NEX.ServerCallbacks[name] then
201 | NEX.ServerCallbacks[name](source, cb, ...)
202 | else
203 | print(('[NexCore] [^3WARNING^7] Server callback "%s" does not exist.'):format(name))
204 | end
205 | end
206 |
207 | NEX.SwitchPlayerData = function(xPlayer, playerId, charId, cb)
208 | local canContinue = false
209 | print('[NexCore] [^2INFO^7] Preparing player switching for ' .. xPlayer.getName() .. ' from #'.. xPlayer.getCharacterId() ..' to character #'..charId)
210 | xPlayer.PrepareForCharacterSwitching()
211 |
212 | while xPlayer.IsPlayerSwitchInProgress() do
213 | Citizen.Wait(5000)
214 | xPlayer.SetPlayerSwitchState(false)
215 | end
216 |
217 | NEX.SavePlayer(xPlayer, function()
218 | local identifier = xPlayer.identifier
219 | loadNEXPlayer(identifier, playerId, charId, function(isValid)
220 | if isValid then
221 | canContinue = true
222 | end
223 | end)
224 | end)
225 | Citizen.Wait(200)
226 | if canContinue then
227 | cb(true)
228 | else
229 | cb(false)
230 | end
231 | end
232 |
233 | NEX.SavePlayer = function(xPlayer, cb)
234 | local asyncTasks = {}
235 |
236 | table.insert(asyncTasks, function(cb2)
237 | MySQL.Async.execute('UPDATE users SET job_invitation=@jobInvite, isVip=@vip, sex=@sex, unlockCharacters=@unlockCharacters, tutorial=@tutorial, characterId = @charId, firstname = @firstname, lastname = @lastname, dob = @dob, height = @height, accounts = @accounts, job = @job, job_grade = @job_grade, job2=@job2, job_grade2 = @job_grade2, `group` = @group, loadout = @loadout, position = @position, inventory = @inventory WHERE identifier = @identifier', {
238 | ['@charId'] = xPlayer.getCharacterId(),
239 | ['@accounts'] = json.encode(xPlayer.getAccounts(true)),
240 | ['@job'] = xPlayer.job.name,
241 | ['@job_grade'] = xPlayer.job.grade,
242 | ['@job2'] = xPlayer.job2.name,
243 | ['@job_grade2'] = xPlayer.job2.grade,
244 | ['@group'] = xPlayer.getGroup(),
245 | ['@loadout'] = json.encode(xPlayer.getLoadout(true)),
246 | ['@position'] = json.encode(xPlayer.getCoords()),
247 | ['@identifier'] = xPlayer.getIdentifier(),
248 | ['@inventory'] = json.encode(xPlayer.getInventory(true)),
249 | ['@firstname'] = xPlayer.getGameData().getFirstname(),
250 | ['@lastname'] = xPlayer.getGameData().getLastname(),
251 | ['@dob'] = xPlayer.getGameData().getDob().getFullDate(),
252 | ['@height'] = xPlayer.getGameData().getHeight(),
253 | ['@tutorial'] = xPlayer.isTutorialPassed() or 0,
254 | ['@unlockCharacters'] = xPlayer.getUnlockedCharacters(),
255 | ['@sex'] = xPlayer.sex,
256 | ['@jobInvite'] = xPlayer.jobInvitation or nil,
257 | ['@vip'] = xPlayer.getVip()
258 | }, function(rowsChanged)
259 | cb2()
260 | end)
261 |
262 | if xPlayer.getCharacterId() > 0 then
263 | MySQL.Async.execute('UPDATE users_characters SET isVip=@vip, job_invitation=@jobInvite, sex = @sex, firstname = @firstname, lastname = @lastname, dob = @dob, height = @height, accounts = @accounts, job = @job, job_grade = @job_grade, job2=@job2, job_grade2 = @job_grade2, loadout = @loadout, position = @position, inventory = @inventory WHERE identifier = @identifier AND characterId = @charId', {
264 | ['@accounts'] = json.encode(xPlayer.getAccounts(true)),
265 | ['@job'] = xPlayer.job.name,
266 | ['@job_grade'] = xPlayer.job.grade,
267 | ['@job2'] = xPlayer.job2.name,
268 | ['@job_grade2'] = xPlayer.job2.grade,
269 | ['@charId'] = xPlayer.getCharacterId(),
270 | ['@loadout'] = json.encode(xPlayer.getLoadout(true)),
271 | ['@position'] = json.encode(xPlayer.getCoords()),
272 | ['@identifier'] = xPlayer.getIdentifier(),
273 | ['@inventory'] = json.encode(xPlayer.getInventory(true)),
274 | ['@firstname'] = xPlayer.getGameData().getFirstname(),
275 | ['@lastname'] = xPlayer.getGameData().getLastname(),
276 | ['@dob'] = xPlayer.getGameData().getDob().getFullDate(),
277 | ['@height'] = xPlayer.getGameData().getHeight(),
278 | ['@sex'] = xPlayer.sex,
279 | ['@jobInvite'] = xPlayer.jobInvitation or nil,
280 | ['@vip'] = xPlayer.getVip()
281 | }, function(rowsChanged)
282 | cb2()
283 | end)
284 | end
285 | end)
286 |
287 | Async.parallel(asyncTasks, function(results)
288 | print(('[NexCore] [^2INFO^7] Saved player "%s^7"'):format(xPlayer.getName()))
289 |
290 | if cb then
291 | cb()
292 | end
293 | end)
294 | end
295 |
296 | NEX.SavePlayers = function(cb)
297 | local xPlayers, asyncTasks = NEX.GetPlayers(), {}
298 |
299 | for i=1, #xPlayers, 1 do
300 | table.insert(asyncTasks, function(cb2)
301 | local xPlayer = NEX.GetPlayerFromId(xPlayers[i])
302 | NEX.SavePlayer(xPlayer, cb2)
303 | end)
304 | end
305 |
306 | Async.parallelLimit(asyncTasks, 8, function(results)
307 | print(('[NexCore] [^2INFO^7] Saved %s player(s)'):format(#xPlayers))
308 | if cb then
309 | cb()
310 | end
311 | end)
312 | end
313 |
314 | NEX.StartDBSync = function()
315 | function saveData()
316 | NEX.SavePlayers()
317 | SetTimeout(10 * 60 * 1000, saveData)
318 | end
319 |
320 | SetTimeout(10 * 60 * 1000, saveData)
321 | end
322 |
323 | NEX.GetPlayers = function()
324 | local sources = {}
325 |
326 | for k,v in pairs(NEX.Players) do
327 | table.insert(sources, k)
328 | end
329 |
330 | return sources
331 | end
332 |
333 | NEX.GetPlayerFromId = function(source)
334 | return NEX.Players[tonumber(source)]
335 | end
336 |
337 | NEX.GetPlayerFromIdentifier = function(identifier)
338 | for k,v in pairs(NEX.Players) do
339 | if v.identifier == identifier then
340 | return v
341 | end
342 | end
343 | end
344 |
345 | NEX.GetPlayerFromDBId = function(dbid)
346 | for k,v in pairs(NEX.Players) do
347 | if v.dbId == dbid then
348 | return v
349 | end
350 | end
351 | end
352 |
353 | NEX.GetPlayerFromCharId = function(charId)
354 | for k,v in pairs(NEX.Players) do
355 | if v.charId == charId then
356 | return v
357 | end
358 | end
359 | end
360 |
361 | NEX.RegisterUsableItem = function(item, cb)
362 | NEX.UsableItemsCallbacks[item] = cb
363 | end
364 |
365 | NEX.UseItem = function(source, item)
366 | NEX.UsableItemsCallbacks[item](source, item)
367 | end
368 |
369 | NEX.GetItemLabel = function(item)
370 | if NEX.Items[item] then
371 | return NEX.Items[item].label
372 | end
373 | end
374 |
375 | NEX.CreatePickup = function(type, name, count, label, playerId, components, tintIndex)
376 | local pickupId = (NEX.PickupId == 65635 and 0 or NEX.PickupId + 1)
377 | local xPlayer = NEX.GetPlayerFromId(playerId)
378 | local coords = xPlayer.getCoords()
379 |
380 | NEX.Pickups[pickupId] = {
381 | type = type, name = name,
382 | count = count, label = label,
383 | coords = coords
384 | }
385 |
386 | if type == 'item_weapon' then
387 | NEX.Pickups[pickupId].components = components
388 | NEX.Pickups[pickupId].tintIndex = tintIndex
389 | end
390 |
391 | TriggerClientEvent('nex:Core:createPickup', -1, pickupId, label, coords, type, name, components, tintIndex)
392 | NEX.PickupId = pickupId
393 | end
394 |
395 | NEX.DoesJobExist = function(job, grade)
396 | grade = tostring(grade)
397 |
398 | if job and grade then
399 | if NEX.Jobs[job] and NEX.Jobs[job].grades[grade] then
400 | return true
401 | end
402 | end
403 |
404 | return false
405 | end
406 |
407 | NEX.RegisterLog = function(playerId, category, message)
408 |
409 | local xPlayer = nil
410 | local urlToUse = NEX.Webhooks[category] or nil
411 |
412 | if playerId == nil then
413 | xPlayer = {
414 | getName = function()
415 | return "Console"
416 | end,
417 | getDBId = function()
418 | return -1
419 | end,
420 |
421 | source = -1
422 | }
423 | else
424 | xPlayer = NEX.GetPlayerFromId(playerId)
425 | end
426 |
427 |
428 |
429 | if urlToUse ~= nil and xPlayer ~= nil then
430 | local data = {
431 | embeds = {
432 | {
433 | title = "[VIGILANT] Registered Action",
434 | description = "New action executed:",
435 | color = 16771840,
436 | fields = {
437 | {
438 | name = "SteamName | DB | GameID",
439 | value = xPlayer.getName() .. " | " .. xPlayer.getDBId() .. " | " .. xPlayer.source
440 | },
441 | {
442 | name = "LOG:",
443 | value = message
444 | },
445 | },
446 | footer = {
447 | text = Config.ServerName,
448 | icon_url = ConfigServer.DiscordWebhookImage
449 | }
450 | }
451 | },
452 | username = Config.ServerName,
453 | avatar_url = ConfigServer.DiscordWebhookImage
454 | }
455 | PerformHttpRequest(urlToUse, function(err, text, headers) end, 'POST', json.encode(data), { ['Content-Type'] = 'application/json' })
456 | else
457 | if Config.EnableDebug then
458 | print('[NexCore] [^3WARNING^7] Discord Action Log "'.. category ..'" was null.')
459 | end
460 | end
461 | end
--------------------------------------------------------------------------------
/server/main.lua:
--------------------------------------------------------------------------------
1 | Citizen.CreateThread(function()
2 | SetMapName(Config.ServerName)
3 | SetGameType('Roleplay')
4 | end)
5 |
6 | RegisterNetEvent('nex:Core:onPlayerJoined')
7 | AddEventHandler('nex:Core:onPlayerJoined', function()
8 | if not NEX.Players[source] then
9 | onPlayerJoined(source)
10 | end
11 | end)
12 |
13 | function onPlayerJoined(playerId)
14 | local identifier
15 |
16 | -- CAMBIAR POR STEAMID
17 | for k,v in ipairs(GetPlayerIdentifiers(playerId)) do
18 | if string.match(v, 'license:') then
19 | identifier = string.sub(v, 9)
20 | break
21 | end
22 | end
23 |
24 | if identifier then
25 | if NEX.GetPlayerFromIdentifier(identifier) then
26 | DropPlayer(playerId, ('Whoops!\nError code: [Integrity at stake]\n\nThis error is caused when someone is playing on your Rockstar Games account.\n\nYour Rockstar ID: %s'):format(identifier))
27 | else
28 | MySQL.Async.fetchScalar('SELECT 1 FROM users WHERE identifier = @identifier', {
29 | ['@identifier'] = identifier
30 | }, function(result)
31 | if result then
32 | loadNEXPlayer(identifier, playerId)
33 | else
34 | local accounts = {}
35 |
36 | for account,money in pairs(Config.StartingAccountMoney) do
37 | accounts[account] = money
38 | end
39 |
40 | MySQL.Async.execute('INSERT INTO users (accounts, identifier) VALUES (@accounts, @identifier)', {
41 | ['@accounts'] = json.encode(accounts),
42 | ['@identifier'] = identifier
43 | }, function(rowsChanged)
44 | loadNEXPlayer(identifier, playerId)
45 | end)
46 | end
47 | end)
48 | end
49 | else
50 | DropPlayer(playerId, 'there was an error loading your character!\nError code: identifier-missing-ingame\n\nThe cause of this error is not known, your identifier could not be found. Please come back later or report this problem to the server administration team.')
51 | end
52 | end
53 |
54 | AddEventHandler('playerConnecting', function(name, setCallback, deferrals)
55 | deferrals.defer()
56 | local playerId, identifier = source
57 | Citizen.Wait(100)
58 |
59 | for k,v in ipairs(GetPlayerIdentifiers(playerId)) do
60 | if string.match(v, 'license:') then
61 | identifier = string.sub(v, 9)
62 | break
63 | end
64 | end
65 |
66 | if identifier then
67 | if NEX.GetPlayerFromIdentifier(identifier) then
68 | deferrals.done(('There was an error loading your character!\nError code: identifier-active\n\nThis error is caused by a player on this server who has the same identifier as you have. Make sure you are not playing on the same Rockstar account.\n\nYour Rockstar identifier: %s'):format(identifier))
69 | else
70 | deferrals.done()
71 | end
72 | else
73 | deferrals.done('There was an error loading your character!\nError code: identifier-missing\n\nThe cause of this error is not known, your identifier could not be found. Please come back later or report this problem to the server administration team.')
74 | end
75 | end)
76 |
77 |
78 | function loadNEXPlayer(identifier, playerId, characterId, cbResult)
79 | local tasks = {}
80 |
81 | local userData = {
82 | id = 0,
83 | accounts = {},
84 | inventory = {},
85 | job = {},
86 | job2 = {},
87 | loadout = {},
88 | playerName = GetPlayerName(playerId),
89 | weight = 0
90 | }
91 |
92 | local query = 'SELECT * FROM users WHERE identifier = @identifier'
93 |
94 | if characterId then
95 | --query = "SELECT * FROM users_characters UC WHERE identifier = @identifier AND characterId = @charId"
96 | query = "SELECT users_characters.*, users.job_invitation, users.id, users.unlockCharacters, users.tutorial, users.group FROM users_characters INNER JOIN users ON users_characters.identifier = users.identifier WHERE users_characters.identifier = @identifier AND users_characters.characterId = @charId"
97 | end
98 |
99 | table.insert(tasks, function(cb)
100 | MySQL.Async.fetchAll(query, {
101 | ['@identifier'] = identifier,
102 | ['@charId'] = characterId
103 | }, function(result)
104 |
105 | if result[1] == nil then
106 | cbResult(false)
107 | return TriggerClientEvent('nex:Core:showNotification', playerId, '~r~You have not created your character yet ~y~#'..characterId..'~w~.')
108 | else
109 | if characterId then
110 | NEX.Players[playerId] = nil
111 | end
112 | end
113 |
114 | local job, grade, jobObject, gradeObject = result[1].job, tostring(result[1].job_grade)
115 | local job2, grade2, jobObject2, gradeObject2 = result[1].job2, tostring(result[1].job_grade)
116 | local foundAccounts, foundItems = {}, {}
117 |
118 | userData.id = result[1].id
119 | userData.characterId = result[1].characterId
120 |
121 | userData.jobInv = result[1].job_invitation or nil
122 |
123 | userData.unlockCharacters = result[1].unlockCharacters
124 |
125 | if not characterId then
126 | userData.tutorial = result[1].tutorial
127 | end
128 |
129 | userData.firstname = result[1].firstname
130 | userData.lastname = result[1].lastname
131 | userData.dob = result[1].dob
132 | userData.height = result[1].height
133 | userData.isVip = result[1].isVip
134 |
135 | userData.sex = result[1].sex
136 |
137 |
138 | -- Accounts
139 | if result[1].accounts and result[1].accounts ~= '' then
140 | local accounts = json.decode(result[1].accounts)
141 |
142 | for account,money in pairs(accounts) do
143 | foundAccounts[account] = money
144 | end
145 | end
146 |
147 | for account,label in pairs(Config.Accounts) do
148 | table.insert(userData.accounts, {
149 | name = account,
150 | money = foundAccounts[account] or Config.StartingAccountMoney[account] or 0,
151 | label = label
152 | })
153 | end
154 |
155 | -- Job
156 | if NEX.DoesJobExist(job, grade) then
157 | jobObject, gradeObject = NEX.Jobs[job], NEX.Jobs[job].grades[grade]
158 | else
159 | print(('[NexCore] [^3WARNING^7] Ignoring invalid job for %s [job: %s, grade: %s]'):format(identifier, job, grade))
160 | job, grade = 'unemployed', '0'
161 | jobObject, gradeObject = NEX.Jobs[job], NEX.Jobs[job].grades[grade]
162 | end
163 |
164 | -- Job
165 | if NEX.DoesJobExist(job2, grade2) then
166 | jobObject2, gradeObject2 = NEX.Jobs[job2], NEX.Jobs[job2].grades[grade2]
167 | else
168 | print(('[NexCore] [^3WARNING^7] Ignoring invalid job for %s [job: %s, grade: %s]'):format(identifier, job2, grade2))
169 | job2, grade2 = 'unemployed', '0'
170 | jobObject2, gradeObject2 = NEX.Jobs[job2], NEX.Jobs[job2].grades[grade2]
171 | end
172 |
173 | userData.job.id = jobObject.id
174 | userData.job.name = jobObject.name
175 | userData.job.label = jobObject.label
176 |
177 | userData.job2.id = jobObject2.id
178 | userData.job2.name = jobObject2.name
179 | userData.job2.label = jobObject2.label
180 |
181 | userData.job.grade = tonumber(grade)
182 | userData.job.grade_name = gradeObject.name
183 | userData.job.grade_label = gradeObject.label
184 | userData.job.grade_salary = gradeObject.salary
185 |
186 | userData.job2.grade = tonumber(grade2)
187 | userData.job2.grade_name = gradeObject2.name
188 | userData.job2.grade_label = gradeObject2.label
189 | userData.job2.grade_salary = gradeObject2.salary
190 |
191 | if gradeObject.skin_male then userData.job.skin_male = json.decode(gradeObject.skin_male) end
192 | if gradeObject.skin_female then userData.job.skin_female = json.decode(gradeObject.skin_female) end
193 |
194 | -- Inventory
195 | if result[1].inventory and result[1].inventory ~= '' then
196 | local inventory = json.decode(result[1].inventory)
197 |
198 | for name,count in pairs(inventory) do
199 | local item = NEX.Items[name]
200 |
201 | if item then
202 | foundItems[name] = count
203 | else
204 | print(('[NexCore] [^3WARNING^7] Ignoring invalid item "%s" for "%s"'):format(name, identifier))
205 | end
206 | end
207 | end
208 |
209 | for name,item in pairs(NEX.Items) do
210 | local count = foundItems[name] or 0
211 | if count > 0 then userData.weight = userData.weight + (item.weight * count) end
212 |
213 | table.insert(userData.inventory, {
214 | name = name,
215 | count = count,
216 | label = item.label,
217 | weight = item.weight,
218 | usable = NEX.UsableItemsCallbacks[name] ~= nil,
219 | rare = item.rare,
220 | canRemove = item.canRemove
221 | })
222 | end
223 |
224 | table.sort(userData.inventory, function(a, b)
225 | return a.label < b.label
226 | end)
227 |
228 | -- Group
229 | if result[1].group ~= nil then
230 | userData.group = result[1].group
231 | end
232 |
233 |
234 | -- Loadout
235 | if result[1].loadout and result[1].loadout ~= '' then
236 | local loadout = json.decode(result[1].loadout)
237 |
238 | for name,weapon in pairs(loadout) do
239 | local label = NEX.GetWeaponLabel(name)
240 |
241 | if label then
242 | if not weapon.components then weapon.components = {} end
243 | if not weapon.tintIndex then weapon.tintIndex = 0 end
244 |
245 | table.insert(userData.loadout, {
246 | name = name,
247 | ammo = weapon.ammo,
248 | label = label,
249 | components = weapon.components,
250 | tintIndex = weapon.tintIndex
251 | })
252 | end
253 | end
254 | end
255 |
256 | -- Position
257 | if result[1].position and result[1].position ~= '' then
258 | userData.coords = json.decode(result[1].position)
259 | else
260 | print('[NexCore] [^3WARNING^7] Column "position" in "users" table is missing required default value. Using backup coords, fix your database.')
261 | userData.coords = {x = -269.4, y = -955.3, z = 31.2, heading = 205.8}
262 | end
263 |
264 | cb()
265 | end)
266 | end)
267 |
268 | Async.parallel(tasks, function(results)
269 | local xPlayer = CreateExtendedPlayer(userData.id, playerId, userData.characterId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.job2, userData.loadout, userData.playerName, userData.coords, userData.firstname, userData.lastname, userData.dob, userData.height, userData.unlockCharacters, userData.tutorial, userData.isVip, userData.sex, userData.jobInv)
270 | NEX.Players[playerId] = xPlayer
271 | TriggerEvent('nex:Core:playerLoaded', playerId, xPlayer)
272 |
273 | xPlayer.triggerEvent('nex:Core:playerLoaded', {
274 | dbId = xPlayer.getDBId(),
275 | charId = xPlayer.getCharacterId(),
276 | accounts = xPlayer.getAccounts(),
277 | coords = xPlayer.getCoords(),
278 | identifier = xPlayer.getIdentifier(),
279 | inventory = xPlayer.getInventory(),
280 | job = xPlayer.getJob(),
281 | job2 = xPlayer.getJob2(),
282 | loadout = xPlayer.getLoadout(),
283 | maxWeight = xPlayer.getMaxWeight(),
284 | money = xPlayer.getMoney(),
285 | gameData = xPlayer.getGameData(),
286 | isTutorialPassed = xPlayer.isTutorialPassed()
287 | })
288 |
289 | xPlayer.triggerEvent('nex:Core:createMissingPickups', NEX.Pickups)
290 | xPlayer.triggerEvent('nex:Core:registerSuggestions', NEX.RegisteredCommands)
291 |
292 | if characterId then
293 | print(('[NexCore] [^2INFO^7] Player "%s^7" change character to %s'):format(xPlayer.getName(), characterId))
294 | NEX.SavePlayer(xPlayer)
295 | cbResult(true)
296 | else
297 | print(('[NexCore] [^2INFO^7] Player "%s^7" connected and assigned the ServerID %s'):format(xPlayer.getName(), playerId))
298 | end
299 | end)
300 |
301 | end
302 |
303 | AddEventHandler('chatMessage', function(playerId, author, message)
304 | if message:sub(1, 1) == '/' and playerId > 0 then
305 | CancelEvent()
306 | local commandName = message:sub(1):gmatch("%w+")()
307 | TriggerClientEvent('chat:addMessage', playerId, {args = {'^1SYSTEM', _U('commanderror_invalidcommand', commandName)}})
308 | end
309 | end)
310 |
311 | AddEventHandler('playerDropped', function(reason)
312 | local playerId = source
313 | local xPlayer = NEX.GetPlayerFromId(playerId)
314 |
315 | if xPlayer then
316 | TriggerEvent('nex:Core:playerDropped', playerId, reason)
317 |
318 | NEX.SavePlayer(xPlayer, function()
319 | NEX.Players[playerId] = nil
320 | end)
321 | end
322 | end)
323 |
324 | RegisterNetEvent('nex:Core:updateCoords')
325 | AddEventHandler('nex:Core:updateCoords', function(coords)
326 | local xPlayer = NEX.GetPlayerFromId(source)
327 |
328 | if xPlayer then
329 | xPlayer.updateCoords(coords)
330 | end
331 | end)
332 |
333 | RegisterNetEvent('nex:Core:updateWeaponAmmo')
334 | AddEventHandler('nex:Core:updateWeaponAmmo', function(weaponName, ammoCount)
335 | local xPlayer = NEX.GetPlayerFromId(source)
336 |
337 | if xPlayer then
338 | xPlayer.updateWeaponAmmo(weaponName, ammoCount)
339 | end
340 | end)
341 |
342 | RegisterNetEvent('nex:Core:giveInventoryItem')
343 | AddEventHandler('nex:Core:giveInventoryItem', function(target, type, itemName, itemCount)
344 | local playerId = source
345 | local sourceXPlayer = NEX.GetPlayerFromId(playerId)
346 | local targetXPlayer = NEX.GetPlayerFromId(target)
347 |
348 | if type == 'item_standard' then
349 | local sourceItem = sourceXPlayer.getInventoryItem(itemName)
350 |
351 | if itemCount > 0 and sourceItem.count >= itemCount then
352 | if targetXPlayer.canCarryItem(itemName, itemCount) then
353 | sourceXPlayer.removeInventoryItem(itemName, itemCount)
354 | targetXPlayer.addInventoryItem (itemName, itemCount)
355 |
356 | sourceXPlayer.showNotification(_U('gave_item', itemCount, sourceItem.label, targetXPlayer.name))
357 | targetXPlayer.showNotification(_U('received_item', itemCount, sourceItem.label, sourceXPlayer.name))
358 | else
359 | sourceXPlayer.showNotification(_U('ex_inv_lim', targetXPlayer.name))
360 | end
361 | else
362 | sourceXPlayer.showNotification(_U('imp_invalid_quantity'))
363 | end
364 | elseif type == 'item_account' then
365 | if itemCount > 0 and sourceXPlayer.getAccount(itemName).money >= itemCount then
366 | sourceXPlayer.removeAccountMoney(itemName, itemCount)
367 | targetXPlayer.addAccountMoney (itemName, itemCount)
368 |
369 | sourceXPlayer.showNotification(_U('gave_account_money', NEX.Math.GroupDigits(itemCount), Config.Accounts[itemName], targetXPlayer.name))
370 | targetXPlayer.showNotification(_U('received_account_money', NEX.Math.GroupDigits(itemCount), Config.Accounts[itemName], sourceXPlayer.name))
371 | else
372 | sourceXPlayer.showNotification(_U('imp_invalid_amount'))
373 | end
374 | elseif type == 'item_weapon' then
375 | if sourceXPlayer.hasWeapon(itemName) then
376 | local weaponLabel = NEX.GetWeaponLabel(itemName)
377 |
378 | if not targetXPlayer.hasWeapon(itemName) then
379 | local _, weapon = sourceXPlayer.getWeapon(itemName)
380 | local _, weaponObject = NEX.GetWeapon(itemName)
381 | itemCount = weapon.ammo
382 |
383 | sourceXPlayer.removeWeapon(itemName)
384 | targetXPlayer.addWeapon(itemName, itemCount)
385 |
386 | if weaponObject.ammo and itemCount > 0 then
387 | local ammoLabel = weaponObject.ammo.label
388 | sourceXPlayer.showNotification(_U('gave_weapon_withammo', weaponLabel, itemCount, ammoLabel, targetXPlayer.name))
389 | targetXPlayer.showNotification(_U('received_weapon_withammo', weaponLabel, itemCount, ammoLabel, sourceXPlayer.name))
390 | else
391 | sourceXPlayer.showNotification(_U('gave_weapon', weaponLabel, targetXPlayer.name))
392 | targetXPlayer.showNotification(_U('received_weapon', weaponLabel, sourceXPlayer.name))
393 | end
394 | else
395 | sourceXPlayer.showNotification(_U('gave_weapon_hasalready', targetXPlayer.name, weaponLabel))
396 | targetXPlayer.showNotification(_U('received_weapon_hasalready', sourceXPlayer.name, weaponLabel))
397 | end
398 | end
399 | elseif type == 'item_ammo' then
400 | if sourceXPlayer.hasWeapon(itemName) then
401 | local weaponNum, weapon = sourceXPlayer.getWeapon(itemName)
402 |
403 | if targetXPlayer.hasWeapon(itemName) then
404 | local _, weaponObject = NEX.GetWeapon(itemName)
405 |
406 | if weaponObject.ammo then
407 | local ammoLabel = weaponObject.ammo.label
408 |
409 | if weapon.ammo >= itemCount then
410 | sourceXPlayer.removeWeaponAmmo(itemName, itemCount)
411 | targetXPlayer.addWeaponAmmo(itemName, itemCount)
412 |
413 | sourceXPlayer.showNotification(_U('gave_weapon_ammo', itemCount, ammoLabel, weapon.label, targetXPlayer.name))
414 | targetXPlayer.showNotification(_U('received_weapon_ammo', itemCount, ammoLabel, weapon.label, sourceXPlayer.name))
415 | end
416 | end
417 | else
418 | sourceXPlayer.showNotification(_U('gave_weapon_noweapon', targetXPlayer.name))
419 | targetXPlayer.showNotification(_U('received_weapon_noweapon', sourceXPlayer.name, weapon.label))
420 | end
421 | end
422 | end
423 | end)
424 |
425 | RegisterNetEvent('nex:Core:removeInventoryItem')
426 | AddEventHandler('nex:Core:removeInventoryItem', function(type, itemName, itemCount)
427 | local playerId = source
428 | local xPlayer = NEX.GetPlayerFromId(source)
429 |
430 | if type == 'item_standard' then
431 | if itemCount == nil or itemCount < 1 then
432 | xPlayer.showNotification(_U('imp_invalid_quantity'))
433 | else
434 | local xItem = xPlayer.getInventoryItem(itemName)
435 |
436 | if (itemCount > xItem.count or xItem.count < 1) then
437 | xPlayer.showNotification(_U('imp_invalid_quantity'))
438 | else
439 | xPlayer.removeInventoryItem(itemName, itemCount)
440 | local pickupLabel = ('~y~%s~s~ [~b~%s~s~]'):format(xItem.label, itemCount)
441 | NEX.CreatePickup('item_standard', itemName, itemCount, pickupLabel, playerId)
442 | xPlayer.showNotification(_U('threw_standard', itemCount, xItem.label))
443 | end
444 | end
445 | elseif type == 'item_account' then
446 | if itemCount == nil or itemCount < 1 then
447 | xPlayer.showNotification(_U('imp_invalid_amount'))
448 | else
449 | local account = xPlayer.getAccount(itemName)
450 |
451 | if (itemCount > account.money or account.money < 1) then
452 | xPlayer.showNotification(_U('imp_invalid_amount'))
453 | else
454 | xPlayer.removeAccountMoney(itemName, itemCount)
455 | local pickupLabel = ('~y~%s~s~ [~g~%s~s~]'):format(account.label, _U('locale_currency', NEX.Math.GroupDigits(itemCount)))
456 | NEX.CreatePickup('item_account', itemName, itemCount, pickupLabel, playerId)
457 | xPlayer.showNotification(_U('threw_account', NEX.Math.GroupDigits(itemCount), string.lower(account.label)))
458 | end
459 | end
460 | elseif type == 'item_weapon' then
461 | itemName = string.upper(itemName)
462 |
463 | if xPlayer.hasWeapon(itemName) then
464 | local _, weapon = xPlayer.getWeapon(itemName)
465 | local _, weaponObject = NEX.GetWeapon(itemName)
466 | local components, pickupLabel = NEX.Table.Clone(weapon.components)
467 | xPlayer.removeWeapon(itemName)
468 |
469 | if weaponObject.ammo and weapon.ammo > 0 then
470 | local ammoLabel = weaponObject.ammo.label
471 | pickupLabel = ('~y~%s~s~ [~g~%s~s~ %s]'):format(weapon.label, weapon.ammo, ammoLabel)
472 | xPlayer.showNotification(_U('threw_weapon_ammo', weapon.label, weapon.ammo, ammoLabel))
473 | else
474 | pickupLabel = ('~y~%s~s~'):format(weapon.label)
475 | xPlayer.showNotification(_U('threw_weapon', weapon.label))
476 | end
477 |
478 | NEX.CreatePickup('item_weapon', itemName, weapon.ammo, pickupLabel, playerId, components, weapon.tintIndex)
479 | end
480 | end
481 | end)
482 |
483 | RegisterNetEvent('nex:Core:useItem')
484 | AddEventHandler('nex:Core:useItem', function(itemName)
485 | local xPlayer = NEX.GetPlayerFromId(source)
486 | local count = xPlayer.getInventoryItem(itemName).count
487 |
488 | if count > 0 then
489 | NEX.UseItem(source, itemName)
490 | else
491 | xPlayer.showNotification(_U('act_imp'))
492 | end
493 | end)
494 |
495 | RegisterNetEvent('nex:Core:onPickup')
496 | AddEventHandler('nex:Core:onPickup', function(pickupId)
497 | local pickup, xPlayer, success = NEX.Pickups[pickupId], NEX.GetPlayerFromId(source)
498 |
499 | if pickup then
500 | if pickup.type == 'item_standard' then
501 | if xPlayer.canCarryItem(pickup.name, pickup.count) then
502 | xPlayer.addInventoryItem(pickup.name, pickup.count)
503 | success = true
504 | else
505 | xPlayer.showNotification(_U('threw_cannot_pickup'))
506 | end
507 | elseif pickup.type == 'item_account' then
508 | success = true
509 | xPlayer.addAccountMoney(pickup.name, pickup.count)
510 | elseif pickup.type == 'item_weapon' then
511 | if xPlayer.hasWeapon(pickup.name) then
512 | xPlayer.showNotification(_U('threw_weapon_already'))
513 | else
514 | success = true
515 | xPlayer.addWeapon(pickup.name, pickup.count)
516 | xPlayer.setWeaponTint(pickup.name, pickup.tintIndex)
517 |
518 | for k,v in ipairs(pickup.components) do
519 | xPlayer.addWeaponComponent(pickup.name, v)
520 | end
521 | end
522 | end
523 |
524 | if success then
525 | NEX.Pickups[pickupId] = nil
526 | TriggerClientEvent('nex:Core:removePickup', -1, pickupId)
527 | end
528 | end
529 | end)
530 |
531 | NEX.RegisterServerCallback('nex:Core:getPlayerData', function(source, cb)
532 | local xPlayer = NEX.GetPlayerFromId(source)
533 |
534 | cb({
535 | firstname = xPlayer.firstname,
536 | lastname = xPlayer.lastname,
537 | dob = xPlayer.dob,
538 | dbId = xPlayer.dbId,
539 | identifier = xPlayer.identifier,
540 | accounts = xPlayer.getAccounts(),
541 | inventory = xPlayer.getInventory(),
542 | job = xPlayer.getJob(),
543 | loadout = xPlayer.getLoadout(),
544 | money = xPlayer.getMoney(),
545 | bank_money = xPlayer.getBankMoney(),
546 | black_money = xPlayer.getBlackMoney(),
547 | points = xPlayer.getPoints(),
548 | charId = xPlayer.charId,
549 | group = xPlayer.getGroup()
550 | })
551 | end)
552 |
553 | NEX.RegisterServerCallback('nex:Core:getOtherPlayerData', function(source, cb, target)
554 | local xPlayer = NEX.GetPlayerFromId(target)
555 |
556 | cb({
557 | firstname = xPlayer.firstname,
558 | lastname = xPlayer.lastname,
559 | dob = xPlayer.dob,
560 | dbId = xPlayer.dbId,
561 | identifier = xPlayer.identifier,
562 | accounts = xPlayer.getAccounts(),
563 | inventory = xPlayer.getInventory(),
564 | job = xPlayer.getJob(),
565 | loadout = xPlayer.getLoadout(),
566 | money = xPlayer.getMoney(),
567 | bank_money = xPlayer.getBankMoney(),
568 | black_money = xPlayer.getBlackMoney(),
569 | points = xPlayer.getPoints(),
570 | charId = xPlayer.charId,
571 | group = xPlayer.getGroup()
572 | })
573 | end)
574 |
575 | NEX.RegisterServerCallback('nex:Core:getPlayerNames', function(source, cb, players)
576 | players[source] = nil
577 |
578 | for playerId,v in pairs(players) do
579 | local xPlayer = NEX.GetPlayerFromId(playerId)
580 |
581 | if xPlayer then
582 | players[playerId] = xPlayer.getName()
583 | else
584 | players[playerId] = nil
585 | end
586 | end
587 |
588 | cb(players)
589 | end)
590 |
591 | NEX.RegisterServerCallback('nexus:Core:CheckResourceName', function(source, cb, resourceName)
592 |
593 | if NEX.DevMode then
594 | print("[NexCore] [^1CAUTION^7] Resource " .. resourceName .. " has been started in DEV MODE.")
595 | return cb(true)
596 | else
597 | local xPlayer = NEX.GetPlayerFromId(source)
598 | if xPlayer then
599 | if NEX.Table.Contains(NEX.RegisterResources, resourceName) or resourceName == 'nex_burglary' then
600 | --print("[NexCore] [^2INFO^7] Resource " .. resourceName .. " is allowed for ".. xPlayer.getName() ..".")
601 | cb(true)
602 | else
603 | print("[NexCore] [^1CAUTION^7] Resource " .. resourceName .. " is not allowed for ".. xPlayer.getName() .." [GID: ".. xPlayer.source .."].")
604 | cb(false)
605 | end
606 | end
607 | end
608 | end)
609 |
610 | NEX.StartDBSync()
611 | NEX.StartPayCheck()
612 |
613 |
--------------------------------------------------------------------------------
/server/paycheck.lua:
--------------------------------------------------------------------------------
1 | NEX.StartPayCheck = function()
2 | function payCheck()
3 | local xPlayers = NEX.GetPlayers()
4 |
5 | for i=1, #xPlayers, 1 do
6 | local xPlayer = NEX.GetPlayerFromId(xPlayers[i])
7 | local job = xPlayer.job.grade_name
8 | local salary = xPlayer.job.grade_salary
9 |
10 | if xPlayer.IsPlayerReadyForPlay() then
11 | -- xPlayer.addAccountMoney('points', 1)
12 | -- TriggerClientEvent('DoLongHudText', xPlayer.source, 'Recibiste 1 GL-Points.', 2)
13 | if salary > 0 then
14 | if job == 'unemployed' then -- unemployed
15 | xPlayer.addAccountMoney('bank', salary)
16 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), _U('received_paycheck'), _U('received_help', salary), 'CHAR_BANK_MAZE', 9)
17 | elseif Config.EnableSocietyPayouts then -- possibly a society
18 | TriggerEvent('esx_society:getSociety', xPlayer.job.name, function (society)
19 | if society ~= nil then -- verified society
20 | TriggerEvent('esx_addonaccount:getSharedAccount', society.account, function (account)
21 | if account.money >= salary then -- does the society money to pay its employees?
22 | xPlayer.addAccountMoney('bank', salary)
23 | account.removeMoney(salary)
24 |
25 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), _U('received_paycheck'), _U('received_salary', salary), 'CHAR_BANK_MAZE', 9)
26 | else
27 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), '', _U('company_nomoney'), 'CHAR_BANK_MAZE', 1)
28 | end
29 | end)
30 | else -- not a society
31 | xPlayer.addAccountMoney('bank', salary)
32 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), _U('received_paycheck'), _U('received_salary', salary), 'CHAR_BANK_MAZE', 9)
33 | end
34 | end)
35 | else -- factions
36 |
37 | local isVip = xPlayer.isVip()
38 | local bonus = 0
39 | local iva = 0
40 |
41 | if Config.EnableTax then
42 | iva = salary * Config.Tax
43 | end
44 |
45 | if string.match(job, "off") then
46 | xPlayer.addAccountMoney('bank', salary)
47 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), _U('received_paycheck'), _U('received_salary', salary, 0, 0), 'CHAR_BANK_MAZE', 9)
48 | else
49 | if isVip > 0 then
50 | if Config.VipTiers[isVip] then
51 | bonus = salary * Config.VipTiers[isVip]
52 | else
53 | bonus = Config.VipTierDefault
54 | end
55 | end
56 |
57 | local finalSalary = ((salary + bonus)-iva)
58 | xPlayer.addAccountMoney('bank', finalSalary)
59 |
60 | TriggerClientEvent('nex:Core:showAdvancedNotification', xPlayer.source, _U('bank'), _U('received_paycheck'), _U('received_salary', finalSalary, iva, bonus), 'CHAR_BANK_MAZE', 9)
61 |
62 | if Config.SendTaxToMazeBankSociety then
63 | TriggerEvent('nex:Factions:Accounts:getSharedAccount', 'society_mazebank', function(account)
64 | if account ~= nil then
65 | account.addMoney(iva)
66 | end
67 | end)
68 | end
69 | end
70 | end
71 | end
72 | end
73 | end
74 |
75 | SetTimeout(Config.PaycheckInterval, payCheck)
76 | end
77 |
78 | SetTimeout(Config.PaycheckInterval, payCheck)
79 | end
80 |
--------------------------------------------------------------------------------