├── .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 | ![](https://i.imgur.com/eVlpIQq.png) 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 | ![](https://i.imgur.com/kKxbuBi.png) 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 | ![enter image description here](https://i.imgur.com/U0sACR9.png) 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 | ![](https://i.imgur.com/QwDvwLq.png) 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 | ![enter image description here](https://i.imgur.com/6hAu8Rk.png) 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 |

' + text + '

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