├── ps-mdt
├── ui
│ └── img
│ │ ├── court.png
│ │ ├── male.png
│ │ ├── val1.webp
│ │ ├── val2.webp
│ │ ├── val3.webp
│ │ ├── val4.webp
│ │ ├── 247Back.webp
│ │ ├── female.png
│ │ ├── fleeca.webp
│ │ ├── liquor.webp
│ │ ├── paleto.webp
│ │ ├── ems_badge.png
│ │ ├── not-found.webp
│ │ ├── pacific1.webp
│ │ ├── pacific2.webp
│ │ ├── pacific3.webp
│ │ ├── sasp_badge.png
│ │ ├── 247SmallBack.webp
│ │ ├── profile_pic.png
│ │ ├── warrant_pfp.png
│ │ ├── 247SmallFront.webp
│ │ ├── ems_badge_zonah.png
│ │ └── Screenshot 2022-07-16 093012.png
├── fxmanifest.lua
├── server
│ ├── utils.lua
│ ├── dbm.lua
│ └── main.lua
├── client
│ ├── cl_impound.lua
│ └── main.lua
├── mdt.sql
└── shared
│ └── config.lua
├── README.md
└── LICENSE
/ps-mdt/ui/img/court.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/court.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/male.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/male.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/val1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/val1.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/val2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/val2.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/val3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/val3.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/val4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/val4.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/247Back.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/247Back.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/female.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/female.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/fleeca.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/fleeca.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/liquor.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/liquor.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/paleto.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/paleto.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/ems_badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/ems_badge.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/not-found.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/not-found.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/pacific1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/pacific1.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/pacific2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/pacific2.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/pacific3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/pacific3.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/sasp_badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/sasp_badge.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/247SmallBack.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/247SmallBack.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/profile_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/profile_pic.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/warrant_pfp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/warrant_pfp.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/247SmallFront.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/247SmallFront.webp
--------------------------------------------------------------------------------
/ps-mdt/ui/img/ems_badge_zonah.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/ems_badge_zonah.png
--------------------------------------------------------------------------------
/ps-mdt/ui/img/Screenshot 2022-07-16 093012.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Project-India/pi-mdt/HEAD/ps-mdt/ui/img/Screenshot 2022-07-16 093012.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pi-mdt
2 |
3 | Css Redesign Of ps-mdt
4 |
5 | # Installation
6 |
7 | Just Drag And Drop The ps-mdt Folder
8 |
9 | # Preview
10 |
11 | (https://youtu.be/1S1-H15wSZ4)
12 |
13 | # Credits
14 |
15 | Scorpion.#5940 , Gabbar Singh#5258 , Team Project India , Project Sloth For MDT And EchoRP For Original MDT
16 |
17 | # Support
18 | https://discord.gg/Kd5B3KPnTv
19 |
--------------------------------------------------------------------------------
/ps-mdt/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 | game 'gta5'
3 |
4 | author 'Flawws, Flakey, Idris and the Project Sloth team'
5 | description 'EchoRP MDT Rewrite for QBCore'
6 | version '0.9.9'
7 |
8 | lua54 'yes'
9 |
10 | shared_script 'shared/config.lua'
11 |
12 | server_scripts {
13 | '@oxmysql/lib/MySQL.lua',
14 | 'server/utils.lua',
15 | 'server/dbm.lua',
16 | 'server/main.lua'
17 | }
18 | client_scripts{
19 | 'client/main.lua',
20 | 'client/cl_impound.lua'
21 | }
22 |
23 | ui_page 'ui/dashboard.html'
24 |
25 | files {
26 | 'ui/img/*.png',
27 | 'ui/img/*.webp',
28 | 'ui/dashboard.html',
29 | 'ui/dmv.html',
30 | 'ui/bolos.html',
31 | 'ui/incidents.html',
32 | 'ui/penalcode.html',
33 | 'ui/reports.html',
34 | 'ui/warrants.html',
35 | 'ui/app.js',
36 | 'ui/style.css',
37 | }
--------------------------------------------------------------------------------
/ps-mdt/server/utils.lua:
--------------------------------------------------------------------------------
1 | local QBCore = exports['qb-core']:GetCoreObject()
2 |
3 | function GetPlayerData(source)
4 | local Player = QBCore.Functions.GetPlayer(source)
5 | return Player.PlayerData
6 | end
7 |
8 | function UnpackJob(data)
9 | local job = {
10 | name = data.name,
11 | label = data.label
12 | }
13 | local grade = {
14 | name = data.grade.name,
15 | }
16 |
17 | return job, grade
18 | end
19 |
20 | function PermCheck(src, PlayerData)
21 | local result = true
22 |
23 | if not Config.AllowedJobs[PlayerData.job.name] then
24 | print(("UserId: %s(%d) tried to access the mdt even though they are not authorised (server direct)"):format(GetPlayerName(src), src))
25 | result = false
26 | end
27 |
28 | return result
29 | end
30 |
31 | function ProfPic(gender, profilepic)
32 | if profilepic then return profilepic end;
33 | if gender == "f" then return "img/female.png" end;
34 | return "img/male.png"
35 | end
36 |
37 | function IsJobAllowedToMDT(job)
38 | if Config.PoliceJobs[job] then
39 | return true
40 | elseif Config.AmbulanceJobs[job] then
41 | return true
42 | elseif Config.DojJobs[job] then
43 | return true
44 | else
45 | return false
46 | end
47 | end
48 |
49 | function GetNameFromPlayerData(PlayerData)
50 | return ('%s %s'):format(PlayerData.charinfo.firstname, PlayerData.charinfo.lastname)
51 | end
52 |
--------------------------------------------------------------------------------
/ps-mdt/client/cl_impound.lua:
--------------------------------------------------------------------------------
1 | local currentGarage = 1
2 |
3 | local function doCarDamage(currentVehicle, veh)
4 | local smash = false
5 | local damageOutside = false
6 | local damageOutside2 = false
7 | local engine = veh.engine + 0.0
8 | local body = veh.body + 0.0
9 |
10 | if engine < 200.0 then engine = 200.0 end
11 | if engine > 1000.0 then engine = 950.0 end
12 | if body < 150.0 then body = 150.0 end
13 | if body < 950.0 then smash = true end
14 | if body < 920.0 then damageOutside = true end
15 | if body < 920.0 then damageOutside2 = true end
16 |
17 | Citizen.Wait(100)
18 | SetVehicleEngineHealth(currentVehicle, engine)
19 |
20 | if smash then
21 | SmashVehicleWindow(currentVehicle, 0)
22 | SmashVehicleWindow(currentVehicle, 1)
23 | SmashVehicleWindow(currentVehicle, 2)
24 | SmashVehicleWindow(currentVehicle, 3)
25 | SmashVehicleWindow(currentVehicle, 4)
26 | end
27 |
28 | if damageOutside then
29 | SetVehicleDoorBroken(currentVehicle, 1, true)
30 | SetVehicleDoorBroken(currentVehicle, 6, true)
31 | SetVehicleDoorBroken(currentVehicle, 4, true)
32 | end
33 |
34 | if damageOutside2 then
35 | SetVehicleTyreBurst(currentVehicle, 1, false, 990.0)
36 | SetVehicleTyreBurst(currentVehicle, 2, false, 990.0)
37 | SetVehicleTyreBurst(currentVehicle, 3, false, 990.0)
38 | SetVehicleTyreBurst(currentVehicle, 4, false, 990.0)
39 | end
40 |
41 | if body < 1000 then
42 | SetVehicleBodyHealth(currentVehicle, 985.1)
43 | end
44 | end
45 |
46 | local function TakeOutImpound(vehicle)
47 | local coords = Config.ImpoundLocations[currentGarage]
48 | if coords then
49 | QBCore.Functions.SpawnVehicle(vehicle.vehicle, function(veh)
50 | QBCore.Functions.TriggerCallback('qb-garage:server:GetVehicleProperties', function(properties)
51 | QBCore.Functions.SetVehicleProperties(veh, properties)
52 | SetVehicleNumberPlateText(veh, vehicle.plate)
53 | SetEntityHeading(veh, coords.w)
54 | exports[Config.Fuel]:SetFuel(veh, vehicle.fuel)
55 | doCarDamage(veh, vehicle)
56 | TriggerServerEvent('police:server:TakeOutImpound',vehicle.plate)
57 | TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh))
58 | SetVehicleEngineOn(veh, true, true)
59 | end, vehicle.plate)
60 | end, coords, true)
61 | end
62 | end
63 |
64 | RegisterNetEvent('ps-mdt:client:TakeOutImpound', function(data)
65 | local pos = GetEntityCoords(PlayerPedId())
66 | currentGarage = data.currentSelection
67 | local takeDist = Config.ImpoundLocations[data.currentSelection]
68 | takeDist = vector3(takeDist.x, takeDist.y, takeDist.z)
69 | if #(pos - takeDist) <= 15.0 then
70 | local vehicle = data.vehicle
71 | TakeOutImpound(data)
72 | else
73 | QBCore.Functions.Notify("You are too far away from the impound location!")
74 | end
75 | end)
--------------------------------------------------------------------------------
/ps-mdt/mdt.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS `mdt_data` (
2 | `id` int(11) NOT NULL AUTO_INCREMENT,
3 | `cid` VARCHAR(20) DEFAULT NULL,
4 | `information` MEDIUMTEXT DEFAULT NULL,
5 | `tags` TEXT NOT NULL,
6 | `gallery` TEXT NOT NULL,
7 | `jobtype` VARCHAR(25) DEFAULT 'police',
8 | `pfp` TEXT DEFAULT NULL,
9 | `fingerprint` VARCHAR(50) DEFAULT NULL,
10 | PRIMARY KEY (`cid`),
11 | KEY `id` (`id`)
12 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
13 |
14 | CREATE TABLE IF NOT EXISTS `mdt_bulletin` (
15 | `id` int(11) NOT NULL AUTO_INCREMENT,
16 | `title` TEXT NOT NULL,
17 | `desc` TEXT NOT NULL,
18 | `author` varchar(50) NOT NULL,
19 | `time` varchar(20) NOT NULL,
20 | `jobtype` VARCHAR(25) DEFAULT 'police',
21 | PRIMARY KEY (`id`)
22 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
23 |
24 | CREATE TABLE IF NOT EXISTS `mdt_reports` (
25 | `id` int(11) NOT NULL AUTO_INCREMENT,
26 | `author` varchar(50) DEFAULT NULL,
27 | `title` varchar(255) DEFAULT NULL,
28 | `type` varchar(50) DEFAULT NULL,
29 | `details` text DEFAULT NULL,
30 | `tags` text DEFAULT NULL,
31 | `officersinvolved` text DEFAULT NULL,
32 | `civsinvolved` text DEFAULT NULL,
33 | `gallery` text DEFAULT NULL,
34 | `time` varchar(20) DEFAULT NULL,
35 | `jobtype` varchar(25) DEFAULT 'police',
36 | PRIMARY KEY (`id`)
37 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
38 |
39 | CREATE TABLE IF NOT EXISTS `mdt_bolos` (
40 | `id` int(11) NOT NULL AUTO_INCREMENT,
41 | `author` varchar(50) DEFAULT NULL,
42 | `title` varchar(50) DEFAULT NULL,
43 | `plate` varchar(50) DEFAULT NULL,
44 | `owner` varchar(50) DEFAULT NULL,
45 | `individual` varchar(50) DEFAULT NULL,
46 | `detail` text DEFAULT NULL,
47 | `tags` text DEFAULT NULL,
48 | `gallery` text DEFAULT NULL,
49 | `officersinvolved` text DEFAULT NULL,
50 | `time` varchar(20) DEFAULT NULL,
51 | `jobtype` varchar(25) NOT NULL DEFAULT 'police',
52 | PRIMARY KEY (`id`)
53 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
54 |
55 | CREATE TABLE IF NOT EXISTS `mdt_convictions` (
56 | `id` int(11) NOT NULL AUTO_INCREMENT,
57 | `cid` varchar(50) DEFAULT NULL,
58 | `linkedincident` int(11) NOT NULL DEFAULT 0,
59 | `warrant` varchar(50) DEFAULT NULL,
60 | `guilty` varchar(50) DEFAULT NULL,
61 | `processed` varchar(50) DEFAULT NULL,
62 | `associated` varchar(50) DEFAULT '0',
63 | `charges` text DEFAULT NULL,
64 | `fine` int(11) DEFAULT 0,
65 | `sentence` int(11) DEFAULT 0,
66 | `recfine` int(11) DEFAULT 0,
67 | `recsentence` int(11) DEFAULT 0,
68 | `time` varchar(20) DEFAULT NULL,
69 | PRIMARY KEY (`id`)
70 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
71 |
72 | CREATE TABLE IF NOT EXISTS `mdt_incidents` (
73 | `id` int(11) NOT NULL AUTO_INCREMENT,
74 | `author` varchar(50) NOT NULL DEFAULT '',
75 | `title` varchar(50) NOT NULL DEFAULT '0',
76 | `details` text NOT NULL,
77 | `tags` text NOT NULL,
78 | `officersinvolved` text NOT NULL,
79 | `civsinvolved` text NOT NULL,
80 | `evidence` text NOT NULL,
81 | `time` varchar(20) DEFAULT NULL,
82 | `jobtype` varchar(25) NOT NULL DEFAULT 'police',
83 | PRIMARY KEY (`id`)
84 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
85 |
86 | CREATE TABLE IF NOT EXISTS `mdt_logs` (
87 | `id` int(11) NOT NULL AUTO_INCREMENT,
88 | `text` text NOT NULL,
89 | `time` varchar(20) DEFAULT NULL,
90 | `jobtype` varchar(25) DEFAULT 'police',
91 | PRIMARY KEY (`id`)
92 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
93 |
94 | CREATE TABLE IF NOT EXISTS `mdt_vehicleinfo` (
95 | `id` int(11) NOT NULL AUTO_INCREMENT,
96 | `plate` varchar(50) DEFAULT NULL,
97 | `information` text NOT NULL DEFAULT '',
98 | `stolen` tinyint(1) NOT NULL DEFAULT 0,
99 | `code5` tinyint(1) NOT NULL DEFAULT 0,
100 | `image` text NOT NULL DEFAULT '',
101 | PRIMARY KEY (`id`)
102 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
103 |
104 | CREATE TABLE IF NOT EXISTS `mdt_impound` (
105 | `id` int(11) NOT NULL AUTO_INCREMENT,
106 | `vehicleid` int(11) NOT NULL,
107 | `linkedreport` int(11) NOT NULL,
108 | `fee` int(11) DEFAULT NULL,
109 | `time` varchar(255) NOT NULL,
110 | PRIMARY KEY (`id`)
111 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--------------------------------------------------------------------------------
/ps-mdt/server/dbm.lua:
--------------------------------------------------------------------------------
1 | local QBCore = exports['qb-core']:GetCoreObject()
2 |
3 | -- Get CitizenIDs from Player License
4 | function GetCitizenID(license)
5 | local result = MySQL.query.await("SELECT citizenid FROM players WHERE license = ?", {license,})
6 | if result ~= nil then
7 | return result
8 | else
9 | print("Cannot find a CitizenID for License: "..license)
10 | return nil
11 | end
12 | end
13 |
14 | -- (Start) Opening the MDT and sending data
15 | function AddLog(text)
16 | --print(text)
17 | return MySQL.insert.await('INSERT INTO `mdt_logs` (`text`, `time`) VALUES (?,?)', {text, os.time() * 1000})
18 | -- return exports.oxmysql:execute('INSERT INTO `mdt_logs` (`text`, `time`) VALUES (:text, :time)', { text = text, time = os.time() * 1000 })
19 | end
20 |
21 | function GetNameFromId(cid)
22 | -- Should be a scalar?
23 | local result = MySQL.scalar.await('SELECT charinfo FROM players WHERE citizenid = @citizenid', { ['@citizenid'] = cid })
24 | if result ~= nil then
25 | local charinfo = json.decode(result)
26 | local fullname = charinfo['firstname']..' '..charinfo['lastname']
27 | return fullname
28 | else
29 | --print('Player does not exist')
30 | return nil
31 | end
32 | -- return exports.oxmysql:executeSync('SELECT firstname, lastname FROM `users` WHERE id = :id LIMIT 1', { id = cid })
33 | end
34 |
35 | -- idk what this is used for either
36 | function GetPersonInformation(cid, jobtype)
37 | local result = MySQL.query.await('SELECT information, tags, gallery, pfp, fingerprint FROM mdt_data WHERE cid = ? and jobtype = ?', { cid, jobtype})
38 | return result[1]
39 | -- return exports.oxmysql:executeSync('SELECT information, tags, gallery FROM mdt WHERE cid= ? and type = ?', { cid, jobtype })
40 | end
41 |
42 | function GetPfpFingerPrintInformation(cid)
43 | local result = MySQL.query.await('SELECT pfp, fingerprint FROM mdt_data WHERE cid = ?', { cid })
44 | return result[1]
45 | end
46 |
47 | -- idk but I guess sure?
48 | function GetIncidentName(id)
49 | -- Should also be a scalar
50 | return MySQL.query.await('SELECT title FROM `mdt_incidents` WHERE id = :id LIMIT 1', { id = id })
51 | -- return exports.oxmysql:executeSync('SELECT title FROM `mdt_incidents` WHERE id = :id LIMIT 1', { id = id })
52 | end
53 |
54 | function GetConvictions(cids)
55 | return MySQL.query.await('SELECT * FROM `mdt_convictions` WHERE `cid` IN(?)', { cids })
56 | -- return exports.oxmysql:executeSync('SELECT * FROM `mdt_convictions` WHERE `cid` IN(?)', { cids })
57 | end
58 |
59 | function GetLicenseInfo(cid)
60 | local result = MySQL.query.await('SELECT * FROM `licenses` WHERE `cid` = ?', { cid })
61 | return result
62 | -- return exports.oxmysql:executeSync('SELECT * FROM `licenses` WHERE `cid`=:cid', { cid = cid })
63 | end
64 |
65 | function CreateUser(cid, tableName)
66 | AddLog("A user was created with the CID: "..cid)
67 | -- return exports.oxmysql:insert("INSERT INTO `"..dbname.."` (cid) VALUES (:cid)", { cid = cid })
68 | return MySQL.insert.await("INSERT INTO `"..tableName.."` (cid) VALUES (:cid)", { cid = cid })
69 | end
70 |
71 | function GetPlayerVehicles(cid, cb)
72 | return MySQL.query.await('SELECT id, plate, vehicle FROM player_vehicles WHERE citizenid=:cid', { cid = cid })
73 | end
74 |
75 | function GetBulletins(JobType)
76 | return MySQL.query.await('SELECT * FROM `mdt_bulletin` WHERE `jobtype` = ? LIMIT 10', { JobType })
77 | -- return exports.oxmysql:executeSync('SELECT * FROM `mdt_bulletin` WHERE `type`= ? LIMIT 10', { JobType })
78 | end
79 |
80 | function GetPlayerProperties(cid, cb)
81 | local result = MySQL.query.await('SELECT houselocations.label, houselocations.coords FROM player_houses INNER JOIN houselocations ON player_houses.house = houselocations.name where player_houses.citizenid = ?', {cid})
82 | return result
83 | end
84 |
85 | function GetPlayerDataById(id)
86 | local Player = QBCore.Functions.GetPlayerByCitizenId(id)
87 | if Player ~= nil then
88 | local response = {citizenid = Player.PlayerData.citizenid, charinfo = Player.PlayerData.charinfo, metadata = Player.PlayerData.metadata, job = Player.PlayerData.job}
89 | return response
90 | else
91 | return MySQL.single.await('SELECT citizenid, charinfo, job, metadata FROM players WHERE citizenid = ? LIMIT 1', { id })
92 | end
93 |
94 | -- return exports.oxmysql:executeSync('SELECT citizenid, charinfo, job FROM players WHERE citizenid = ? LIMIT 1', { id })
95 | end
96 |
97 | -- Probs also best not to use
98 | --[[ function GetImpoundStatus(vehicleid, cb)
99 | cb( #(exports.oxmysql:executeSync('SELECT id FROM `impound` WHERE `vehicleid`=:vehicleid', {['vehicleid'] = vehicleid })) > 0 )
100 | end ]]
101 |
102 | function GetBoloStatus(plate)
103 | local result = MySQL.scalar.await('SELECT id FROM `mdt_bolos` WHERE LOWER(`plate`)=:plate', { plate = string.lower(plate)})
104 | return result
105 | -- return exports.oxmysql:scalarSync('SELECT id FROM `mdt_bolos` WHERE LOWER(`plate`)=:plate', { plate = string.lower(plate)})
106 | end
107 |
108 | function GetOwnerName(cid)
109 | local result = MySQL.scalar.await('SELECT charinfo FROM `players` WHERE LOWER(`citizenid`) = ? LIMIT 1', {cid})
110 | return result
111 | -- return exports.oxmysql:scalarSync('SELECT charinfo FROM `players` WHERE id=:cid LIMIT 1', { cid = cid})
112 | end
113 |
114 | function GetVehicleInformation(plate, cb)
115 | local result = MySQL.query.await('SELECT id, information FROM `mdt_vehicleinfo` WHERE plate=:plate', { plate = plate})
116 | cb(result)
117 | end
118 |
119 | function GetPlayerLicenses(identifier)
120 | local response = false
121 | local Player = QBCore.Functions.GetPlayerByCitizenId(identifier)
122 | if Player ~= nil then
123 | return Player.PlayerData.metadata.licences
124 | else
125 | local result = MySQL.scalar.await('SELECT metadata FROM players WHERE citizenid = @identifier', {['@identifier'] = identifier})
126 | if result ~= nil then
127 | local metadata = json.decode(result)
128 | if metadata["licences"] ~= nil and metadata["licences"] then
129 | return metadata["licences"]
130 | else
131 | return {
132 | ['driver'] = false,
133 | ['business'] = false,
134 | ['weapon'] = false,
135 | ['pilot'] = false
136 | }
137 | end
138 | end
139 | end
140 | end
141 |
142 | function ManageLicense(identifier, type, status)
143 | local Player = QBCore.Functions.GetPlayerByCitizenId(identifier)
144 | local licenseStatus = nil
145 | if status == "give" then licenseStatus = true elseif status == "revoke" then licenseStatus = false end
146 | if Player ~= nil then
147 | local licences = Player.PlayerData.metadata["licences"]
148 | local newLicenses = {}
149 | for k, v in pairs(licences) do
150 | local status = v
151 | if k == type then
152 | status = licenseStatus
153 | end
154 | newLicenses[k] = status
155 | end
156 | Player.Functions.SetMetaData("licences", newLicenses)
157 | else
158 | local licenseType = '$.licences.'..type
159 | local result = MySQL.query.await('UPDATE `players` SET `metadata` = JSON_REPLACE(`metadata`, ?, ?) WHERE `citizenid` = ?', {licenseType, licenseStatus, identifier}) --seems to not work on older MYSQL versions, think about alternative
160 | end
161 | end
162 |
163 | function ManageLicenses(identifier, incomingLicenses)
164 | local Player = QBCore.Functions.GetPlayerByCitizenId(identifier)
165 | if Player ~= nil then
166 | Player.Functions.SetMetaData("licences", incomingLicenses)
167 |
168 | else
169 | local result = MySQL.scalar.await('SELECT metadata FROM players WHERE citizenid = @identifier', {['@identifier'] = identifier})
170 | result = json.decode(result)
171 |
172 | result.licences = result.licences or {
173 | ['driver'] = true,
174 | ['business'] = false,
175 | ['weapon'] = false,
176 | ['pilot'] = false
177 | }
178 |
179 | for k, _ in pairs(incomingLicenses) do
180 | result.licences[k] = incomingLicenses[k]
181 | end
182 | MySQL.query.await('UPDATE `players` SET `metadata` = @metadata WHERE citizenid = @citizenid', {['@metadata'] = json.encode(result), ['@citizenid'] = identifier})
183 | end
184 | end
185 |
--------------------------------------------------------------------------------
/ps-mdt/client/main.lua:
--------------------------------------------------------------------------------
1 | QBCore = exports['qb-core']:GetCoreObject()
2 | local PlayerData = {}
3 | local CurrentCops = 0
4 | local isOpen = false
5 | local callSign = ""
6 | local tablet = 0
7 | local tabletDict = "amb@code_human_in_bus_passenger_idles@female@tablet@base"
8 | local tabletAnim = "base"
9 | local tabletProp = `prop_cs_tablet`
10 | local tabletBone = 60309
11 | local tabletOffset = vector3(0.03, 0.002, -0.0)
12 | local tabletRot = vector3(10.0, 160.0, 0.0)
13 |
14 | -- Events from qbcore
15 | RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
16 | PlayerData = QBCore.Functions.GetPlayerData()
17 | callSign = PlayerData.metadata.callsign
18 | end)
19 |
20 | RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
21 | TriggerServerEvent("ps-mdt:server:OnPlayerUnload")
22 | PlayerData = {}
23 | end)
24 |
25 | RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo)
26 | PlayerData.job = JobInfo
27 | end)
28 |
29 | RegisterNetEvent('QBCore:Client:OnGangUpdate', function(GangInfo)
30 | PlayerData.gang = GangInfo
31 | end)
32 |
33 | RegisterNetEvent("QBCore:Client:SetDuty", function(job, state)
34 | if AllowedJob(job) then
35 | TriggerServerEvent("ps-mdt:server:ToggleDuty")
36 | end
37 | end)
38 |
39 | RegisterNetEvent('police:SetCopCount', function(amount)
40 | CurrentCops = amount
41 | end)
42 |
43 | RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
44 | PlayerData = val
45 | end)
46 |
47 | AddEventHandler('onResourceStart', function(resourceName)
48 | if GetCurrentResourceName() ~= resourceName then return end
49 | Wait(150)
50 | PlayerData = QBCore.Functions.GetPlayerData()
51 | callSign = PlayerData.metadata.callsign
52 | end)
53 |
54 | --====================================================================================
55 | ------------------------------------------
56 | -- Functions --
57 | ------------------------------------------
58 | --====================================================================================\
59 |
60 | RegisterKeyMapping('mdt', 'Open Police MDT', 'keyboard', 'k')
61 |
62 | RegisterCommand('mdt', function()
63 | local plyPed = PlayerPedId()
64 | PlayerData = QBCore.Functions.GetPlayerData()
65 | if not PlayerData.metadata["isdead"] and not PlayerData.metadata["inlaststand"] and not PlayerData.metadata["ishandcuffed"] and not IsPauseMenuActive() then
66 | if GetJobType(PlayerData.job.name) ~= nil then
67 | TriggerServerEvent('mdt:server:openMDT')
68 | end
69 | else
70 | QBCore.Functions.Notify("Can't do that!", "error")
71 | end
72 | end, false)
73 |
74 | Citizen.CreateThread(function()
75 | TriggerEvent('chat:addSuggestion', '/mdt', 'Open the emergency services MDT', {})
76 | end)
77 |
78 | local function doAnimation()
79 | if not isOpen then return end
80 | -- Animation
81 | RequestAnimDict(tabletDict)
82 | while not HasAnimDictLoaded(tabletDict) do Citizen.Wait(100) end
83 | -- Model
84 | RequestModel(tabletProp)
85 | while not HasModelLoaded(tabletProp) do Citizen.Wait(100) end
86 |
87 | local plyPed = PlayerPedId()
88 | local tabletObj = CreateObject(tabletProp, 0.0, 0.0, 0.0, true, true, false)
89 | local tabletBoneIndex = GetPedBoneIndex(plyPed, tabletBone)
90 |
91 | AttachEntityToEntity(tabletObj, plyPed, tabletBoneIndex, tabletOffset.x, tabletOffset.y, tabletOffset.z, tabletRot.x, tabletRot.y, tabletRot.z, true, false, false, false, 2, true)
92 | SetModelAsNoLongerNeeded(tabletProp)
93 |
94 | CreateThread(function()
95 | while isOpen do
96 | Wait(0)
97 | if not IsEntityPlayingAnim(plyPed, tabletDict, tabletAnim, 3) then
98 | TaskPlayAnim(plyPed, tabletDict, tabletAnim, 3.0, 3.0, -1, 49, 0, 0, 0, 0)
99 | end
100 | end
101 |
102 |
103 | ClearPedSecondaryTask(plyPed)
104 | Citizen.Wait(250)
105 | DetachEntity(tabletObj, true, false)
106 | DeleteEntity(tabletObj)
107 | end)
108 | end
109 |
110 |
111 | local function CurrentDuty(duty)
112 | if duty == 1 then
113 | return "10-41"
114 | end
115 | return "10-42"
116 | end
117 |
118 | local function EnableGUI(enable)
119 | SetNuiFocus(enable, enable)
120 | SendNUIMessage({ type = "show", enable = enable, job = PlayerData.job.name, rosterLink = Config.RosterLink[PlayerData.job.name] })
121 | isOpen = enable
122 | doAnimation()
123 | end
124 |
125 | local function RefreshGUI()
126 | SetNuiFocus(false, false)
127 | SendNUIMessage({ type = "show", enable = false, job = PlayerData.job.name, rosterLink = Config.RosterLink[PlayerData.job.name] })
128 | isOpen = false
129 | end
130 |
131 | --// Non local function so above EHs can utilise
132 | function AllowedJob(job)
133 | for key, _ in pairs(Config.AllowedJobs) do
134 | if key == job then
135 | return true
136 | end
137 | end
138 | --// Return false if current job is not in allowed list
139 | return false
140 | end
141 |
142 |
143 | --====================================================================================
144 | ------------------------------------------
145 | -- MAIN PAGE --
146 | ------------------------------------------
147 | --====================================================================================
148 |
149 |
150 | RegisterCommand("restartmdt", function(source, args, rawCommand)
151 | RefreshGUI()
152 | end, false)
153 |
154 | RegisterNUICallback("deleteBulletin", function(data, cb)
155 | local id = data.id
156 | TriggerServerEvent('mdt:server:deleteBulletin', id, data.title)
157 | cb(true)
158 | end)
159 |
160 | RegisterNUICallback("newBulletin", function(data, cb)
161 | local title = data.title
162 | local info = data.info
163 | local time = data.time
164 | TriggerServerEvent('mdt:server:NewBulletin', title, info, time)
165 | cb(true)
166 | end)
167 |
168 | RegisterNUICallback('escape', function(data, cb)
169 | EnableGUI(false)
170 | cb(true)
171 | end)
172 |
173 | RegisterNetEvent('mdt:client:dashboardbulletin', function(sentData)
174 | SendNUIMessage({ type = "bulletin", data = sentData })
175 | end)
176 |
177 | RegisterNetEvent('mdt:client:dashboardWarrants', function()
178 | QBCore.Functions.TriggerCallback("mdt:server:getWarrants", function(data)
179 | if data then
180 | SendNUIMessage({ type = "warrants", data = data })
181 | end
182 | end)
183 | -- SendNUIMessage({ type = "warrants",})
184 | end)
185 |
186 | RegisterNUICallback("getAllDashboardData", function(data, cb)
187 | TriggerEvent("mdt:client:dashboardWarrants")
188 | cb(true)
189 | end)
190 |
191 |
192 | RegisterNetEvent('mdt:client:dashboardReports', function(sentData)
193 | SendNUIMessage({ type = "reports", data = sentData })
194 | end)
195 |
196 | RegisterNetEvent('mdt:client:dashboardCalls', function(sentData)
197 | SendNUIMessage({ type = "calls", data = sentData })
198 | end)
199 |
200 | RegisterNetEvent('mdt:client:newBulletin', function(ignoreId, sentData, job)
201 | if ignoreId == GetPlayerServerId(PlayerId()) then return end;
202 | if AllowedJob(PlayerData.job.name) then
203 | SendNUIMessage({ type = "newBulletin", data = sentData })
204 | end
205 | end)
206 |
207 | RegisterNetEvent('mdt:client:deleteBulletin', function(ignoreId, sentData, job)
208 | if ignoreId == GetPlayerServerId(PlayerId()) then return end;
209 | if AllowedJob(PlayerData.job.name) then
210 | SendNUIMessage({ type = "deleteBulletin", data = sentData })
211 | end
212 | end)
213 |
214 | RegisterNetEvent('mdt:client:open', function(bulletin, activeUnits, calls, cid)
215 | EnableGUI(true)
216 | local x, y, z = table.unpack(GetEntityCoords(PlayerPedId()))
217 |
218 | local currentStreetHash, intersectStreetHash = GetStreetNameAtCoord(x, y, z)
219 | local currentStreetName = GetStreetNameFromHashKey(currentStreetHash)
220 | local intersectStreetName = GetStreetNameFromHashKey(intersectStreetHash)
221 | local zone = tostring(GetNameOfZone(x, y, z))
222 | local area = GetLabelText(zone)
223 | local playerStreetsLocation = area
224 |
225 | if not zone then zone = "UNKNOWN" end;
226 |
227 | if intersectStreetName ~= nil and intersectStreetName ~= "" then playerStreetsLocation = currentStreetName .. ", " .. intersectStreetName .. ", " .. area
228 | elseif currentStreetName ~= nil and currentStreetName ~= "" then playerStreetsLocation = currentStreetName .. ", " .. area
229 | else playerStreetsLocation = area end
230 |
231 | -- local grade = PlayerData.job.grade.name
232 |
233 | SendNUIMessage({ type = "data", activeUnits = activeUnits, citizenid = cid, ondutyonly = Config.OnlyShowOnDuty, name = "Welcome, " ..PlayerData.job.grade.name..' '..PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), location = playerStreetsLocation, fullname = PlayerData.charinfo.firstname..' '..PlayerData.charinfo.lastname, bulletin = bulletin })
234 | SendNUIMessage({ type = "calls", data = calls })
235 | TriggerEvent("mdt:client:dashboardWarrants")
236 | end)
237 |
238 | RegisterNetEvent('mdt:client:exitMDT', function()
239 | EnableGUI(false)
240 | end)
241 |
242 | --====================================================================================
243 | ------------------------------------------
244 | -- PROFILE PAGE --
245 | ------------------------------------------
246 | --====================================================================================
247 |
248 | RegisterNUICallback("searchProfiles", function(data, cb)
249 | local p = promise.new()
250 |
251 | QBCore.Functions.TriggerCallback('mdt:server:SearchProfile', function(result)
252 | p:resolve(result)
253 | end, data.name)
254 |
255 | local data = Citizen.Await(p)
256 |
257 | cb(data)
258 | end)
259 |
260 |
261 | RegisterNetEvent('mdt:client:searchProfile', function(sentData, isLimited)
262 | SendNUIMessage({ type = "profiles", data = sentData, isLimited = isLimited })
263 | end)
264 |
265 | RegisterNUICallback("saveProfile", function(data, cb)
266 | local profilepic = data.pfp
267 | local information = data.description
268 | local cid = data.id
269 | local fName = data.fName
270 | local sName = data.sName
271 | local tags = data.tags
272 | local gallery = data.gallery
273 | local fingerprint = data.fingerprint
274 | local licenses = data.licenses
275 |
276 | TriggerServerEvent("mdt:server:saveProfile", profilepic, information, cid, fName, sName, tags, gallery, fingerprint, licenses)
277 | cb(true)
278 | end)
279 |
280 | RegisterNUICallback("getProfileData", function(data, cb)
281 | local id = data.id
282 | local p = nil
283 | local getProfileDataPromise = function(data)
284 | if p then return end
285 | p = promise.new()
286 | QBCore.Functions.TriggerCallback('mdt:server:GetProfileData', function(result)
287 | p:resolve(result)
288 | end, data)
289 | return Citizen.Await(p)
290 | end
291 | local pP = nil
292 | local result = getProfileDataPromise(id)
293 |
294 | --[[ local getProfileProperties = function(data)
295 | if pP then return end
296 | pP = promise.new()
297 | QBCore.Functions.TriggerCallback('qb-phone:server:MeosGetPlayerHouses', function(result)
298 | pP:resolve(result)
299 | end, data)
300 | return Citizen.Await(pP)
301 | end
302 | local propertiesResult = getProfileProperties(id)
303 | result.properties = propertiesResult
304 | ]]
305 | local vehicles=result.vehicles
306 | for i=1,#vehicles do
307 | local vehicle=result.vehicles[i]
308 | result.vehicles[i]['model'] = GetLabelText(GetDisplayNameFromVehicleModel(vehicle['vehicle']))
309 | end
310 | p = nil
311 | return cb(result)
312 | end)
313 |
314 | RegisterNUICallback("newTag", function(data, cb)
315 | if data.id ~= "" and data.tag ~= "" then
316 | TriggerServerEvent('mdt:server:newTag', data.id, data.tag)
317 | end
318 | cb(true)
319 | end)
320 |
321 | RegisterNUICallback("removeProfileTag", function(data, cb)
322 | local cid = data.cid
323 | local tagtext = data.text
324 | TriggerServerEvent('mdt:server:removeProfileTag', cid, tagtext)
325 | cb(true)
326 | end)
327 |
328 | RegisterNUICallback("updateLicence", function(data, cb)
329 | local type = data.type
330 | local status = data.status
331 | local cid = data.cid
332 | TriggerServerEvent('mdt:server:updateLicense', cid, type, status)
333 | cb(true)
334 | end)
335 |
336 | RegisterNUICallback("searchIncidents", function(data, cb)
337 | local incident = data.incident
338 | TriggerServerEvent('mdt:server:searchIncidents', incident)
339 | cb(true)
340 | end)
341 |
342 | RegisterNUICallback("getIncidentData", function(data, cb)
343 | local id = data.id
344 | TriggerServerEvent('mdt:server:getIncidentData', id)
345 | cb(true)
346 | end)
347 |
348 | RegisterNUICallback("incidentSearchPerson", function(data, cb)
349 | local name = data.name
350 | TriggerServerEvent('mdt:server:incidentSearchPerson', name )
351 | cb(true)
352 | end)
353 |
354 | RegisterNetEvent('mdt:client:getProfileData', function(sentData, isLimited)
355 | if not isLimited then
356 | local vehicles = sentData['vehicles']
357 | for i=1, #vehicles do
358 | sentData['vehicles'][i]['plate'] = string.upper(sentData['vehicles'][i]['plate'])
359 | local tempModel = vehicles[i]['model']
360 | if tempModel and tempModel ~= "Unknown" then
361 | local DisplayNameModel = GetDisplayNameFromVehicleModel(tempModel)
362 | local LabelText = GetLabelText(DisplayNameModel)
363 | if LabelText == "NULL" then LabelText = DisplayNameModel end
364 | sentData['vehicles'][i]['model'] = LabelText
365 | end
366 | end
367 | end
368 | SendNUIMessage({ type = "profileData", data = sentData, isLimited = isLimited })
369 | end)
370 |
371 | RegisterNetEvent('mdt:client:getIncidents', function(sentData)
372 | SendNUIMessage({ type = "incidents", data = sentData })
373 | end)
374 |
375 | RegisterNetEvent('mdt:client:getIncidentData', function(sentData, sentConvictions)
376 | SendNUIMessage({ type = "incidentData", data = sentData, convictions = sentConvictions })
377 | end)
378 |
379 | RegisterNetEvent('mdt:client:incidentSearchPerson', function(sentData)
380 | SendNUIMessage({ type = "incidentSearchPerson", data = sentData })
381 | end)
382 |
383 |
384 | RegisterNUICallback('SetHouseLocation', function(data, cb)
385 | local coords = {}
386 | for word in data.coord[1]:gmatch('[^,%s]+') do
387 | coords[#coords+1] = tonumber(word)
388 | end
389 | SetNewWaypoint(coords[1], coords[2])
390 | QBCore.Functions.Notify('GPS has been set!', 'success')
391 | end)
392 |
393 | --====================================================================================
394 | ------------------------------------------
395 | -- BOLO PAGE --
396 | ------------------------------------------
397 | --====================================================================================
398 |
399 | RegisterNUICallback("searchBolos", function(data, cb)
400 | local searchVal = data.searchVal
401 | TriggerServerEvent('mdt:server:searchBolos', searchVal)
402 | cb(true)
403 | end)
404 |
405 | RegisterNUICallback("getAllBolos", function(data, cb)
406 | TriggerServerEvent('mdt:server:getAllBolos')
407 | cb(true)
408 | end)
409 |
410 | RegisterNUICallback("getAllIncidents", function(data, cb)
411 | TriggerServerEvent('mdt:server:getAllIncidents')
412 | cb(true)
413 | end)
414 |
415 | RegisterNUICallback("getBoloData", function(data, cb)
416 | local id = data.id
417 | TriggerServerEvent('mdt:server:getBoloData', id)
418 | cb(true)
419 | end)
420 |
421 | RegisterNUICallback("newBolo", function(data, cb)
422 | local existing = data.existing
423 | local id = data.id
424 | local title = data.title
425 | local plate = data.plate
426 | local owner = data.owner
427 | local individual = data.individual
428 | local detail = data.detail
429 | local tags = data.tags
430 | local gallery = data.gallery
431 | local officers = data.officers
432 | local time = data.time
433 | TriggerServerEvent('mdt:server:newBolo', existing, id, title, plate, owner, individual, detail, tags, gallery, officers, time)
434 | cb(true)
435 | end)
436 |
437 | RegisterNUICallback("deleteBolo", function(data, cb)
438 | local id = data.id
439 | TriggerServerEvent('mdt:server:deleteBolo', id)
440 | cb(true)
441 | end)
442 |
443 | RegisterNUICallback("deleteICU", function(data, cb)
444 | local id = data.id
445 | TriggerServerEvent('mdt:server:deleteICU', id)
446 | cb(true)
447 | end)
448 |
449 | RegisterNetEvent('mdt:client:getBolos', function(sentData)
450 | SendNUIMessage({ type = "bolos", data = sentData })
451 | end)
452 |
453 | RegisterNetEvent('mdt:client:getAllIncidents', function(sentData)
454 | SendNUIMessage({ type = "incidents", data = sentData })
455 | end)
456 |
457 | RegisterNetEvent('mdt:client:getAllBolos', function(sentData)
458 | SendNUIMessage({ type = "bolos", data = sentData })
459 | end)
460 |
461 | RegisterNetEvent('mdt:client:getBoloData', function(sentData)
462 | SendNUIMessage({ type = "boloData", data = sentData })
463 | end)
464 |
465 | RegisterNetEvent('mdt:client:boloComplete', function(sentData)
466 | SendNUIMessage({ type = "boloComplete", data = sentData })
467 | end)
468 |
469 | --====================================================================================
470 | ------------------------------------------
471 | -- REPORTS PAGE --
472 | ------------------------------------------
473 | --====================================================================================
474 |
475 | RegisterNUICallback("getAllReports", function(data, cb)
476 | TriggerServerEvent('mdt:server:getAllReports')
477 | cb(true)
478 | end)
479 |
480 | RegisterNUICallback("getReportData", function(data, cb)
481 | local id = data.id
482 | TriggerServerEvent('mdt:server:getReportData', id)
483 | cb(true)
484 | end)
485 |
486 | RegisterNUICallback("searchReports", function(data, cb)
487 | local name = data.name
488 | TriggerServerEvent('mdt:server:searchReports', name)
489 | cb(true)
490 | end)
491 |
492 | RegisterNUICallback("newReport", function(data, cb)
493 | local existing = data.existing
494 | local id = data.id
495 | local title = data.title
496 | local reporttype = data.type
497 | local details = data.details
498 | local tags = data.tags
499 | local gallery = data.gallery
500 | local officers = data.officers
501 | local civilians = data.civilians
502 | local time = data.time
503 |
504 | TriggerServerEvent('mdt:server:newReport', existing, id, title, reporttype, details, tags, gallery, officers, civilians, time)
505 | cb(true)
506 | end)
507 |
508 | RegisterNetEvent('mdt:client:getAllReports', function(sentData)
509 | SendNUIMessage({ type = "reports", data = sentData })
510 | end)
511 |
512 | RegisterNetEvent('mdt:client:getReportData', function(sentData)
513 | SendNUIMessage({ type = "reportData", data = sentData })
514 | end)
515 |
516 | RegisterNetEvent('mdt:client:reportComplete', function(sentData)
517 | SendNUIMessage({ type = "reportComplete", data = sentData })
518 | end)
519 |
520 | --====================================================================================
521 | ------------------------------------------
522 | -- DMV PAGE --
523 | ------------------------------------------
524 | --====================================================================================
525 | RegisterNUICallback("searchVehicles", function(data, cb)
526 |
527 | local p = promise.new()
528 |
529 | QBCore.Functions.TriggerCallback('mdt:server:SearchVehicles', function(result)
530 | p:resolve(result)
531 | end, data.name)
532 |
533 | local result = Citizen.Await(p)
534 | for i=1, #result do
535 | local vehicle = result[i]
536 | local mods = json.decode(result[i].mods)
537 | result[i]['plate'] = string.upper(result[i]['plate'])
538 | result[i]['color'] = Config.ColorInformation[mods['color1']]
539 | result[i]['colorName'] = Config.ColorNames[mods['color1']]
540 | result[i]['model'] = GetLabelText(GetDisplayNameFromVehicleModel(vehicle['vehicle']))
541 | end
542 | cb(result)
543 |
544 | end)
545 |
546 | RegisterNUICallback("getVehicleData", function(data, cb)
547 | local plate = data.plate
548 | TriggerServerEvent('mdt:server:getVehicleData', plate)
549 | cb(true)
550 | end)
551 |
552 | RegisterNUICallback("saveVehicleInfo", function(data, cb)
553 | local dbid = data.dbid
554 | local plate = data.plate
555 | local imageurl = data.imageurl
556 | local notes = data.notes
557 | local stolen = data.stolen
558 | local code5 = data.code5
559 | local impound = data.impound
560 | local JobType = GetJobType(PlayerData.job.name)
561 | if JobType == 'police' and impound.impoundChanged == true then
562 | if impound.impoundActive then
563 | local found = 0
564 | local plate = string.upper(string.gsub(data['plate'], "^%s*(.-)%s*$", "%1"))
565 | local vehicles = GetGamePool('CVehicle')
566 |
567 | for k,v in pairs(vehicles) do
568 | local plt = string.upper(string.gsub(GetVehicleNumberPlateText(v), "^%s*(.-)%s*$", "%1"))
569 | if plt == plate then
570 | local dist = #(GetEntityCoords(PlayerPedId()) - GetEntityCoords(v))
571 | if dist < 5.0 then
572 | found = VehToNet(v)
573 | SendNUIMessage({ type = "greenImpound" })
574 | TriggerServerEvent('mdt:server:saveVehicleInfo', dbid, plate, imageurl, notes, stolen, code5, impound)
575 | end
576 | break
577 | end
578 | end
579 |
580 | if found == 0 then
581 | QBCore.Functions.Notify('Vehicle not found!', 'error')
582 | SendNUIMessage({ type = "redImpound" })
583 | end
584 | else
585 | local ped = PlayerPedId()
586 | local playerPos = GetEntityCoords(ped)
587 | for k, v in pairs(Config.ImpoundLocations) do
588 | if (#(playerPos - vector3(v.x, v.y, v.z)) < 20.0) then
589 | impound.CurrentSelection = k
590 | TriggerServerEvent('mdt:server:saveVehicleInfo', dbid, plate, imageurl, notes, stolen, code5, impound)
591 | break
592 | end
593 | end
594 | end
595 | else
596 | TriggerServerEvent('mdt:server:saveVehicleInfo', dbid, plate, imageurl, notes, stolen, code5, impound)
597 | end
598 | cb(true)
599 | end)
600 |
601 | RegisterNUICallback("getAllLogs", function(data, cb)
602 | TriggerServerEvent('mdt:server:getAllLogs')
603 | cb(true)
604 | end)
605 |
606 | RegisterNUICallback("getPenalCode", function(data, cb)
607 | TriggerServerEvent('mdt:server:getPenalCode')
608 | cb(true)
609 | end)
610 |
611 | RegisterNUICallback("toggleDuty", function(data, cb)
612 | TriggerServerEvent('QBCore:ToggleDuty')
613 | cb(true)
614 | end)
615 |
616 | RegisterNUICallback("setCallsign", function(data, cb)
617 | TriggerServerEvent('mdt:server:setCallsign', data.cid, data.newcallsign)
618 | cb(true)
619 | end)
620 |
621 | RegisterNUICallback("setRadio", function(data, cb)
622 | TriggerServerEvent('mdt:server:setRadio', data.cid, data.newradio)
623 | cb(true)
624 | end)
625 |
626 | RegisterNUICallback("saveIncident", function(data, cb)
627 | TriggerServerEvent('mdt:server:saveIncident', data.ID, data.title, data.information, data.tags, data.officers, data.civilians, data.evidence, data.associated, data.time)
628 | cb(true)
629 | end)
630 |
631 | RegisterNUICallback("removeIncidentCriminal", function(data, cb)
632 | TriggerServerEvent('mdt:server:removeIncidentCriminal', data.cid, data.incidentId)
633 | cb(true)
634 | end)
635 |
636 | RegisterNetEvent('mdt:client:getVehicleData', function(sentData)
637 | if sentData and sentData[1] then
638 | local vehicle = sentData[1]
639 | local vehData = json.decode(vehicle['vehicle'])
640 | vehicle['color'] = Config.ColorInformation[vehicle['color1']]
641 | vehicle['colorName'] = Config.ColorNames[vehicle['color1']]
642 | vehicle['model'] = GetLabelText(GetDisplayNameFromVehicleModel(vehicle['vehicle']))
643 | vehicle['class'] = Config.ClassList[GetVehicleClassFromName(vehicle['vehicle'])]
644 | vehicle['vehicle'] = nil
645 | SendNUIMessage({ type = "getVehicleData", data = vehicle })
646 | end
647 | end)
648 |
649 | RegisterNetEvent('mdt:client:updateVehicleDbId', function(sentData)
650 | SendNUIMessage({ type = "updateVehicleDbId", data = tonumber(sentData) })
651 | end)
652 |
653 | RegisterNetEvent('mdt:client:getAllLogs', function(sentData)
654 | SendNUIMessage({ type = "getAllLogs", data = sentData })
655 | end)
656 |
657 | RegisterNetEvent('mdt:client:getPenalCode', function(titles, penalcode)
658 | SendNUIMessage({ type = "getPenalCode", titles = titles, penalcode = penalcode })
659 | end)
660 |
661 | RegisterNetEvent('mdt:client:setRadio', function(radio)
662 | if type(tonumber(radio)) == "number" then
663 | exports["pma-voice"]:setVoiceProperty("radioEnabled", true)
664 | exports["pma-voice"]:setRadioChannel(tonumber(radio))
665 | QBCore.Functions.Notify("You have set your radio frequency to "..radio..".", "success")
666 | else
667 | QBCore.Functions.Notify("Invalid Station(Please enter a number)", "error")
668 | end
669 | end)
670 |
671 | RegisterNetEvent('mdt:client:sig100', function(radio, type)
672 | local job = PlayerData.job.name
673 | local duty = PlayerData.job.onduty
674 | if AllowedJob(job) and duty == 1 then
675 | if type == true then
676 | exports['erp_notifications']:PersistentAlert("START", "signall100-"..radio, "inform", "Radio "..radio.." is currently signal 100!")
677 | end
678 | end
679 | if not type then
680 | exports['erp_notifications']:PersistentAlert("END", "signall100-"..radio)
681 | end
682 | end)
683 |
684 | RegisterNetEvent('mdt:client:updateCallsign', function(callsign)
685 | callSign = tostring(callsign)
686 | end)
687 |
688 | RegisterNetEvent('mdt:client:updateIncidentDbId', function(sentData)
689 | SendNUIMessage({ type = "updateIncidentDbId", data = tonumber(sentData) })
690 | end)
691 |
692 |
693 | --====================================================================================
694 | ------------------------------------------
695 | -- DISPATCH PAGE --
696 | ------------------------------------------
697 | --====================================================================================
698 |
699 | RegisterNetEvent('dispatch:clNotify', function(sNotificationData, sNotificationId)
700 | if LocalPlayer.state.isLoggedIn then
701 | sNotificationData.playerJob = PlayerData.job.name
702 | SendNUIMessage({ type = "call", data = sNotificationData })
703 | end
704 | end)
705 |
706 | RegisterNUICallback("setWaypoint", function(data, cb)
707 | TriggerServerEvent('mdt:server:setWaypoint', data.callid)
708 | cb(true)
709 | end)
710 |
711 | RegisterNUICallback("callDetach", function(data, cb)
712 | TriggerServerEvent('mdt:server:callDetach', data.callid)
713 | cb(true)
714 | end)
715 |
716 | RegisterNUICallback("removeCallBlip", function(data, cb)
717 | TriggerEvent('ps-dispatch:client:removeCallBlip', data.callid)
718 | cb(true)
719 | end)
720 |
721 | RegisterNUICallback("callAttach", function(data, cb)
722 | TriggerServerEvent('mdt:server:callAttach', data.callid)
723 | cb(true)
724 | end)
725 |
726 | RegisterNUICallback("attachedUnits", function(data, cb)
727 | TriggerServerEvent('mdt:server:attachedUnits', data.callid)
728 | cb(true)
729 | end)
730 |
731 | RegisterNUICallback("callDispatchDetach", function(data, cb)
732 | TriggerServerEvent('mdt:server:callDispatchDetach', data.callid, data.cid)
733 | cb(true)
734 | end)
735 |
736 | RegisterNUICallback("setDispatchWaypoint", function(data, cb)
737 | TriggerServerEvent('mdt:server:setDispatchWaypoint', data.callid, data.cid)
738 | cb(true)
739 | end)
740 |
741 | RegisterNUICallback("callDragAttach", function(data, cb)
742 | TriggerServerEvent('mdt:server:callDragAttach', data.callid, data.cid)
743 | cb(true)
744 | end)
745 |
746 | RegisterNUICallback("setWaypointU", function(data, cb)
747 | TriggerServerEvent('mdt:server:setWaypoint:unit', data.cid)
748 | cb(true)
749 | end)
750 |
751 | RegisterNUICallback("dispatchMessage", function(data, cb)
752 | TriggerServerEvent('mdt:server:sendMessage', data.message, data.time)
753 | cb(true)
754 | end)
755 |
756 | RegisterNUICallback("refreshDispatchMsgs", function(data, cb)
757 | TriggerServerEvent('mdt:server:refreshDispatchMsgs')
758 | cb(true)
759 | end)
760 |
761 | RegisterNUICallback("dispatchNotif", function(data, cb)
762 | local info = data['data']
763 | local mentioned = false
764 | if callSign ~= "" then if string.find(string.lower(info['message']),string.lower(string.gsub(callSign,'-','%%-'))) then mentioned = true end end
765 | if mentioned then
766 |
767 | -- Send notification to phone??
768 | TriggerEvent('erp_phone:sendNotification', {img = info['profilepic'], title = "Dispatch (Mention)", content = info['message'], time = 7500, customPic = true })
769 |
770 | PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false)
771 | PlaySoundFrontend(-1, "Event_Start_Text", "GTAO_FM_Events_Soundset", 0)
772 | else
773 | TriggerEvent('erp_phone:sendNotification', {img = info['profilepic'], title = "Dispatch ("..info['name']..")", content = info['message'], time = 5000, customPic = true })
774 | end
775 | cb(true)
776 | end)
777 |
778 | RegisterNUICallback("getCallResponses", function(data, cb)
779 | TriggerServerEvent('mdt:server:getCallResponses', data.callid)
780 | cb(true)
781 | end)
782 |
783 | RegisterNUICallback("sendCallResponse", function(data, cb)
784 | TriggerServerEvent('mdt:server:sendCallResponse', data.message, data.time, data.callid)
785 | cb(true)
786 | end)
787 |
788 | --[[ RegisterNUICallback("impoundVehicle", function(data, cb)
789 | local JobType = GetJobType(PlayerData.job.name)
790 | if JobType == 'police' then
791 | local found = 0
792 | local plate = string.upper(string.gsub(data['plate'], "^%s*(.-)%s*$", "%1"))
793 | local vehicles = GetGamePool('CVehicle')
794 |
795 | for k,v in pairs(vehicles) do
796 | local plt = string.upper(string.gsub(GetVehicleNumberPlateText(v), "^%s*(.-)%s*$", "%1"))
797 | if plt == plate then
798 | local dist = #(GetEntityCoords(PlayerPedId()) - GetEntityCoords(v))
799 | if dist < 5.0 then
800 | found = VehToNet(v)
801 | end
802 | break
803 | end
804 | end
805 |
806 | if found == 0 then
807 | QBCore.Functions.Notify('Vehicle not found!', 'error')
808 | return
809 | end
810 |
811 | SendNUIMessage({ type = "greenShit" })
812 | TriggerServerEvent('mdt:server:impoundVehicle', data, found)
813 | cb('ok')
814 | end
815 | end) ]]
816 |
817 | RegisterNUICallback("removeImpound", function(data, cb)
818 | local ped = PlayerPedId()
819 | local playerPos = GetEntityCoords(ped)
820 | for k, v in pairs(Config.ImpoundLocations) do
821 | if (#(playerPos - vector3(v.x, v.y, v.z)) < 20.0) then
822 | TriggerServerEvent('mdt:server:removeImpound', data['plate'], k)
823 | break
824 | end
825 | end
826 | cb('ok')
827 | end)
828 |
829 | RegisterNUICallback("statusImpound", function(data, cb)
830 | TriggerServerEvent('mdt:server:statusImpound', data['plate'])
831 | cb('ok')
832 | end)
833 |
834 | RegisterNUICallback('openCamera', function(data)
835 | local camId = tonumber(data.cam)
836 | TriggerEvent('police:client:ActiveCamera', camId)
837 | end)
838 |
839 | RegisterNetEvent('mdt:client:attachedUnits', function(sentData, callid)
840 | SendNUIMessage({ type = "attachedUnits", data = sentData, callid = callid })
841 | end)
842 |
843 | RegisterNetEvent('mdt:client:setWaypoint', function(callInformation)
844 | SetNewWaypoint(callInformation['origin']['x'], callInformation['origin']['y'])
845 | end)
846 |
847 | RegisterNetEvent('mdt:client:callDetach', function(callid, sentData)
848 | local job = PlayerData.job.name
849 | if AllowedJob(job) then
850 | SendNUIMessage({ type = "callDetach", callid = callid, data = tonumber(sentData) })
851 | end
852 | end)
853 | RegisterNetEvent('mdt:client:callAttach', function(callid, sentData)
854 | local job = PlayerData.job.name
855 | if AllowedJob(job) then
856 | SendNUIMessage({ type = "callAttach", callid = callid, data = tonumber(sentData) })
857 | end
858 | end)
859 |
860 | RegisterNetEvent('mdt:client:setWaypoint:unit', function(sentData)
861 | SetNewWaypoint(sentData.x, sentData.y)
862 | end)
863 |
864 | RegisterNetEvent('mdt:client:dashboardMessage', function(sentData)
865 | local job = PlayerData.job.name
866 | if AllowedJob(job) then
867 | SendNUIMessage({ type = "dispatchmessage", data = sentData })
868 | end
869 | end)
870 |
871 | RegisterNetEvent('mdt:client:dashboardMessages', function(sentData)
872 | SendNUIMessage({ type = "dispatchmessages", data = sentData })
873 | end)
874 |
875 | RegisterNetEvent('mdt:client:getCallResponses', function(sentData, sentCallId)
876 | SendNUIMessage({ type = "getCallResponses", data = sentData, callid = sentCallId })
877 | end)
878 |
879 | RegisterNetEvent('mdt:client:sendCallResponse', function(message, time, callid, name)
880 | SendNUIMessage({ type = "sendCallResponse", message = message, time = time, callid = callid, name = name })
881 | end)
882 |
883 | RegisterNetEvent('mdt:client:notifyMechanics', function(sentData)
884 | --[[if exports["erp-jobsystem"]:CanTow() then
885 | TriggerServerEvent('erp-sounds:PlayWithinDistance', 1.5, 'beep', 0.4)
886 | TriggerEvent('erp_phone:sendNotification', {img = 'vehiclenotif.png', title = "Impound", content = "New vehicle is ready to be impounded!", time = 5000 })
887 | end]]
888 | end)
889 |
890 | RegisterNetEvent('mdt:client:statusImpound', function(data, plate)
891 | SendNUIMessage({ type = "statusImpound", data = data, plate = plate })
892 | end)
893 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/ps-mdt/shared/config.lua:
--------------------------------------------------------------------------------
1 | Config = Config or {}
2 |
3 | Config.RosterLink = {
4 | ['police'] = '',
5 | ['ambulance'] = '',
6 | ['bcso'] = '',
7 | ['doj'] = '',
8 | }
9 |
10 |
11 | Config.UseWolfknightRadar = false
12 | --[[
13 | Adds support for Wraith ARS 2X by WolfKnight98 (wk_wars2x)
14 | https://github.com/WolfKnight98/wk_wars2x
15 | To save on unnecessary database queries, in wk_wars2x/config.lua set 'CONFIG.use_sonorancad = true'
16 | This will only check plates of vehicles that have been occupied by a player
17 | --]]
18 |
19 | Config.OnlyShowOnDuty = true
20 |
21 | Config.Fuel = "lj-fuel" -- "LegacyFuel", "lj-fuel"
22 |
23 | Config.PenalCodeTitles = {
24 | [1] = 'OFFENSES AGAINST PERSONS',
25 | [2] = 'OFFENSES INVOLVING THEFT',
26 | [3] = 'OFFENSES INVOLVING FRAUD',
27 | [4] = 'OFFENSES INVOLVING DAMAGE TO PROPERTY',
28 | [5] = 'OFFENSES AGAINST PUBLIC ADMINISTRATION',
29 | [6] = 'OFFENSES AGAINST PUBLIC ORDER',
30 | [7] = 'OFFENSES AGAINST HEALTH AND MORALS',
31 | [8] = 'OFFENSES AGAINST PUBLIC SAFETY',
32 | [9] = 'OFFENSES INVOLVING THE OPERATION OF A VEHICLE',
33 | [10] = 'OFFENSES INVOLVING THE WELL-BEING OF WILDLIFE',
34 | }
35 |
36 | Config.PenalCode = {
37 | [1] = {
38 | [1] = {title = 'Simple Assault', class = 'Misdemeanor', id = 'P.C. 1001', months = 7, fine = 500, color = 'green'},
39 | [2] = {title = 'Assault', class = 'Misdemeanor', id = 'P.C. 1002', months = 15, fine = 850, color = 'orange'},
40 | [3] = {title = 'Aggravated Assault', class = 'Felony', id = 'P.C. 1003', months = 20, fine = 1250, color = 'orange'},
41 | [4] = {title = 'Assault with a Deadly Weapon', class = 'Felony', id = 'P.C. 1004', months = 30, fine = 3750, color = 'red'},
42 | [5] = {title = 'Involuntary Manslaughter', class = 'Felony', id = 'P.C. 1005', months = 60, fine = 7500, color = 'red'},
43 | [6] = {title = 'Vehicular Manslaughter', class = 'Felony', id = 'P.C. 1006', months = 75, fine = 7500, color = 'red'},
44 | [7] = {title = 'Attempted Murder of a Civilian', class = 'Felony', id = 'P.C. 1007', months = 50, fine = 7500, color = 'red'},
45 | [8] = {title = 'Second Degree Murder', class = 'Felony', id = 'P.C. 1008', months = 100, fine = 15000, color = 'red'},
46 | [9] = {title = 'Accessory to Second Degree Murder', class = 'Felony', id = 'P.C. 1009', months = 50, fine = 5000, color = 'red'},
47 | [10] = {title = 'First Degree Murder', class = 'Felony', id = 'P.C. 1010', months = 0, fine = 0, color = 'red'},
48 | [11] = {title = 'Accessory to First Degree Murder', class = 'Felony', id = 'P.C. 1011', months = 0, fine = 0, color = 'red'},
49 | [12] = {title = 'Murder of a Public Servant or Peace Officer', class = 'Felony', id = 'P.C. 1012', months = 0, fine = 0, color = 'red'},
50 | [13] = {title = 'Attempted Murder of a Public Servant or Peace Officer', class = 'Felony', id = 'P.C. 1013', months = 65, fine = 10000, color = 'red'},
51 | [14] = {title = 'Accessory to the Murder of a Public Servant or Peace Officer', class = 'Felony', id = 'P.C. 1014', months = 0, fine = 0, color = 'red'},
52 | [15] = {title = 'Unlawful Imprisonment', class = 'Misdemeanor', id = 'P.C. 1015', months = 10, fine = 600, color = 'green'},
53 | [16] = {title = 'Kidnapping', class = 'Felony', id = 'P.C. 1016', months = 15, fine = 900, color = 'orange'},
54 | [17] = {title = 'Accessory to Kidnapping', class = 'Felony', id = 'P.C. 1017', months = 7, fine = 450, color = 'orange'},
55 | [18] = {title = 'Attempted Kidnapping', class = 'Felony', id = 'P.C. 1018', months = 10, fine = 450, color = 'orange'},
56 | [19] = {title = 'Hostage Taking', class = 'Felony', id = 'P.C. 1019', months = 20, fine = 1200, color = 'orange'},
57 | [20] = {title = 'Accessory to Hostage Taking', class = 'Felony', id = 'P.C. 1020', months = 10, fine = 600, color = 'orange'},
58 | [21] = {title = 'Unlawful Imprisonment of a Public Servant or Peace Officer.', class = 'Felony', id = 'P.C. 1021', months = 25, fine = 4000, color = 'orange'},
59 | [22] = {title = 'Criminal Threats', class = 'Misdemeanor', id = 'P.C. 1022', months = 5, fine = 500, color = 'orange'},
60 | [23] = {title = 'Reckless Endangerment', class = 'Misdemeanor', id = 'P.C. 1023', months = 10, fine = 1000, color = 'orange'},
61 | [24] = {title = 'Gang Related Shooting', class = 'Felony', id = 'P.C. 1024', months = 30, fine = 2500, color = 'red'},
62 | [25] = {title = 'Cannibalism', class = 'Felony', id = 'P.C. 1025', months = 0, fine = 0, color = 'red'},
63 | [26] = {title = 'Torture', class = 'Felony', id = 'P.C. 1026', months = 40, fine = 4500, color = 'red'},
64 | },
65 | [2] = {
66 | [1] = {title = 'Petty Theft', class = 'Infraction', id = 'P.C. 2001', months = 0, fine = 250, color = 'green'},
67 | [2] = {title = 'Grand Theft', class = 'Misdemeanor', id = 'P.C. 2002', months = 10, fine = 600, color = 'green'},
68 | [3] = {title = 'Grand Theft Auto A', class = 'Felony', id = 'P.C. 2003', months = 15, fine = 900, color = 'green'},
69 | [4] = {title = 'Grand Theft Auto B', class = 'Felony', id = 'P.C. 2004', months = 35, fine = 3500, color = 'green'},
70 | [5] = {title = 'Carjacking', class = 'Felony', id = 'P.C. 2005', months = 30, fine = 2000, color = 'orange'},
71 | [6] = {title = 'Burglary', class = 'Misdemeanor', id = 'P.C. 2006', months = 10, fine = 500, color = 'green'},
72 | [7] = {title = 'Robbery', class = 'Felony', id = 'P.C. 2007', months = 25, fine = 2000, color = 'green'},
73 | [8] = {title = 'Accessory to Robbery', class = 'Felony', id = 'P.C. 2008', months = 12, fine = 1000, color = 'green'},
74 | [9] = {title = 'Attempted Robbery', class = 'Felony', id = 'P.C. 2009', months = 20, fine = 1000, color = 'green'},
75 | [10] = {title = 'Armed Robbery', class = 'Felony', id = 'P.C. 2010', months = 30, fine = 3000, color = 'orange'},
76 | [11] = {title = 'Accessory to Armed Robbery', class = 'Felony', id = 'P.C. 2011', months = 15, fine = 1500, color = 'orange'},
77 | [12] = {title = 'Attempted Armed Robbery', class = 'Felony', id = 'P.C. 2012', months = 25, fine = 1500, color = 'orange'},
78 | [13] = {title = 'Grand Larceny', class = 'Felony', id = 'P.C. 2013', months = 45, fine = 7500, color = 'orange'},
79 | [14] = {title = 'Leaving Without Paying', class = 'Infraction', id = 'P.C. 2014', months = 0, fine = 500, color = 'green'},
80 | [15] = {title = 'Possession of Nonlegal Currency', class = 'Misdemeanor', id = 'P.C. 2015', months = 10, fine = 750, color = 'green'},
81 | [16] = {title = 'Possession of Government-Issued Items', class = 'Misdemeanor', id = 'P.C. 2016', months = 15, fine = 1000, color = 'green'},
82 | [17] = {title = 'Possession of Items Used in the Commission of a Crime', class = 'Misdemeanor', id = 'P.C. 2017', months = 10, fine = 500, color = 'green'},
83 | [18] = {title = 'Sale of Items Used in the Commission of a Crime', class = 'Felony', id = 'P.C. 2018', months = 15, fine = 1000, color = 'orange'},
84 | [19] = {title = 'Theft of an Aircraft', class = 'Felony', id = 'P.C. 2019', months = 20, fine = 1000, color = 'green'},
85 | },
86 | [3] = {
87 | [1] = {title = 'Impersonating', class = 'Misdemeanor', id = 'P.C. 3001', months = 15, fine = 1250, color = 'green'},
88 | [2] = {title = 'Impersonating a Peace Officer or Public Servant', class = 'Felony', id = 'P.C. 3002', months = 25, fine = 2750, color = 'green'},
89 | [3] = {title = 'Impersonating a Judge', class = 'Felony', id = 'P.C. 3003', months = 0, fine = 0, color = 'green'},
90 | [4] = {title = 'Possession of Stolen Identification', class = 'Misdemeanor', id = 'P.C. 3004', months = 10, fine = 750, color = 'green'},
91 | [5] = {title = 'Possession of Stolen Government Identification', class = 'Misdemeanor', id = 'P.C. 3005', months = 20, fine = 2000, color = 'green'},
92 | [6] = {title = 'Extortion', class = 'Felony', id = 'P.C. 3006', months = 20, fine = 900, color = 'orange'},
93 | [7] = {title = 'Fraud', class = 'Misdemeanor', id = 'P.C. 3007', months = 10, fine = 450, color = 'green'},
94 | [8] = {title = 'Forgery', class = 'Misdemeanor', id = 'P.C. 3008', months = 15, fine = 750, color = 'green'},
95 | [9] = {title = 'Money Laundering', class = 'Felony', id = 'P.C. 3009', months = 0, fine = 0, color = 'red'},
96 | },
97 | [4] = {
98 | [1] = {title = 'Trespassing', class = 'Misdemeanor', id = 'P.C. 4001', months = 10, fine = 450, color = 'green'},
99 | [2] = {title = 'Felony Trespassing', class = 'Felony', id = 'P.C. 4002', months = 15, fine = 1500, color = 'green'},
100 | [3] = {title = 'Arson', class = 'Felony', id = 'P.C. 4003', months = 15, fine = 1500, color = 'orange'},
101 | [4] = {title = 'Vandalism', class = 'Infraction', id = 'P.C. 4004', months = 0, fine = 300, color = 'green'},
102 | [5] = {title = 'Vandalism of Government Property', class = 'Felony', id = 'P.C. 4005', months = 20, fine = 1500, color = 'green'},
103 | [6] = {title = 'Littering', class = 'Infraction', id = 'P.C. 4006', months = 0, fine = 200, color = 'green'},
104 | },
105 | [5] = {
106 | [1] = {title = 'Bribery of a Government Official', class = 'Felony', id = 'P.C. 5001', months = 20, fine = 3500, color = 'green'},
107 | [2] = {title = 'Anti-Mask Law', class = 'Infraction', id = 'P.C. 5002', months = 0, fine = 750, color = 'green'},
108 | [3] = {title = 'Possession of Contraband in a Government Facility', class = 'Felony', id = 'P.C. 5003', months = 25, fine = 1000, color = 'green'},
109 | [4] = {title = 'Criminal Possession of Stolen Property', class = 'Misdemeanor', id = 'P.C. 5004', months = 10, fine = 500, color = 'green'},
110 | [5] = {title = 'Escaping', class = 'Felony', id = 'P.C. 5005', months = 10, fine = 450, color = 'green'},
111 | [6] = {title = 'Jailbreak', class = 'Felony', id = 'P.C. 5006', months = 30, fine = 2500, color = 'orange'},
112 | [7] = {title = 'Accessory to Jailbreak', class = 'Felony', id = 'P.C. 5007', months = 25, fine = 2000, color = 'orange'},
113 | [8] = {title = 'Attempted Jailbreak', class = 'Felony', id = 'P.C. 5008', months = 20, fine = 1500, color = 'orange'},
114 | [9] = {title = 'Perjury', class = 'Felony', id = 'P.C. 5009', months = 0, fine = 0, color = 'green'},
115 | [10] = {title = 'Violation of a Restraining Order', class = 'Felony', id = 'P.C. 5010', months = 20, fine = 2250, color = 'green'},
116 | [11] = {title = 'Embezzlement', class = 'Felony', id = 'P.C. 5011', months = 45, fine = 10000, color = 'green'},
117 | [12] = {title = 'Unlawful Practice', class = 'Felony', id = 'P.C. 5012', months = 15, fine = 1500, color = 'orange'},
118 | [13] = {title = 'Misuse of Emergency Systems', class = 'Infraction', id = 'P.C. 5013', months = 0, fine = 600, color = 'orange'},
119 | [14] = {title = 'Conspiracy', class = 'Misdemeanor', id = 'P.C. 5014', months = 10, fine = 450, color = 'green'},
120 | [15] = {title = 'Violating a Court Order', class = 'Misdemeanor', id = 'P.C. 5015', months = 0, fine = 0, color = 'orange'},
121 | [16] = {title = 'Failure to Appear', class = 'Misdemeanor', id = 'P.C. 5016', months = 0, fine = 0, color = 'orange'},
122 | [17] = {title = 'Contempt of Court', class = 'Felony', id = 'P.C. 5017', months = 0, fine = 0, color = 'orange'},
123 | [18] = {title = 'Resisting Arrest', class = 'Misdemeanor', id = 'P.C. 5018', months = 5, fine = 300, color = 'orange'},
124 | },
125 | [6] = {
126 | [1] = {title = 'Disobeying a Peace Officer', class = 'infraction', id = 'P.C. 6001', months = 0, fine = 750, color = 'green'},
127 | [2] = {title = 'Disorderly Conduct', class = 'Infraction', id = 'P.C. 6002', months = 0, fine = 250, color = 'green'},
128 | [3] = {title = 'Disturbing the Peace', class = 'infraction', id = 'P.C. 6003', months = 0, fine = 350, color = 'green'},
129 | [4] = {title = 'False Reporting', class = 'Misdemeanor', id = 'P.C. 6004', months = 10, fine = 750, color = 'green'},
130 | [5] = {title = 'Harassment', class = 'Misdemeanor', id = 'P.C. 6005', months = 10, fine = 500, color = 'orange'},
131 | [6] = {title = 'Misdemeanor Obstruction of Justice', class = 'Misdemeanor', id = 'P.C. 6006', months = 10, fine = 500, color = 'green'},
132 | [7] = {title = 'Felony Obstruction of Justice', class = 'Felony', id = 'P.C. 6007', months = 15, fine = 900, color = 'green'},
133 | [8] = {title = 'Inciting a Riot', class = 'Felony', id = 'P.C. 6008', months = 25, fine = 1000, color = 'orange'},
134 | [9] = {title = 'Loitering on Government Properties', class = 'Infraction', id = 'P.C. 6009', months = 0, fine = 500, color = 'green'},
135 | [10] = {title = 'Tampering', class = 'Misdemeanor', id = 'P.C. 6010', months = 10, fine = 500, color = 'green'},
136 | [11] = {title = 'Vehicle Tampering', class = 'Misdemeanor', id = 'P.C. 6011', months = 15, fine = 750, color = 'green'},
137 | [12] = {title = 'Evidence Tampering', class = 'Felony', id = 'P.C. 6012', months = 20, fine = 1000, color = 'green'},
138 | [13] = {title = 'Witness Tampering', class = 'Felony', id = 'P.C. 6013', months = 0, fine = 0, color = 'green'},
139 | [14] = {title = 'Failure to Provide Identification', class = 'Misdemeanor', id = 'P.C. 6014', months = 15, fine = 1500, color = 'green'},
140 | [15] = {title = 'Vigilantism', class = 'Felony', id = 'P.C. 6015', months = 30, fine = 1500, color = 'orange'},
141 | [16] = {title = 'Unlawful Assembly', class = 'Misdemeanor', id = 'P.C. 6016', months = 10, fine = 750, color = 'orange'},
142 | [17] = {title = 'Government Corruption', class = 'Felony', id = 'P.C. 6017', months = 0, fine = 0, color = 'red'},
143 | [18] = {title = 'Stalking', class = 'Felony', id = 'P.C. 6018', months = 40, fine = 1500, color = 'orange'},
144 | [19] = {title = 'Aiding and Abetting', class = 'Misdemeanor', id = 'P.C. 6019', months = 15, fine = 450, color = 'orange'},
145 | [20] = {title = 'Harboring a Fugitive', class = 'Misdemeanor', id = 'P.C. 6020', months = 10, fine = 1000, color = 'green'},
146 | },
147 | [7] = {
148 | [1] = {title = 'Misdemeanor Possession of Marijuana', class = 'Mask', id = 'P.C. 7001', months = 5, fine = 250, color = 'green'},
149 | [2] = {title = 'Felony Possession of Marijuana', class = 'Felony', id = 'P.C. 7002', months = 15, fine = 1000, color = 'green'},
150 | [3] = {title = 'Cultivation of Marijuana A', class = 'Misdemeanor', id = 'P.C. 7003', months = 10, fine = 750, color = 'green'},
151 | [4] = {title = 'Cultivation of Marijuana B', class = 'Felony', id = 'P.C. 7004', months = 30, fine = 1500, color = 'orange'},
152 | [5] = {title = 'Possession of Marijuana with Intent to Distribute', class = 'Felony', id = 'P.C. 7005', months = 30, fine = 3000, color = 'orange'},
153 | [6] = {title = 'Misdemeanor Possession of Cocaine', class = 'Misdemeanor', id = 'P.C. 7006', months = 7, fine = 500, color = 'green'},
154 | [7] = {title = 'Felony Possession of Cocaine', class = 'Felony', id = 'P.C. 7007', months = 25, fine = 1500, color = 'green'},
155 | [8] = {title = 'Possession of Cocaine with Intent to Distribute', class = 'Felony', id = 'P.C. 7008', months = 35, fine = 4500, color = 'orange'},
156 | [9] = {title = 'Misdemeanor Possession of Methamphetamine', class = 'Misdemeanor', id = 'P.C. 7009', months = 7, fine = 500, color = 'green'},
157 | [10] = {title = 'Felony Possession of Methamphetamine', class = 'Felony', id = 'P.C. 7010', months = 25, fine = 1500, color = 'green'},
158 | [11] = {title = 'Possession of Methamphetamine with Intent to Distribute', class = 'Felony', id = 'P.C. 7011', months = 35, fine = 4500, color = 'orange'},
159 | [12] = {title = 'Misdemeanor Possession of Oxy / Vicodin', class = 'Felony', id = 'P.C. 7012', months = 7, fine = 500, color = 'green'},
160 | [13] = {title = 'Felony Possession of Oxy / Vicodin', class = 'Felony', id = 'P.C. 7013', months = 25, fine = 1500, color = 'green'},
161 | [14] = {title = 'Felony Possession of Oxy / Vicodin with Intent to Distribute', class = 'Felony', id = 'P.C. 7014', months = 35, fine = 4500, color = 'orange'},
162 | [15] = {title = 'Misdemeanor Possession of Ecstasy', class = 'Misdemeanor', id = 'P.C. 7015', months = 7, fine = 500, color = 'green'},
163 | [16] = {title = 'Felony Possession of Ecstasy', class = 'Felony', id = 'P.C. 7016', months = 25, fine = 1500, color = 'green'},
164 | [17] = {title = 'Possession of Ecstasy with Intent to Distribute', class = 'Felony', id = 'P.C. 7017', months = 35, fine = 4500, color = 'orange'},
165 | [18] = {title = 'Misdemeanor Possession of Opium', class = 'Misdemeanor', id = 'P.C. 7018', months = 7, fine = 500, color = 'green'},
166 | [19] = {title = 'Felony Possession of Opium', class = 'Felony', id = 'P.C. 7019', months = 25, fine = 1500, color = 'green'},
167 | [20] = {title = 'Possession of Opium with Intent to Distribute', class = 'Felony', id = 'P.C. 7020', months = 35, fine = 4500, color = 'orange'},
168 | [21] = {title = 'Misdemeanor Possession of Adderall', class = 'Misdemeanor', id = 'P.C. 7021', months = 7, fine = 500, color = 'green'},
169 | [22] = {title = 'Felony Possession of Adderall', class = 'Felony', id = 'P.C. 7022', months = 25, fine = 1500, color = 'green'},
170 | [23] = {title = 'Possession of Adderall with Intent to Distribute', class = 'Felony', id = 'P.C. 7023', months = 35, fine = 4500, color = 'orange'},
171 | [24] = {title = 'Misdemeanor Possession of Xanax', class = 'Misdemeanor', id = 'P.C. 7024', months = 7, fine = 500, color = 'green'},
172 | [25] = {title = 'Felony Possession of Xanax', class = 'Felony', id = 'P.C. 7025', months = 25, fine = 1500, color = 'green'},
173 | [26] = {title = 'Possession of Xanax with Intent to Distribute', class = 'Felony', id = 'P.C. 7026', months = 35, fine = 4500, color = 'orange'},
174 | [27] = {title = 'Misdemeanor Possession of Shrooms', class = 'Misdemeanor', id = 'P.C. 7027', months = 7, fine = 500, color = 'green'},
175 | [28] = {title = 'Felony Possession of Shrooms', class = 'Felony', id = 'P.C. 7028', months = 25, fine = 1500, color = 'green'},
176 | [29] = {title = 'Possession of Shrooms with Intent to Distribute', class = 'Felony', id = 'P.C. 7029', months = 35, fine = 4500, color = 'orange'},
177 | [30] = {title = 'Misdemeanor Possession of Lean', class = 'Misdemeanor', id = 'P.C. 7030', months = 7, fine = 500, color = 'green'},
178 | [31] = {title = 'Felony Possession of Lean', class = 'Felony', id = 'P.C. 7031', months = 25, fine = 1500, color = 'green'},
179 | [32] = {title = 'Possession of Lean with Intent to Distribute', class = 'Felony', id = 'P.C. 7032', months = 35, fine = 4500, color = 'orange'},
180 | [33] = {title = 'Sale of a controlled substance', class = 'Misdemeanor', id = 'P.C. 7033', months = 10, fine = 1000, color = 'green'},
181 | [34] = {title = 'Drug Trafficking', class = 'Felony', id = 'P.C. 7034', months = 0, fine = 0, color = 'red'},
182 | [35] = {title = 'Desecration of a Human Corpse', class = 'Felony', id = 'P.C. 7035', months = 20, fine = 1500, color = 'orange'},
183 | [36] = {title = 'Public Intoxication', class = 'Infraction', id = 'P.C. 7036', months = 0, fine = 500, color = 'green'},
184 | [37] = {title = 'Public Indecency', class = 'Misdemeanor', id = 'P.C. 7037', months = 10, fine = 750, color = 'green'},
185 | },
186 | [8] = {
187 | [1] = {title = 'Criminal Possession of Weapon Class A', class = 'Felony', id = 'P.C. 8001', months = 10, fine = 500, color = 'green'},
188 | [2] = {title = 'Criminal Possession of Weapon Class B', class = 'Felony', id = 'P.C. 8002', months = 15, fine = 1000, color = 'green'},
189 | [3] = {title = 'Criminal Possession of Weapon Class C', class = 'Felony', id = 'P.C. 8003', months = 30, fine = 3500, color = 'green'},
190 | [4] = {title = 'Criminal Possession of Weapon Class D', class = 'Felony', id = 'P.C. 8004', months = 25, fine = 1500, color = 'green'},
191 | [5] = {title = 'Criminal Sale of Weapon Class A', class = 'Felony', id = 'P.C. 8005', months = 15, fine = 1000, color = 'orange'},
192 | [6] = {title = 'Criminal Sale of Weapon Class B', class = 'Felony', id = 'P.C. 8006', months = 20, fine = 2000, color = 'orange'},
193 | [7] = {title = 'Criminal Sale of Weapon Class C', class = 'Felony', id = 'P.C. 8007', months = 35, fine = 7000, color = 'orange'},
194 | [8] = {title = 'Criminal Sale of Weapon Class D', class = 'Felony', id = 'P.C. 8008', months = 30, fine = 3000, color = 'orange'},
195 | [9] = {title = 'Criminal Use of Weapon', class = 'Misdemeanor', id = 'P.C. 8009', months = 10, fine = 450, color = 'orange'},
196 | [10] = {title = 'Possession of Illegal Firearm Modifications', class = 'Misdemeanor', id = 'P.C. 8010', months = 10, fine = 300, color = 'green'},
197 | [11] = {title = 'Weapon Trafficking', class = 'Felony', id = 'P.C. 8011', months = 0, fine = 0, color = 'red'},
198 | [12] = {title = 'Brandishing a Weapon', class = 'Misdemeanor', id = 'P.C. 8012', months = 15, fine = 500, color = 'orange'},
199 | [13] = {title = 'Insurrection', class = 'Felony', id = 'P.C. 8013', months = 0, fine = 0, color = 'red'},
200 | [14] = {title = 'Flying into Restricted Airspace', class = 'Felony', id = 'P.C. 8014', months = 20, fine = 1500, color = 'green'},
201 | [15] = {title = 'Jaywalking', class = 'Infraction', id = 'P.C. 8015', months = 0, fine = 150, color = 'green'},
202 | [16] = {title = 'Criminal Use of Explosives', class = 'Felony', id = 'P.C. 8016', months = 30, fine = 2500, color = 'orange'},
203 | },
204 | [9] = {
205 | [1] = {title = 'Driving While Intoxicated', class = 'Misdemeanor', id = 'P.C. 9001', months = 5, fine = 300, color = 'green'},
206 | [2] = {title = 'Evading', class = 'Misdemeanor', id = 'P.C. 9002', months = 5, fine = 400, color = 'green'},
207 | [3] = {title = 'Reckless Evading', class = 'Felony', id = 'P.C. 9003', months = 10, fine = 800, color = 'orange'},
208 | [4] = {title = 'Failure to Yield to Emergency Vehicle', class = 'Infraction', id = 'P.C. 9004', months = 0, fine = 600, color = 'green'},
209 | [5] = {title = 'Failure to Obey Traffic Control Device', class = 'Infraction', id = 'P.C. 9005', months = 0, fine = 150, color = 'green'},
210 | [6] = {title = 'Nonfunctional Vehicle', class = 'Infraction', id = 'P.C. 9006', months = 0, fine = 75, color = 'green'},
211 | [7] = {title = 'Negligent Driving', class = 'Infraction', id = 'P.C. 9007', months = 0, fine = 300, color = 'green'},
212 | [8] = {title = 'Reckless Driving', class = 'Misdemeanor', id = 'P.C. 9008', months = 10, fine = 750, color = 'orange'},
213 | [9] = {title = 'Third Degree Speeding', class = 'Infraction', id = 'P.C. 9009', months = 0, fine = 225, color = 'green'},
214 | [10] = {title = 'Second Degree Speeding', class = 'Infraction', id = 'P.C. 9010', months = 0, fine = 450, color = 'green'},
215 | [11] = {title = 'First Degree Speeding', class = 'Infraction', id = 'P.C. 9011', months = 0, fine = 750, color = 'green'},
216 | [12] = {title = 'Unlicensed Operation of Vehicle', class = 'Infraction', id = 'P.C. 9012', months = 0, fine = 500, color = 'green'},
217 | [13] = {title = 'Illegal U-Turn', class = 'Infraction', id = 'P.C. 9013', months = 0, fine = 75, color = 'green'},
218 | [14] = {title = 'Illegal Passing', class = 'Infraction', id = 'P.C. 9014', months = 0, fine = 300, color = 'green'},
219 | [15] = {title = 'Failure to Maintain Lane', class = 'Infraction', id = 'P.C. 9015', months = 0, fine = 300, color = 'green'},
220 | [16] = {title = 'Illegal Turn', class = 'Infraction', id = 'P.C. 9016', months = 0, fine = 150, color = 'green'},
221 | [17] = {title = 'Failure to Stop', class = 'Infraction', id = 'P.C. 9017', months = 0, fine = 600, color = 'green'},
222 | [18] = {title = 'Unauthorized Parking', class = 'Infraction', id = 'P.C. 9018', months = 0, fine = 300, color = 'green'},
223 | [19] = {title = 'Hit and Run', class = 'Misdemeanor', id = 'P.C. 9019', months = 10, fine = 500, color = 'green'},
224 | [20] = {title = 'Driving without Headlights or Signals', class = 'Infraction', id = 'P.C. 9020', months = 0, fine = 300, color = 'green'},
225 | [21] = {title = 'Street Racing', class = 'Felony', id = 'P.C. 9021', months = 15, fine = 1500, color = 'green'},
226 | [22] = {title = 'Piloting without Proper Licensing', class = 'Felony', id = 'P.C. 9022', months = 20, fine = 1500, color = 'orange'},
227 | [23] = {title = 'Unlawful Use of a Motorvehicle', class = 'Misdemeanor', id = 'P.C. 9023', months = 10, fine = 750, color = 'green'},
228 | },
229 | [10] = {
230 | [1] = {title = 'Hunting in Restricted Areas', class = 'Infraction', id = 'P.C. 10001', months = 0, fine = 450, color = 'green'},
231 | [2] = {title = 'Unlicensed Hunting', class = 'Infraction', id = 'P.C. 10002', months = 0, fine = 450, color = 'green'},
232 | [3] = {title = 'Animal Cruelty', class = 'Misdemeanor', id = 'P.C. 10003', months = 10, fine = 450, color = 'green'},
233 | [4] = {title = 'Hunting with a Non-Hunting Weapon', class = 'Misdemeanor', id = 'P.C. 10004', months = 10, fine = 750, color = 'green'},
234 | [5] = {title = 'Hunting outside of hunting hours', class = 'Infraction', id = 'P.C. 10005', months = 0, fine = 750, color = 'green'},
235 | [6] = {title = 'Overhunting', class = 'Misdemeanor', id = 'P.C. 10006', months = 10, fine = 1000, color = 'green'},
236 | [7] = {title = 'Poaching', class = 'Felony', id = 'P.C. 10007', months = 20, fine = 1250, color = 'red'},
237 | }
238 | }
239 |
240 | Config.PoliceJobs = {
241 | ['police'] = true,
242 | ['lspd'] = true,
243 | ['bcso'] = true,
244 | ['sast'] = true,
245 | ['sasp'] = true,
246 | ['doc'] = true,
247 | ['sapr'] = true,
248 | ['pa'] = true -- yucky
249 | }
250 |
251 | Config.AmbulanceJobs = {
252 | ['ambulance'] = true,
253 | ['doctor'] = true
254 | }
255 |
256 | Config.DojJobs = {
257 | ['lawyer'] = true,
258 | }
259 |
260 | -- Leave my hacky code alone ya goblins
261 | Config.AllowedJobs = {}
262 | for index, value in pairs(Config.PoliceJobs) do
263 | Config.AllowedJobs[index] = value
264 | end
265 | for index, value in pairs(Config.AmbulanceJobs) do
266 | Config.AllowedJobs[index] = value
267 | end
268 | for index, value in pairs(Config.DojJobs) do
269 | Config.AllowedJobs[index] = value
270 | end
271 | -- Leave my hacky code alone ya goblins
272 |
273 | Config.LogPerms = {
274 | ['ambulance'] = {
275 | [4] = true,
276 | },
277 | ['police'] = {
278 | [4] = true,
279 | },
280 | }
281 |
282 | Config.ColorNames = {
283 | [0] = "Metallic Black",
284 | [1] = "Metallic Graphite Black",
285 | [2] = "Metallic Black Steel",
286 | [3] = "Metallic Dark Silver",
287 | [4] = "Metallic Silver",
288 | [5] = "Metallic Blue Silver",
289 | [6] = "Metallic Steel Gray",
290 | [7] = "Metallic Shadow Silver",
291 | [8] = "Metallic Stone Silver",
292 | [9] = "Metallic Midnight Silver",
293 | [10] = "Metallic Gun Metal",
294 | [11] = "Metallic Anthracite Grey",
295 | [12] = "Matte Black",
296 | [13] = "Matte Gray",
297 | [14] = "Matte Light Grey",
298 | [15] = "Util Black",
299 | [16] = "Util Black Poly",
300 | [17] = "Util Dark silver",
301 | [18] = "Util Silver",
302 | [19] = "Util Gun Metal",
303 | [20] = "Util Shadow Silver",
304 | [21] = "Worn Black",
305 | [22] = "Worn Graphite",
306 | [23] = "Worn Silver Grey",
307 | [24] = "Worn Silver",
308 | [25] = "Worn Blue Silver",
309 | [26] = "Worn Shadow Silver",
310 | [27] = "Metallic Red",
311 | [28] = "Metallic Torino Red",
312 | [29] = "Metallic Formula Red",
313 | [30] = "Metallic Blaze Red",
314 | [31] = "Metallic Graceful Red",
315 | [32] = "Metallic Garnet Red",
316 | [33] = "Metallic Desert Red",
317 | [34] = "Metallic Cabernet Red",
318 | [35] = "Metallic Candy Red",
319 | [36] = "Metallic Sunrise Orange",
320 | [37] = "Metallic Classic Gold",
321 | [38] = "Metallic Orange",
322 | [39] = "Matte Red",
323 | [40] = "Matte Dark Red",
324 | [41] = "Matte Orange",
325 | [42] = "Matte Yellow",
326 | [43] = "Util Red",
327 | [44] = "Util Bright Red",
328 | [45] = "Util Garnet Red",
329 | [46] = "Worn Red",
330 | [47] = "Worn Golden Red",
331 | [48] = "Worn Dark Red",
332 | [49] = "Metallic Dark Green",
333 | [50] = "Metallic Racing Green",
334 | [51] = "Metallic Sea Green",
335 | [52] = "Metallic Olive Green",
336 | [53] = "Metallic Green",
337 | [54] = "Metallic Gasoline Blue Green",
338 | [55] = "Matte Lime Green",
339 | [56] = "Util Dark Green",
340 | [57] = "Util Green",
341 | [58] = "Worn Dark Green",
342 | [59] = "Worn Green",
343 | [60] = "Worn Sea Wash",
344 | [61] = "Metallic Midnight Blue",
345 | [62] = "Metallic Dark Blue",
346 | [63] = "Metallic Saxony Blue",
347 | [64] = "Metallic Blue",
348 | [65] = "Metallic Mariner Blue",
349 | [66] = "Metallic Harbor Blue",
350 | [67] = "Metallic Diamond Blue",
351 | [68] = "Metallic Surf Blue",
352 | [69] = "Metallic Nautical Blue",
353 | [70] = "Metallic Bright Blue",
354 | [71] = "Metallic Purple Blue",
355 | [72] = "Metallic Spinnaker Blue",
356 | [73] = "Metallic Ultra Blue",
357 | [74] = "Metallic Bright Blue",
358 | [75] = "Util Dark Blue",
359 | [76] = "Util Midnight Blue",
360 | [77] = "Util Blue",
361 | [78] = "Util Sea Foam Blue",
362 | [79] = "Uil Lightning blue",
363 | [80] = "Util Maui Blue Poly",
364 | [81] = "Util Bright Blue",
365 | [82] = "Matte Dark Blue",
366 | [83] = "Matte Blue",
367 | [84] = "Matte Midnight Blue",
368 | [85] = "Worn Dark blue",
369 | [86] = "Worn Blue",
370 | [87] = "Worn Light blue",
371 | [88] = "Metallic Taxi Yellow",
372 | [89] = "Metallic Race Yellow",
373 | [90] = "Metallic Bronze",
374 | [91] = "Metallic Yellow Bird",
375 | [92] = "Metallic Lime",
376 | [93] = "Metallic Champagne",
377 | [94] = "Metallic Pueblo Beige",
378 | [95] = "Metallic Dark Ivory",
379 | [96] = "Metallic Choco Brown",
380 | [97] = "Metallic Golden Brown",
381 | [98] = "Metallic Light Brown",
382 | [99] = "Metallic Straw Beige",
383 | [100] = "Metallic Moss Brown",
384 | [101] = "Metallic Biston Brown",
385 | [102] = "Metallic Beechwood",
386 | [103] = "Metallic Dark Beechwood",
387 | [104] = "Metallic Choco Orange",
388 | [105] = "Metallic Beach Sand",
389 | [106] = "Metallic Sun Bleeched Sand",
390 | [107] = "Metallic Cream",
391 | [108] = "Util Brown",
392 | [109] = "Util Medium Brown",
393 | [110] = "Util Light Brown",
394 | [111] = "Metallic White",
395 | [112] = "Metallic Frost White",
396 | [113] = "Worn Honey Beige",
397 | [114] = "Worn Brown",
398 | [115] = "Worn Dark Brown",
399 | [116] = "Worn straw beige",
400 | [117] = "Brushed Steel",
401 | [118] = "Brushed Black steel",
402 | [119] = "Brushed Aluminium",
403 | [120] = "Chrome",
404 | [121] = "Worn Off White",
405 | [122] = "Util Off White",
406 | [123] = "Worn Orange",
407 | [124] = "Worn Light Orange",
408 | [125] = "Metallic Securicor Green",
409 | [126] = "Worn Taxi Yellow",
410 | [127] = "police car blue",
411 | [128] = "Matte Green",
412 | [129] = "Matte Brown",
413 | [130] = "Worn Orange",
414 | [131] = "Matte White",
415 | [132] = "Worn White",
416 | [133] = "Worn Olive Army Green",
417 | [134] = "Pure White",
418 | [135] = "Hot Pink",
419 | [136] = "Salmon pink",
420 | [137] = "Metallic Vermillion Pink",
421 | [138] = "Orange",
422 | [139] = "Green",
423 | [140] = "Blue",
424 | [141] = "Mettalic Black Blue",
425 | [142] = "Metallic Black Purple",
426 | [143] = "Metallic Black Red",
427 | [144] = "Hunter Green",
428 | [145] = "Metallic Purple",
429 | [146] = "Metaillic V Dark Blue",
430 | [147] = "MODSHOP BLACK1",
431 | [148] = "Matte Purple",
432 | [149] = "Matte Dark Purple",
433 | [150] = "Metallic Lava Red",
434 | [151] = "Matte Forest Green",
435 | [152] = "Matte Olive Drab",
436 | [153] = "Matte Desert Brown",
437 | [154] = "Matte Desert Tan",
438 | [155] = "Matte Foilage Green",
439 | [156] = "DEFAULT ALLOY COLOR",
440 | [157] = "Epsilon Blue",
441 | [158] = "Unknown",
442 | }
443 |
444 | Config.ColorInformation = {
445 | [0] = "black",
446 | [1] = "black",
447 | [2] = "black",
448 | [3] = "darksilver",
449 | [4] = "silver",
450 | [5] = "bluesilver",
451 | [6] = "silver",
452 | [7] = "darksilver",
453 | [8] = "silver",
454 | [9] = "bluesilver",
455 | [10] = "darksilver",
456 | [11] = "darksilver",
457 | [12] = "matteblack",
458 | [13] = "gray",
459 | [14] = "lightgray",
460 | [15] = "black",
461 | [16] = "black",
462 | [17] = "darksilver",
463 | [18] = "silver",
464 | [19] = "utilgunmetal",
465 | [20] = "silver",
466 | [21] = "black",
467 | [22] = "black",
468 | [23] = "darksilver",
469 | [24] = "silver",
470 | [25] = "bluesilver",
471 | [26] = "darksilver",
472 | [27] = "red",
473 | [28] = "torinored",
474 | [29] = "formulared",
475 | [30] = "blazered",
476 | [31] = "gracefulred",
477 | [32] = "garnetred",
478 | [33] = "desertred",
479 | [34] = "cabernetred",
480 | [35] = "candyred",
481 | [36] = "orange",
482 | [37] = "gold",
483 | [38] = "orange",
484 | [39] = "red",
485 | [40] = "mattedarkred",
486 | [41] = "orange",
487 | [42] = "matteyellow",
488 | [43] = "red",
489 | [44] = "brightred",
490 | [45] = "garnetred",
491 | [46] = "red",
492 | [47] = "red",
493 | [48] = "darkred",
494 | [49] = "darkgreen",
495 | [50] = "racingreen",
496 | [51] = "seagreen",
497 | [52] = "olivegreen",
498 | [53] = "green",
499 | [54] = "gasolinebluegreen",
500 | [55] = "mattelimegreen",
501 | [56] = "darkgreen",
502 | [57] = "green",
503 | [58] = "darkgreen",
504 | [59] = "green",
505 | [60] = "seawash",
506 | [61] = "midnightblue",
507 | [62] = "darkblue",
508 | [63] = "saxonyblue",
509 | [64] = "blue",
510 | [65] = "blue",
511 | [66] = "blue",
512 | [67] = "diamondblue",
513 | [68] = "blue",
514 | [69] = "blue",
515 | [70] = "brightblue",
516 | [71] = "purpleblue",
517 | [72] = "blue",
518 | [73] = "ultrablue",
519 | [74] = "brightblue",
520 | [75] = "darkblue",
521 | [76] = "midnightblue",
522 | [77] = "blue",
523 | [78] = "blue",
524 | [79] = "lightningblue",
525 | [80] = "blue",
526 | [81] = "brightblue",
527 | [82] = "mattedarkblue",
528 | [83] = "matteblue",
529 | [84] = "matteblue",
530 | [85] = "darkblue",
531 | [86] = "blue",
532 | [87] = "lightningblue",
533 | [88] = "yellow",
534 | [89] = "yellow",
535 | [90] = "bronze",
536 | [91] = "yellow",
537 | [92] = "lime",
538 | [93] = "champagne",
539 | [94] = "beige",
540 | [95] = "darkivory",
541 | [96] = "brown",
542 | [97] = "brown",
543 | [98] = "lightbrown",
544 | [99] = "beige",
545 | [100] = "brown",
546 | [101] = "brown",
547 | [102] = "beechwood",
548 | [103] = "beechwood",
549 | [104] = "chocoorange",
550 | [105] = "yellow",
551 | [106] = "yellow",
552 | [107] = "cream",
553 | [108] = "brown",
554 | [109] = "brown",
555 | [110] = "brown",
556 | [111] = "white",
557 | [112] = "white",
558 | [113] = "beige",
559 | [114] = "brown",
560 | [115] = "brown",
561 | [116] = "beige",
562 | [117] = "steel",
563 | [118] = "blacksteel",
564 | [119] = "aluminium",
565 | [120] = "chrome",
566 | [121] = "wornwhite",
567 | [122] = "offwhite",
568 | [123] = "orange",
569 | [124] = "lightorange",
570 | [125] = "green",
571 | [126] = "yellow",
572 | [127] = "blue",
573 | [128] = "green",
574 | [129] = "brown",
575 | [130] = "orange",
576 | [131] = "white",
577 | [132] = "white",
578 | [133] = "darkgreen",
579 | [134] = "white",
580 | [135] = "pink",
581 | [136] = "pink",
582 | [137] = "pink",
583 | [138] = "orange",
584 | [139] = "green",
585 | [140] = "blue",
586 | [141] = "blackblue",
587 | [142] = "blackpurple",
588 | [143] = "blackred",
589 | [144] = "darkgreen",
590 | [145] = "purple",
591 | [146] = "darkblue",
592 | [147] = "black",
593 | [148] = "purple",
594 | [149] = "darkpurple",
595 | [150] = "red",
596 | [151] = "darkgreen",
597 | [152] = "olivedrab",
598 | [153] = "brown",
599 | [154] = "tan",
600 | [155] = "green",
601 | [156] = "silver",
602 | [157] = "blue",
603 | [158] = "black",
604 | }
605 |
606 | Config.ClassList = {
607 | [0] = "Compact",
608 | [1] = "Sedan",
609 | [2] = "SUV",
610 | [3] = "Coupe",
611 | [4] = "Muscle",
612 | [5] = "Sport Classic",
613 | [6] = "Sport",
614 | [7] = "Super",
615 | [8] = "Motorbike",
616 | [9] = "Off-Road",
617 | [10] = "Industrial",
618 | [11] = "Utility",
619 | [12] = "Van",
620 | [13] = "Bike",
621 | [14] = "Boat",
622 | [15] = "Helicopter",
623 | [16] = "Plane",
624 | [17] = "Service",
625 | [18] = "Emergency",
626 | [19] = "Military",
627 | [20] = "Commercial",
628 | [21] = "Train"
629 | }
630 |
631 | function GetJobType(job)
632 | if Config.PoliceJobs[job] then
633 | return 'police'
634 | elseif Config.AmbulanceJobs[job] then
635 | return 'ambulance'
636 | elseif Config.DojJobs[job] then
637 | return 'doj'
638 | else
639 | return nil
640 | end
641 | end
642 |
643 | -- this is a hack, because the qb-menu in qb-policejob populates an impound location and passed it through to the event.
644 | -- if this impound locations are changed in qb-policejob, they must also be changed here.
645 | Config.ImpoundLocations = {
646 | [1] = vector4(436.68, -1007.42, 27.32, 180.0),
647 | [2] = vector4(-436.14, 5982.63, 31.34, 136.0),
648 | }
649 |
--------------------------------------------------------------------------------
/ps-mdt/server/main.lua:
--------------------------------------------------------------------------------
1 | local QBCore = exports['qb-core']:GetCoreObject()
2 | -- Maybe cache?
3 | local incidents = {}
4 | local convictions = {}
5 | local bolos = {}
6 |
7 | -- TODO make it departments compatible
8 | local activeUnits = {}
9 |
10 | local impound = {}
11 | local dispatchMessages = {}
12 |
13 | local function IsPolice(job)
14 | for k, v in pairs(Config.PoliceJobs) do
15 | if job == k then
16 | return true
17 | end
18 | end
19 | return false
20 | end
21 |
22 | AddEventHandler("onResourceStart", function(resourceName)
23 | if (resourceName == 'ps-mdt') then
24 | activeUnits = {}
25 | end
26 | end)
27 |
28 | if Config.UseWolfknightRadar == true then
29 | RegisterNetEvent("wk:onPlateScanned")
30 | AddEventHandler("wk:onPlateScanned", function(cam, plate, index)
31 | local src = source
32 | local Player = QBCore.Functions.GetPlayer(src)
33 | local bolo = GetBoloStatus(plate)
34 | if bolo == true then
35 | TriggerClientEvent("wk:togglePlateLock", src, cam, true, bolo)
36 | end
37 | end)
38 | end
39 | RegisterNetEvent("ps-mdt:server:OnPlayerUnload", function()
40 | --// Delete player from the MDT on logout
41 | local src = source
42 | local player = QBCore.Functions.GetPlayer(src)
43 | if activeUnits[player.PlayerData.citizenid] ~= nil then
44 | activeUnits[player.PlayerData.citizenid] = nil
45 | end
46 | end)
47 |
48 | AddEventHandler("playerDropped", function(reason)
49 | --// Delete player from the MDT on logout
50 | local src = source
51 | local player = QBCore.Functions.GetPlayer(src)
52 | if player ~= nil then
53 | if activeUnits[player.PlayerData.citizenid] ~= nil then
54 | activeUnits[player.PlayerData.citizenid] = nil
55 | end
56 | else
57 | local license = QBCore.Functions.GetIdentifier(src, "license")
58 | local citizenids = GetCitizenID(license)
59 |
60 | for _, v in pairs(citizenids) do
61 | if activeUnits[v.citizenid] ~= nil then
62 | activeUnits[v.citizenid] = nil
63 | end
64 | end
65 | end
66 | end)
67 |
68 | RegisterNetEvent("ps-mdt:server:ToggleDuty", function()
69 | local src = source
70 | local player = QBCore.Functions.GetPlayer(src)
71 | if not player.PlayerData.job.onduty then
72 | --// Remove from MDT
73 | if activeUnits[player.PlayerData.citizenid] ~= nil then
74 | activeUnits[player.PlayerData.citizenid] = nil
75 | end
76 | end
77 | end)
78 |
79 | RegisterNetEvent('mdt:server:openMDT', function()
80 | local src = source
81 | local PlayerData = GetPlayerData(src)
82 | if not PermCheck(src, PlayerData) then return end
83 | local Radio = Player(src).state.radioChannel or 0
84 | --[[ if Radio > 100 then
85 | Radio = 0
86 | end ]]
87 |
88 | activeUnits[PlayerData.citizenid] = {
89 | cid = PlayerData.citizenid,
90 | callSign = PlayerData.metadata['callsign'],
91 | firstName = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2),
92 | lastName = PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2),
93 | radio = Radio,
94 | unitType = PlayerData.job.name,
95 | duty = PlayerData.job.onduty
96 | }
97 |
98 | local JobType = GetJobType(PlayerData.job.name)
99 | local bulletin = GetBulletins(JobType)
100 |
101 | local calls = exports['ps-dispatch']:GetDispatchCalls()
102 |
103 | --TriggerClientEvent('mdt:client:dashboardbulletin', src, bulletin)
104 | TriggerClientEvent('mdt:client:open', src, bulletin, activeUnits, calls, PlayerData.citizenid)
105 | --TriggerClientEvent('mdt:client:GetActiveUnits', src, activeUnits)
106 | end)
107 |
108 | QBCore.Functions.CreateCallback('mdt:server:SearchProfile', function(source, cb, sentData)
109 | if not sentData then return cb({}) end
110 | local src = source
111 | local Player = QBCore.Functions.GetPlayer(src)
112 | if Player then
113 | local JobType = GetJobType(Player.PlayerData.job.name)
114 | if JobType ~= nil then
115 | local people = MySQL.query.await("SELECT p.citizenid, p.charinfo, md.pfp FROM players p LEFT JOIN mdt_data md on p.citizenid = md.cid WHERE LOWER(CONCAT(JSON_VALUE(p.charinfo, '$.firstname'), ' ', JSON_VALUE(p.charinfo, '$.lastname'))) LIKE :query OR LOWER(`charinfo`) LIKE :query OR LOWER(`citizenid`) LIKE :query OR LOWER(`fingerprint`) LIKE :query AND jobtype = :jobtype LIMIT 20", { query = string.lower('%'..sentData..'%'), jobtype = JobType })
116 | local citizenIds = {}
117 | local citizenIdIndexMap = {}
118 | if not next(people) then cb({}) return end
119 |
120 | for index, data in pairs(people) do
121 | people[index]['warrant'] = false
122 | people[index]['convictions'] = 0
123 | people[index]['licences'] = GetPlayerLicenses(data.citizenid)
124 | people[index]['pp'] = ProfPic(data.gender, data.pfp)
125 | citizenIds[#citizenIds+1] = data.citizenid
126 | citizenIdIndexMap[data.citizenid] = index
127 | end
128 |
129 | local convictions = GetConvictions(citizenIds)
130 |
131 | if next(convictions) then
132 | for _, conv in pairs(convictions) do
133 | if conv.warrant then people[citizenIdIndexMap[conv.cid]].warrant = true end
134 |
135 | local charges = json.decode(conv.charges)
136 | people[citizenIdIndexMap[conv.cid]].convictions = people[citizenIdIndexMap[conv.cid]].convictions + #charges
137 | end
138 | end
139 |
140 |
141 | return cb(people)
142 | end
143 | end
144 |
145 | return cb({})
146 | end)
147 |
148 | QBCore.Functions.CreateCallback("mdt:server:getWarrants", function(source, cb)
149 | local WarrantData = {}
150 | local data = MySQL.query.await("SELECT * FROM mdt_convictions", {})
151 | for _, value in pairs(data) do
152 | if value.warrant == "1" then
153 | WarrantData[#WarrantData+1] = {
154 | cid = value.cid,
155 | linkedincident = value.linkedincident,
156 | name = GetNameFromId(value.cid),
157 | time = value.time
158 | }
159 | end
160 | end
161 | cb(WarrantData)
162 | end)
163 |
164 | QBCore.Functions.CreateCallback('mdt:server:OpenDashboard', function(source, cb)
165 | local PlayerData = GetPlayerData(source)
166 | if not PermCheck(source, PlayerData) then return end
167 | local JobType = GetJobType(PlayerData.job.name)
168 | local bulletin = GetBulletins(JobType)
169 | cb(bulletin)
170 | end)
171 |
172 | RegisterNetEvent('mdt:server:NewBulletin', function(title, info, time)
173 | local src = source
174 | local PlayerData = GetPlayerData(src)
175 | if not PermCheck(src, PlayerData) then return end
176 | local JobType = GetJobType(PlayerData.job.name)
177 | local playerName = GetNameFromPlayerData(PlayerData)
178 | local newBulletin = MySQL.insert.await('INSERT INTO `mdt_bulletin` (`title`, `desc`, `author`, `time`, `jobtype`) VALUES (:title, :desc, :author, :time, :jt)', {
179 | title = title,
180 | desc = info,
181 | author = playerName,
182 | time = tostring(time),
183 | jt = JobType
184 | })
185 |
186 | AddLog(("A new bulletin was added by %s with the title: %s!"):format(playerName, title))
187 | TriggerClientEvent('mdt:client:newBulletin', -1, src, {id = newBulletin, title = title, info = info, time = time, author = PlayerData.CitizenId}, JobType)
188 | end)
189 |
190 | RegisterNetEvent('mdt:server:deleteBulletin', function(id, title)
191 | if not id then return false end
192 | local src = source
193 | local PlayerData = GetPlayerData(src)
194 | if not PermCheck(src, PlayerData) then return end
195 | local JobType = GetJobType(PlayerData.job.name)
196 |
197 | MySQL.query.await('DELETE FROM `mdt_bulletin` where id = ?', {id})
198 | AddLog("Bulletin with Title: "..title.." was deleted by " .. GetNameFromPlayerData(PlayerData) .. ".")
199 | end)
200 |
201 | QBCore.Functions.CreateCallback('mdt:server:GetProfileData', function(source, cb, sentId)
202 | if not sentId then return cb({}) end
203 |
204 | local src = source
205 | local PlayerData = GetPlayerData(src)
206 | if not PermCheck(src, PlayerData) then return cb({}) end
207 | local JobType = GetJobType(PlayerData.job.name)
208 | local target = GetPlayerDataById(sentId)
209 | local JobName = PlayerData.job.name
210 |
211 | if not target or not next(target) then return cb({}) end
212 |
213 | -- Convert to string because bad code, yes?
214 | if type(target.job) == 'string' then target.job = json.decode(target.job) end
215 | if type(target.charinfo) == 'string' then target.charinfo = json.decode(target.charinfo) end
216 | if type(target.metadata) == 'string' then target.metadata = json.decode(target.metadata) end
217 |
218 | local licencesdata = target.metadata['licences'] or {
219 | ['driver'] = false,
220 | ['business'] = false,
221 | ['weapon'] = false,
222 | ['pilot'] = false
223 | }
224 |
225 | local job, grade = UnpackJob(target.job)
226 |
227 | local person = {
228 | cid = target.citizenid,
229 | firstname = target.charinfo.firstname,
230 | lastname = target.charinfo.lastname,
231 | job = job.label,
232 | grade = grade.name,
233 | pp = ProfPic(target.charinfo.gender),
234 | licences = licencesdata,
235 | dob = target.charinfo.birthdate,
236 | mdtinfo = '',
237 | fingerprint = '',
238 | tags = {},
239 | vehicles = {},
240 | properties = {},
241 | gallery = {},
242 | isLimited = false
243 | }
244 |
245 | if Config.PoliceJobs[JobName] then
246 | local convictions = GetConvictions({person.cid})
247 | person.convictions2 = {}
248 | local convCount = 1
249 | if next(convictions) then
250 | for _, conv in pairs(convictions) do
251 | if conv.warrant then person.warrant = true end
252 | local charges = json.decode(conv.charges)
253 | for _, charge in pairs(charges) do
254 | person.convictions2[convCount] = charge
255 | convCount = convCount + 1
256 | end
257 | end
258 | end
259 | local hash = {}
260 | person.convictions = {}
261 |
262 | for _,v in ipairs(person.convictions2) do
263 | if (not hash[v]) then
264 | person.convictions[#person.convictions+1] = v -- found this dedupe method on sourceforge somewhere, copy+pasta dev, needs to be refined later
265 | hash[v] = true
266 | end
267 | end
268 | local vehicles = GetPlayerVehicles(person.cid)
269 |
270 | if vehicles then
271 | person.vehicles = vehicles
272 | end
273 | local Coords = {}
274 | local Houses = {}
275 | local properties= GetPlayerProperties(person.cid)
276 | for k, v in pairs(properties) do
277 | Coords[#Coords+1] = {
278 | coords = json.decode(v["coords"]),
279 | }
280 | end
281 | for index = 1, #Coords, 1 do
282 | Houses[#Houses+1] = {
283 | label = properties[index]["label"],
284 | coords = tostring(Coords[index]["coords"]["enter"]["x"]..",".. Coords[index]["coords"]["enter"]["y"].. ",".. Coords[index]["coords"]["enter"]["z"]),
285 | }
286 | end
287 | -- if properties then
288 | person.properties = Houses
289 | -- end
290 | end
291 |
292 | local mdtData = GetPersonInformation(sentId, JobType)
293 | if mdtData then
294 | person.mdtinfo = mdtData.information
295 | person.fingerprint = mdtData.fingerprint
296 | person.profilepic = mdtData.pfp
297 | person.tags = json.decode(mdtData.tags)
298 | person.gallery = json.decode(mdtData.gallery)
299 | end
300 |
301 | local mdtData2 = GetPfpFingerPrintInformation(sentId)
302 | if mdtData2 then
303 | person.fingerprint = mdtData2.fingerprint
304 | person.profilepic = mdtData and mdtData.pfp or ""
305 | end
306 |
307 | return cb(person)
308 | end)
309 |
310 | RegisterNetEvent("mdt:server:saveProfile", function(pfp, information, cid, fName, sName, tags, gallery, fingerprint, licenses)
311 | local src = source
312 | local Player = QBCore.Functions.GetPlayer(src)
313 | ManageLicenses(cid, licenses)
314 | if Player then
315 | local JobType = GetJobType(Player.PlayerData.job.name)
316 | if JobType == 'doj' then JobType = 'police' end
317 | MySQL.Async.insert('INSERT INTO mdt_data (cid, information, pfp, jobtype, tags, gallery, fingerprint) VALUES (:cid, :information, :pfp, :jobtype, :tags, :gallery, :fingerprint) ON DUPLICATE KEY UPDATE cid = :cid, information = :information, pfp = :pfp, tags = :tags, gallery = :gallery, fingerprint = :fingerprint', {
318 | cid = cid,
319 | information = information,
320 | pfp = pfp,
321 | jobtype = JobType,
322 | tags = json.encode(tags),
323 | gallery = json.encode(gallery),
324 | fingerprint = fingerprint,
325 | })
326 | end
327 | end)
328 |
329 | RegisterNetEvent("mdt:server:updateLicense", function(cid, type, status)
330 | local src = source
331 | local Player = QBCore.Functions.GetPlayer(src)
332 | if Player then
333 | if GetJobType(Player.PlayerData.job.name) == 'police' then
334 | ManageLicense(cid, type, status)
335 | end
336 | end
337 | end)
338 |
339 | -- Incidents
340 |
341 |
342 | RegisterNetEvent('mdt:server:getAllIncidents', function()
343 | local src = source
344 | local Player = QBCore.Functions.GetPlayer(src)
345 | if Player then
346 | local JobType = GetJobType(Player.PlayerData.job.name)
347 | if JobType == 'police' or JobType == 'doj' then
348 | local matches = MySQL.query.await("SELECT * FROM `mdt_incidents` ORDER BY `id` DESC LIMIT 30", {})
349 |
350 | TriggerClientEvent('mdt:client:getAllIncidents', src, matches)
351 | end
352 | end
353 | end)
354 |
355 | RegisterNetEvent('mdt:server:searchIncidents', function(query)
356 | if query then
357 | local src = source
358 | local Player = QBCore.Functions.GetPlayer(src)
359 | if Player then
360 | local JobType = GetJobType(Player.PlayerData.job.name)
361 | if JobType == 'police' or JobType == 'doj' then
362 | local matches = MySQL.query.await("SELECT * FROM `mdt_incidents` WHERE `id` LIKE :query OR LOWER(`title`) LIKE :query OR LOWER(`author`) LIKE :query OR LOWER(`details`) LIKE :query OR LOWER(`tags`) LIKE :query OR LOWER(`officersinvolved`) LIKE :query OR LOWER(`civsinvolved`) LIKE :query OR LOWER(`author`) LIKE :query ORDER BY `id` DESC LIMIT 50", {
363 | query = string.lower('%'..query..'%') -- % wildcard, needed to search for all alike results
364 | })
365 |
366 | TriggerClientEvent('mdt:client:getIncidents', src, matches)
367 | end
368 | end
369 | end
370 | end)
371 |
372 | RegisterNetEvent('mdt:server:getIncidentData', function(sentId)
373 | if sentId then
374 | local src = source
375 | local Player = QBCore.Functions.GetPlayer(src)
376 | if Player then
377 | local JobType = GetJobType(Player.PlayerData.job.name)
378 | if JobType == 'police' or JobType == 'doj' then
379 | local matches = MySQL.query.await("SELECT * FROM `mdt_incidents` WHERE `id` = :id", {
380 | id = sentId
381 | })
382 | local data = matches[1]
383 | data['tags'] = json.decode(data['tags'])
384 | data['officersinvolved'] = json.decode(data['officersinvolved'])
385 | data['civsinvolved'] = json.decode(data['civsinvolved'])
386 | data['evidence'] = json.decode(data['evidence'])
387 |
388 |
389 | local convictions = MySQL.query.await("SELECT * FROM `mdt_convictions` WHERE `linkedincident` = :id", {
390 | id = sentId
391 | })
392 | if convictions ~= nil then
393 | for i=1, #convictions do
394 | local res = GetNameFromId(convictions[i]['cid'])
395 | if res ~= nil then
396 | convictions[i]['name'] = res
397 | else
398 | convictions[i]['name'] = "Unknown"
399 | end
400 | convictions[i]['charges'] = json.decode(convictions[i]['charges'])
401 | end
402 | end
403 | TriggerClientEvent('mdt:client:getIncidentData', src, data, convictions)
404 | end
405 | end
406 | end
407 | end)
408 |
409 | RegisterNetEvent('mdt:server:getAllBolos', function()
410 | local src = source
411 | local Player = QBCore.Functions.GetPlayer(src)
412 | local JobType = GetJobType(Player.PlayerData.job.name)
413 | if JobType == 'police' or JobType == 'ambulance' then
414 | local matches = MySQL.query.await("SELECT * FROM `mdt_bolos` WHERE jobtype = :jobtype", {jobtype = JobType})
415 | TriggerClientEvent('mdt:client:getAllBolos', src, matches)
416 | end
417 | end)
418 |
419 | RegisterNetEvent('mdt:server:searchBolos', function(sentSearch)
420 | if sentSearch then
421 | local src = source
422 | local Player = QBCore.Functions.GetPlayer(src)
423 | local JobType = GetJobType(Player.PlayerData.job.name)
424 | if JobType == 'police' or JobType == 'ambulance' then
425 | local matches = MySQL.query.await("SELECT * FROM `mdt_bolos` WHERE `id` LIKE :query OR LOWER(`title`) LIKE :query OR `plate` LIKE :query OR LOWER(`owner`) LIKE :query OR LOWER(`individual`) LIKE :query OR LOWER(`detail`) LIKE :query OR LOWER(`officersinvolved`) LIKE :query OR LOWER(`tags`) LIKE :query OR LOWER(`author`) LIKE :query AND jobtype = :jobtype", {
426 | query = string.lower('%'..sentSearch..'%'), -- % wildcard, needed to search for all alike results
427 | jobtype = JobType
428 | })
429 | TriggerClientEvent('mdt:client:getBolos', src, matches)
430 | end
431 | end
432 | end)
433 |
434 | RegisterNetEvent('mdt:server:getBoloData', function(sentId)
435 | if sentId then
436 | local src = source
437 | local Player = QBCore.Functions.GetPlayer(src)
438 | local JobType = GetJobType(Player.PlayerData.job.name)
439 | if JobType == 'police' or JobType == 'ambulance' then
440 | local matches = MySQL.query.await("SELECT * FROM `mdt_bolos` WHERE `id` = :id AND jobtype = :jobtype LIMIT 1", {
441 | id = sentId,
442 | jobtype = JobType
443 | })
444 |
445 | local data = matches[1]
446 | data['tags'] = json.decode(data['tags'])
447 | data['officersinvolved'] = json.decode(data['officersinvolved'])
448 | data['gallery'] = json.decode(data['gallery'])
449 | TriggerClientEvent('mdt:client:getBoloData', src, data)
450 | end
451 | end
452 | end)
453 |
454 | RegisterNetEvent('mdt:server:newBolo', function(existing, id, title, plate, owner, individual, detail, tags, gallery, officersinvolved, time)
455 | if id then
456 | local src = source
457 | local Player = QBCore.Functions.GetPlayer(src)
458 | local JobType = GetJobType(Player.PlayerData.job.name)
459 | if JobType == 'police' or JobType == 'ambulance' then
460 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
461 |
462 | local function InsertBolo()
463 | MySQL.insert('INSERT INTO `mdt_bolos` (`title`, `author`, `plate`, `owner`, `individual`, `detail`, `tags`, `gallery`, `officersinvolved`, `time`, `jobtype`) VALUES (:title, :author, :plate, :owner, :individual, :detail, :tags, :gallery, :officersinvolved, :time, :jobtype)', {
464 | title = title,
465 | author = fullname,
466 | plate = plate,
467 | owner = owner,
468 | individual = individual,
469 | detail = detail,
470 | tags = json.encode(tags),
471 | gallery = json.encode(gallery),
472 | officersinvolved = json.encode(officersinvolved),
473 | time = tostring(time),
474 | jobtype = JobType
475 | }, function(r)
476 | if r then
477 | TriggerClientEvent('mdt:client:boloComplete', src, r)
478 | TriggerEvent('mdt:server:AddLog', "A new BOLO was created by "..fullname.." with the title ("..title..") and ID ("..id..")")
479 | end
480 | end)
481 | end
482 |
483 | local function UpdateBolo()
484 | MySQL.update("UPDATE mdt_bolos SET `title`=:title, plate=:plate, owner=:owner, individual=:individual, detail=:detail, tags=:tags, gallery=:gallery, officersinvolved=:officersinvolved WHERE `id`=:id AND jobtype = :jobtype LIMIT 1", {
485 | title = title,
486 | plate = plate,
487 | owner = owner,
488 | individual = individual,
489 | detail = detail,
490 | tags = json.encode(tags),
491 | gallery = json.encode(gallery),
492 | officersinvolved = json.encode(officersinvolved),
493 | id = id,
494 | jobtype = JobType
495 | }, function(r)
496 | if r then
497 | TriggerClientEvent('mdt:client:boloComplete', src, id)
498 | TriggerEvent('mdt:server:AddLog', "A BOLO was updated by "..fullname.." with the title ("..title..") and ID ("..id..")")
499 | end
500 | end)
501 | end
502 |
503 | if existing then
504 | UpdateBolo()
505 | elseif not existing then
506 | InsertBolo()
507 | end
508 | end
509 | end
510 | end)
511 |
512 | RegisterNetEvent('mdt:server:deleteBolo', function(id)
513 | if id then
514 | local src = source
515 | local Player = QBCore.Functions.GetPlayer(src)
516 | local JobType = GetJobType(Player.PlayerData.job.name)
517 | if JobType == 'police' then
518 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
519 | MySQL.update("DELETE FROM `mdt_bolos` WHERE id=:id", { id = id, jobtype = JobType })
520 | TriggerEvent('mdt:server:AddLog', "A BOLO was deleted by "..fullname.." with the ID ("..id..")")
521 | end
522 | end
523 | end)
524 |
525 | RegisterNetEvent('mdt:server:deleteICU', function(id)
526 | if id then
527 | local src = source
528 | local Player = QBCore.Functions.GetPlayer(src)
529 | local JobType = GetJobType(Player.PlayerData.job.name)
530 | if JobType == 'ambulance' then
531 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
532 | MySQL.update("DELETE FROM `mdt_bolos` WHERE id=:id", { id = id, jobtype = JobType })
533 | TriggerEvent('mdt:server:AddLog', "A ICU Check-in was deleted by "..fullname.." with the ID ("..id..")")
534 | end
535 | end
536 | end)
537 |
538 | RegisterNetEvent('mdt:server:incidentSearchPerson', function(query)
539 | if query then
540 | local src = source
541 | local Player = QBCore.Functions.GetPlayer(src)
542 | if Player then
543 | local JobType = GetJobType(Player.PlayerData.job.name)
544 | if JobType == 'police' or JobType == 'doj' then
545 | local function ProfPic(gender, profilepic)
546 | if profilepic then return profilepic end;
547 | if gender == "f" then return "img/female.png" end;
548 | return "img/male.png"
549 | end
550 |
551 | local result = MySQL.query.await("SELECT p.citizenid, p.charinfo, md.pfp from players p LEFT JOIN mdt_data md on p.citizenid = md.cid WHERE LOWER(`charinfo`) LIKE :query OR LOWER(`citizenid`) LIKE :query AND `jobtype` = :jobtype LIMIT 30", {
552 | query = string.lower('%'..query..'%'), -- % wildcard, needed to search for all alike results
553 | jobtype = JobType
554 | })
555 | local data = {}
556 | for i=1, #result do
557 | local charinfo = json.decode(result[i].charinfo)
558 | data[i] = {id = result[i].citizenid, firstname = charinfo.firstname, lastname = charinfo.lastname, profilepic = ProfPic(charinfo.gender, result[i].pfp)}
559 | end
560 | TriggerClientEvent('mdt:client:incidentSearchPerson', src, data)
561 | end
562 | end
563 | end
564 | end)
565 |
566 | RegisterNetEvent('mdt:server:getAllReports', function()
567 | local src = source
568 | local Player = QBCore.Functions.GetPlayer(src)
569 | if Player then
570 | local JobType = GetJobType(Player.PlayerData.job.name)
571 | if JobType == 'police' or JobType == 'doj' or JobType == 'ambulance' then
572 | if JobType == 'doj' then JobType = 'police' end
573 | local matches = MySQL.query.await("SELECT * FROM `mdt_reports` WHERE jobtype = :jobtype ORDER BY `id` DESC LIMIT 30", {
574 | jobtype = JobType
575 | })
576 | TriggerClientEvent('mdt:client:getAllReports', src, matches)
577 | end
578 | end
579 | end)
580 |
581 | RegisterNetEvent('mdt:server:getReportData', function(sentId)
582 | if sentId then
583 | local src = source
584 | local Player = QBCore.Functions.GetPlayer(src)
585 | if Player then
586 | local JobType = GetJobType(Player.PlayerData.job.name)
587 | if JobType == 'police' or JobType == 'doj' or JobType == 'ambulance' then
588 | if JobType == 'doj' then JobType = 'police' end
589 | local matches = MySQL.query.await("SELECT * FROM `mdt_reports` WHERE `id` = :id AND `jobtype` = :jobtype LIMIT 1", {
590 | id = sentId,
591 | jobtype = JobType
592 | })
593 | local data = matches[1]
594 | data['tags'] = json.decode(data['tags'])
595 | data['officersinvolved'] = json.decode(data['officersinvolved'])
596 | data['civsinvolved'] = json.decode(data['civsinvolved'])
597 | data['gallery'] = json.decode(data['gallery'])
598 | TriggerClientEvent('mdt:client:getReportData', src, data)
599 | end
600 | end
601 | end
602 | end)
603 |
604 | RegisterNetEvent('mdt:server:searchReports', function(sentSearch)
605 | if sentSearch then
606 | local src = source
607 | local Player = QBCore.Functions.GetPlayer(src)
608 | if Player then
609 | local JobType = GetJobType(Player.PlayerData.job.name)
610 | if JobType == 'police' or JobType == 'doj' or JobType == 'ambulance' then
611 | if JobType == 'doj' then JobType = 'police' end
612 | local matches = MySQL.query.await("SELECT * FROM `mdt_reports` WHERE `id` LIKE :query OR LOWER(`author`) LIKE :query OR LOWER(`title`) LIKE :query OR LOWER(`type`) LIKE :query OR LOWER(`details`) LIKE :query OR LOWER(`tags`) LIKE :query AND `jobtype` = :jobtype ORDER BY `id` DESC LIMIT 50", {
613 | query = string.lower('%'..sentSearch..'%'), -- % wildcard, needed to search for all alike results
614 | jobtype = JobType
615 | })
616 |
617 | TriggerClientEvent('mdt:client:getAllReports', src, matches)
618 | end
619 | end
620 | end
621 | end)
622 |
623 | RegisterNetEvent('mdt:server:newReport', function(existing, id, title, reporttype, details, tags, gallery, officers, civilians, time)
624 | if id then
625 | local src = source
626 | local Player = QBCore.Functions.GetPlayer(src)
627 | if Player then
628 | local JobType = GetJobType(Player.PlayerData.job.name)
629 | if JobType ~= nil then
630 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
631 | local function InsertReport()
632 | MySQL.insert('INSERT INTO `mdt_reports` (`title`, `author`, `type`, `details`, `tags`, `gallery`, `officersinvolved`, `civsinvolved`, `time`, `jobtype`) VALUES (:title, :author, :type, :details, :tags, :gallery, :officersinvolved, :civsinvolved, :time, :jobtype)', {
633 | title = title,
634 | author = fullname,
635 | type = reporttype,
636 | details = details,
637 | tags = json.encode(tags),
638 | gallery = json.encode(gallery),
639 | officersinvolved = json.encode(officers),
640 | civsinvolved = json.encode(civilians),
641 | time = tostring(time),
642 | jobtype = JobType,
643 | }, function(r)
644 | if r then
645 | TriggerClientEvent('mdt:client:reportComplete', src, r)
646 | TriggerEvent('mdt:server:AddLog', "A new report was created by "..fullname.." with the title ("..title..") and ID ("..id..")")
647 | end
648 | end)
649 | end
650 |
651 | local function UpdateReport()
652 | MySQL.update("UPDATE `mdt_reports` SET `title` = :title, type = :type, details = :details, tags = :tags, gallery = :gallery, officersinvolved = :officersinvolved, civsinvolved = :civsinvolved, jobtype = :jobtype WHERE `id` = :id LIMIT 1", {
653 | title = title,
654 | type = reporttype,
655 | details = details,
656 | tags = json.encode(tags),
657 | gallery = json.encode(gallery),
658 | officersinvolved = json.encode(officers),
659 | civsinvolved = json.encode(civilians),
660 | jobtype = JobType,
661 | id = id,
662 | }, function(affectedRows)
663 | if affectedRows > 0 then
664 | TriggerClientEvent('mdt:client:reportComplete', src, id)
665 | TriggerEvent('mdt:server:AddLog', "A report was updated by "..fullname.." with the title ("..title..") and ID ("..id..")")
666 | end
667 | end)
668 | end
669 |
670 | if existing then
671 | UpdateReport()
672 | elseif not existing then
673 | InsertReport()
674 | end
675 | end
676 | end
677 | end
678 | end)
679 |
680 | QBCore.Functions.CreateCallback('mdt:server:SearchVehicles', function(source, cb, sentData)
681 | if not sentData then return cb({}) end
682 | local src = source
683 | local PlayerData = GetPlayerData(src)
684 | if not PermCheck(source, PlayerData) then return cb({}) end
685 |
686 | local src = source
687 | local Player = QBCore.Functions.GetPlayer(src)
688 | if Player then
689 | local JobType = GetJobType(Player.PlayerData.job.name)
690 | if JobType == 'police' or JobType == 'doj' then
691 | local vehicles = MySQL.query.await("SELECT pv.id, pv.citizenid, pv.plate, pv.vehicle, pv.mods, pv.state, p.charinfo FROM `player_vehicles` pv LEFT JOIN players p ON pv.citizenid = p.citizenid WHERE LOWER(`plate`) LIKE :query OR LOWER(`vehicle`) LIKE :query LIMIT 25", {
692 | query = string.lower('%'..sentData..'%')
693 | })
694 |
695 | if not next(vehicles) then cb({}) return end
696 |
697 | for _, value in ipairs(vehicles) do
698 | if value.state == 0 then
699 | value.state = "Out"
700 | elseif value.state == 1 then
701 | value.state = "Garaged"
702 | elseif value.state == 2 then
703 | value.state = "Impounded"
704 | end
705 |
706 | value.bolo = false
707 | local boloResult = GetBoloStatus(value.plate)
708 | if boloResult then
709 | value.bolo = true
710 | end
711 |
712 | value.code = false
713 | value.stolen = false
714 | value.image = "img/not-found.webp"
715 | local info = GetVehicleInformation(value.plate)
716 | if info then
717 | value.code = info['code5']
718 | value.stolen = info['stolen']
719 | value.image = info['image']
720 | end
721 |
722 | local ownerResult = json.decode(value.charinfo)
723 |
724 | value.owner = ownerResult['firstname'] .. " " .. ownerResult['lastname']
725 | end
726 | -- idk if this works or I have to call cb first then return :shrug:
727 | return cb(vehicles)
728 | end
729 |
730 | return cb({})
731 | end
732 |
733 | end)
734 |
735 | RegisterNetEvent('mdt:server:getVehicleData', function(plate)
736 | if plate then
737 | local src = source
738 | local Player = QBCore.Functions.GetPlayer(src)
739 | if Player then
740 | local JobType = GetJobType(Player.PlayerData.job.name)
741 | if JobType == 'police' or JobType == 'doj' then
742 | local vehicle = MySQL.query.await("select pv.*, p.charinfo from player_vehicles pv LEFT JOIN players p ON pv.citizenid = p.citizenid where pv.plate = :plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1")})
743 | if vehicle and vehicle[1] then
744 | vehicle[1]['impound'] = false
745 | if vehicle[1].state == 2 then
746 | vehicle[1]['impound'] = true
747 | end
748 |
749 | vehicle[1]['bolo'] = GetBoloStatus(vehicle[1]['plate'])
750 | vehicle[1]['information'] = ""
751 |
752 | vehicle[1]['name'] = "Unknown Person"
753 |
754 | local ownerResult = json.decode(vehicle[1].charinfo)
755 | vehicle[1]['name'] = ownerResult['firstname'] .. " " .. ownerResult['lastname']
756 |
757 | local color1 = json.decode(vehicle[1].mods)
758 | vehicle[1]['color1'] = color1['color1']
759 |
760 | vehicle[1]['dbid'] = 0
761 |
762 | local info = GetVehicleInformation(vehicle[1]['plate'])
763 | if info then
764 | vehicle[1]['information'] = info['information']
765 | vehicle[1]['dbid'] = info['id']
766 | vehicle[1]['image'] = info['image']
767 | vehicle[1]['code'] = info['code5']
768 | vehicle[1]['stolen'] = info['stolen']
769 | end
770 |
771 | if vehicle[1]['image'] == nil then vehicle[1]['image'] = "img/not-found.webp" end -- Image
772 | end
773 |
774 | TriggerClientEvent('mdt:client:getVehicleData', src, vehicle)
775 | end
776 | end
777 | end
778 | end)
779 |
780 | RegisterNetEvent('mdt:server:saveVehicleInfo', function(dbid, plate, imageurl, notes, stolen, code5, impoundInfo)
781 | if plate then
782 | local src = source
783 | local Player = QBCore.Functions.GetPlayer(src)
784 | if Player then
785 | if GetJobType(Player.PlayerData.job.name) == 'police' then
786 | if dbid == nil then dbid = 0 end;
787 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
788 | TriggerEvent('mdt:server:AddLog', "A vehicle with the plate ("..plate..") has a new image ("..imageurl..") edited by "..fullname)
789 | if tonumber(dbid) == 0 then
790 | MySQL.insert('INSERT INTO `mdt_vehicleinfo` (`plate`, `information`, `image`, `code5`, `stolen`) VALUES (:plate, :information, :image, :code5, :stolen)', { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1"), information = notes, image = imageurl, code5 = code5, stolen = stolen }, function(infoResult)
791 | if infoResult then
792 | TriggerClientEvent('mdt:client:updateVehicleDbId', src, infoResult)
793 | TriggerEvent('mdt:server:AddLog', "A vehicle with the plate ("..plate..") was added to the vehicle information database by "..fullname)
794 | end
795 | end)
796 | elseif tonumber(dbid) > 0 then
797 | MySQL.update("UPDATE mdt_vehicleinfo SET `information`= :information, `image`= :image, `code5`= :code5, `stolen`= :stolen WHERE `plate`= :plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1"), information = notes, image = imageurl, code5 = code5, stolen = stolen })
798 | end
799 |
800 | if impoundInfo.impoundChanged then
801 | local vehicle = MySQL.single.await("SELECT p.id, p.plate, i.vehicleid AS impoundid FROM `player_vehicles` p LEFT JOIN `mdt_impound` i ON i.vehicleid = p.id WHERE plate=:plate", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1") })
802 | if impoundInfo.impoundActive then
803 | local plate, linkedreport, fee, time = impoundInfo['plate'], impoundInfo['linkedreport'], impoundInfo['fee'], impoundInfo['time']
804 | if (plate and linkedreport and fee and time) then
805 | if vehicle.impoundid == nil then
806 | -- This section is copy pasted from request impound and needs some attention.
807 | -- sentVehicle doesnt exist.
808 | -- data is defined twice
809 | -- INSERT INTO will not work if it exists already (which it will)
810 | local data = vehicle
811 | MySQL.insert('INSERT INTO `mdt_impound` (`vehicleid`, `linkedreport`, `fee`, `time`) VALUES (:vehicleid, :linkedreport, :fee, :time)', {
812 | vehicleid = data['id'],
813 | linkedreport = linkedreport,
814 | fee = fee,
815 | time = os.time() + (time * 60)
816 | }, function(res)
817 | -- notify?
818 | local data = {
819 | vehicleid = data['id'],
820 | plate = plate,
821 | beingcollected = 0,
822 | vehicle = sentVehicle,
823 | officer = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
824 | number = Player.PlayerData.charinfo.phone,
825 | time = os.time() * 1000,
826 | src = src,
827 | }
828 | local vehicle = NetworkGetEntityFromNetworkId(sentVehicle)
829 | FreezeEntityPosition(vehicle, true)
830 | impound[#impound+1] = data
831 |
832 | TriggerClientEvent("police:client:ImpoundVehicle", src, true, fee)
833 | end)
834 | -- Read above comment
835 | end
836 | end
837 | else
838 | if vehicle.impoundid ~= nil then
839 | local data = vehicle
840 | local result = MySQL.single.await("SELECT id, vehicle, fuel, engine, body FROM `player_vehicles` WHERE plate=:plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1")})
841 | if result then
842 | local data = result
843 | MySQL.update("DELETE FROM `mdt_impound` WHERE vehicleid=:vehicleid", { vehicleid = data['id'] })
844 |
845 | result.currentSelection = impoundInfo.CurrentSelection
846 | result.plate = plate
847 | TriggerClientEvent('ps-mdt:client:TakeOutImpound', src, result)
848 | end
849 |
850 | end
851 | end
852 | end
853 | end
854 | end
855 | end
856 | end)
857 |
858 | RegisterNetEvent('mdt:server:getAllLogs', function()
859 | local src = source
860 | local Player = QBCore.Functions.GetPlayer(src)
861 | if Player then
862 | if Config.LogPerms[Player.PlayerData.job.name] then
863 | if Config.LogPerms[Player.PlayerData.job.name][Player.PlayerData.job.grade.level] then
864 |
865 | local JobType = GetJobType(Player.PlayerData.job.name)
866 | local infoResult = MySQL.query.await('SELECT * FROM mdt_logs WHERE `jobtype` = :jobtype ORDER BY `id` DESC LIMIT 250', {jobtype = JobType})
867 |
868 | TriggerLatentClientEvent('mdt:client:getAllLogs', src, 30000, infoResult)
869 | end
870 | end
871 | end
872 | end)
873 |
874 | -- Penal Code
875 |
876 | local function IsCidFelon(sentCid, cb)
877 | if sentCid then
878 | local convictions = MySQL.query.await('SELECT charges FROM mdt_convictions WHERE cid=:cid', { cid = sentCid })
879 | local Charges = {}
880 | for i=1, #convictions do
881 | local currCharges = json.decode(convictions[i]['charges'])
882 | for x=1, #currCharges do
883 | Charges[#Charges+1] = currCharges[x]
884 | end
885 | end
886 | local PenalCode = Config.PenalCode
887 | for i=1, #Charges do
888 | for p=1, #PenalCode do
889 | for x=1, #PenalCode[p] do
890 | if PenalCode[p][x]['title'] == Charges[i] then
891 | if PenalCode[p][x]['class'] == 'Felony' then
892 | cb(true)
893 | return
894 | end
895 | break
896 | end
897 | end
898 | end
899 | end
900 | cb(false)
901 | end
902 | end
903 |
904 | exports('IsCidFelon', IsCidFelon) -- exports['erp_mdt']:IsCidFelon()
905 |
906 | RegisterCommand("isfelon", function(source, args, rawCommand)
907 | IsCidFelon(1998, function(res)
908 | end)
909 | end, false)
910 |
911 | RegisterNetEvent('mdt:server:getPenalCode', function()
912 | local src = source
913 | TriggerClientEvent('mdt:client:getPenalCode', src, Config.PenalCodeTitles, Config.PenalCode)
914 | end)
915 |
916 | RegisterNetEvent('mdt:server:setCallsign', function(cid, newcallsign)
917 | local Player = QBCore.Functions.GetPlayerByCitizenId(cid)
918 | Player.Functions.SetMetaData("callsign", newcallsign)
919 | end)
920 |
921 | RegisterNetEvent('mdt:server:saveIncident', function(id, title, information, tags, officers, civilians, evidence, associated, time)
922 | local src = source
923 | local Player = QBCore.Functions.GetPlayer(src)
924 | if Player then
925 | if GetJobType(Player.PlayerData.job.name) == 'police' then
926 | if id == 0 then
927 | local fullname = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
928 | MySQL.insert('INSERT INTO `mdt_incidents` (`author`, `title`, `details`, `tags`, `officersinvolved`, `civsinvolved`, `evidence`, `time`, `jobtype`) VALUES (:author, :title, :details, :tags, :officersinvolved, :civsinvolved, :evidence, :time, :jobtype)',
929 | {
930 | author = fullname,
931 | title = title,
932 | details = information,
933 | tags = json.encode(tags),
934 | officersinvolved = json.encode(officers),
935 | civsinvolved = json.encode(civilians),
936 | evidence = json.encode(evidence),
937 | time = time,
938 | jobtype = 'police',
939 | }, function(infoResult)
940 | if infoResult then
941 | for i=1, #associated do
942 | MySQL.insert('INSERT INTO `mdt_convictions` (`cid`, `linkedincident`, `warrant`, `guilty`, `processed`, `associated`, `charges`, `fine`, `sentence`, `recfine`, `recsentence`, `time`) VALUES (:cid, :linkedincident, :warrant, :guilty, :processed, :associated, :charges, :fine, :sentence, :recfine, :recsentence, :time)', {
943 | cid = associated[i]['Cid'],
944 | linkedincident = infoResult,
945 | warrant = associated[i]['Warrant'],
946 | guilty = associated[i]['Guilty'],
947 | processed = associated[i]['Processed'],
948 | associated = associated[i]['Isassociated'],
949 | charges = json.encode(associated[i]['Charges']),
950 | fine = tonumber(associated[i]['Fine']),
951 | sentence = tonumber(associated[i]['Sentence']),
952 | recfine = tonumber(associated[i]['recfine']),
953 | recsentence = tonumber(associated[i]['recsentence']),
954 | time = time
955 | })
956 | end
957 | TriggerClientEvent('mdt:client:updateIncidentDbId', src, infoResult)
958 | --TriggerEvent('mdt:server:AddLog', "A vehicle with the plate ("..plate..") was added to the vehicle information database by "..player['fullname'])
959 | end
960 | end)
961 | elseif id > 0 then
962 | MySQL.update("UPDATE mdt_incidents SET title=:title, details=:details, civsinvolved=:civsinvolved, tags=:tags, officersinvolved=:officersinvolved, evidence=:evidence WHERE id=:id", {
963 | title = title,
964 | details = information,
965 | tags = json.encode(tags),
966 | officersinvolved = json.encode(officers),
967 | civsinvolved = json.encode(civilians),
968 | evidence = json.encode(evidence),
969 | id = id
970 | })
971 | for i=1, #associated do
972 | TriggerEvent('mdt:server:handleExistingConvictions', associated[i], id, time)
973 | end
974 | end
975 | end
976 | end
977 | end)
978 |
979 | RegisterNetEvent('mdt:server:handleExistingConvictions', function(data, incidentid, time)
980 | MySQL.query('SELECT * FROM mdt_convictions WHERE cid=:cid AND linkedincident=:linkedincident', {
981 | cid = data['Cid'],
982 | linkedincident = incidentid
983 | }, function(convictionRes)
984 | if convictionRes and convictionRes[1] and convictionRes[1]['id'] then
985 | MySQL.update('UPDATE mdt_convictions SET cid=:cid, linkedincident=:linkedincident, warrant=:warrant, guilty=:guilty, processed=:processed, associated=:associated, charges=:charges, fine=:fine, sentence=:sentence, recfine=:recfine, recsentence=:recsentence WHERE cid=:cid AND linkedincident=:linkedincident', {
986 | cid = data['Cid'],
987 | linkedincident = incidentid,
988 | warrant = data['Warrant'],
989 | guilty = data['Guilty'],
990 | processed = data['Processed'],
991 | associated = data['Isassociated'],
992 | charges = json.encode(data['Charges']),
993 | fine = tonumber(data['Fine']),
994 | sentence = tonumber(data['Sentence']),
995 | recfine = tonumber(data['recfine']),
996 | recsentence = tonumber(data['recsentence']),
997 | })
998 | else
999 | MySQL.insert('INSERT INTO `mdt_convictions` (`cid`, `linkedincident`, `warrant`, `guilty`, `processed`, `associated`, `charges`, `fine`, `sentence`, `recfine`, `recsentence`, `time`) VALUES (:cid, :linkedincident, :warrant, :guilty, :processed, :associated, :charges, :fine, :sentence, :recfine, :recsentence, :time)', {
1000 | cid = data['Cid'],
1001 | linkedincident = incidentid,
1002 | warrant = data['Warrant'],
1003 | guilty = data['Guilty'],
1004 | processed = data['Processed'],
1005 | associated = data['Isassociated'],
1006 | charges = json.encode(data['Charges']),
1007 | fine = tonumber(data['Fine']),
1008 | sentence = tonumber(data['Sentence']),
1009 | recfine = tonumber(data['recfine']),
1010 | recsentence = tonumber(data['recsentence']),
1011 | time = time
1012 | })
1013 | end
1014 | end)
1015 | end)
1016 |
1017 | RegisterNetEvent('mdt:server:removeIncidentCriminal', function(cid, incident)
1018 | MySQL.update('DELETE FROM mdt_convictions WHERE cid=:cid AND linkedincident=:linkedincident', {
1019 | cid = cid,
1020 | linkedincident = incident
1021 | })
1022 | end)
1023 |
1024 | -- Dispatch
1025 |
1026 | RegisterNetEvent('mdt:server:setWaypoint', function(callid)
1027 | local src = source
1028 | local Player = QBCore.Functions.GetPlayer(source)
1029 | local JobType = GetJobType(Player.PlayerData.job.name)
1030 | if JobType == 'police' or JobType == 'ambulance' then
1031 | if callid then
1032 | local calls = exports['ps-dispatch']:GetDispatchCalls()
1033 | TriggerClientEvent('mdt:client:setWaypoint', src, calls[callid])
1034 | end
1035 | end
1036 | end)
1037 |
1038 | RegisterNetEvent('mdt:server:callDetach', function(callid)
1039 | local src = source
1040 | local Player = QBCore.Functions.GetPlayer(src)
1041 | local playerdata = {
1042 | fullname = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1043 | job = Player.PlayerData.job,
1044 | cid = Player.PlayerData.citizenid,
1045 | callsign = Player.PlayerData.metadata.callsign
1046 | }
1047 | local JobType = GetJobType(Player.PlayerData.job.name)
1048 | if JobType == 'police' or JobType == 'ambulance' then
1049 | if callid then
1050 | TriggerEvent('dispatch:removeUnit', callid, playerdata, function(newNum)
1051 | TriggerClientEvent('mdt:client:callDetach', -1, callid, newNum)
1052 | end)
1053 | end
1054 | end
1055 | end)
1056 |
1057 | RegisterNetEvent('mdt:server:callAttach', function(callid)
1058 | local src = source
1059 | local Player = QBCore.Functions.GetPlayer(src)
1060 | local playerdata = {
1061 | fullname = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1062 | job = Player.PlayerData.job,
1063 | cid = Player.PlayerData.citizenid,
1064 | callsign = Player.PlayerData.metadata.callsign
1065 | }
1066 | local JobType = GetJobType(Player.PlayerData.job.name)
1067 | if JobType == 'police' or JobType == 'ambulance' then
1068 | if callid then
1069 | TriggerEvent('dispatch:addUnit', callid, playerdata, function(newNum)
1070 | TriggerClientEvent('mdt:client:callAttach', -1, callid, newNum)
1071 | end)
1072 | end
1073 | end
1074 |
1075 | end)
1076 |
1077 | RegisterNetEvent('mdt:server:attachedUnits', function(callid)
1078 | local src = source
1079 | local Player = QBCore.Functions.GetPlayer(src)
1080 | local JobType = GetJobType(Player.PlayerData.job.name)
1081 | if JobType == 'police' or JobType == 'ambulance' then
1082 | if callid then
1083 | local calls = exports['ps-dispatch']:GetDispatchCalls()
1084 | TriggerClientEvent('mdt:client:attachedUnits', src, calls[callid]['units'], callid)
1085 | end
1086 | end
1087 | end)
1088 |
1089 | RegisterNetEvent('mdt:server:callDispatchDetach', function(callid, cid)
1090 | local src = source
1091 | local Player = QBCore.Functions.GetPlayer(src)
1092 | local playerdata = {
1093 | fullname = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1094 | job = Player.PlayerData.job,
1095 | cid = Player.PlayerData.citizenid,
1096 | callsign = Player.PlayerData.metadata.callsign
1097 | }
1098 | local callid = tonumber(callid)
1099 | local JobType = GetJobType(Player.PlayerData.job.name)
1100 | if JobType == 'police' or JobType == 'ambulance' then
1101 | if callid then
1102 | TriggerEvent('dispatch:removeUnit', callid, playerdata, function(newNum)
1103 | TriggerClientEvent('mdt:client:callDetach', -1, callid, newNum)
1104 | end)
1105 | end
1106 | end
1107 | end)
1108 |
1109 | RegisterNetEvent('mdt:server:setDispatchWaypoint', function(callid, cid)
1110 | local src = source
1111 | local Player = QBCore.Functions.GetPlayer(src)
1112 | local callid = tonumber(callid)
1113 | local JobType = GetJobType(Player.PlayerData.job.name)
1114 | if JobType == 'police' or JobType == 'ambulance' then
1115 | if callid then
1116 | local calls = exports['ps-dispatch']:GetDispatchCalls()
1117 | TriggerClientEvent('mdt:client:setWaypoint', src, calls[callid])
1118 | end
1119 | end
1120 |
1121 | end)
1122 |
1123 | RegisterNetEvent('mdt:server:callDragAttach', function(callid, cid)
1124 | local src = source
1125 | local Player = QBCore.Functions.GetPlayer(src)
1126 | local playerdata = {
1127 | name = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1128 | job = Player.PlayerData.job.name,
1129 | cid = Player.PlayerData.citizenid,
1130 | callsign = Player.PlayerData.metadata.callsign
1131 | }
1132 | local callid = tonumber(callid)
1133 | local JobType = GetJobType(Player.PlayerData.job.name)
1134 | if JobType == 'police' or JobType == 'ambulance' then
1135 | if callid then
1136 | TriggerEvent('dispatch:addUnit', callid, playerdata, function(newNum)
1137 | TriggerClientEvent('mdt:client:callAttach', -1, callid, newNum)
1138 | end)
1139 | end
1140 | end
1141 | end)
1142 |
1143 | RegisterNetEvent('mdt:server:setWaypoint:unit', function(cid)
1144 | local src = source
1145 | local Player = QBCore.Functions.GetPlayerByCitizenId(cid)
1146 | local PlayerCoords = GetEntityCoords(GetPlayerPed(Player.PlayerData.source))
1147 | TriggerClientEvent("mdt:client:setWaypoint:unit", src, PlayerCoords)
1148 | end)
1149 |
1150 | -- Dispatch chat
1151 |
1152 | RegisterNetEvent('mdt:server:sendMessage', function(message, time)
1153 | if message and time then
1154 | local src = source
1155 | local Player = QBCore.Functions.GetPlayer(src)
1156 | if Player then
1157 | MySQL.scalar("SELECT pfp FROM `mdt_data` WHERE cid=:id LIMIT 1", {
1158 | id = Player.PlayerData.citizenid -- % wildcard, needed to search for all alike results
1159 | }, function(data)
1160 | if data == "" then data = nil end
1161 | local ProfilePicture = ProfPic(Player.PlayerData.charinfo.gender, data)
1162 | local callsign = Player.PlayerData.metadata.callsign or "000"
1163 | local Item = {
1164 | profilepic = ProfilePicture,
1165 | callsign = Player.PlayerData.metadata.callsign,
1166 | cid = Player.PlayerData.citizenid,
1167 | name = '('..callsign..') '..Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1168 | message = message,
1169 | time = time,
1170 | job = Player.PlayerData.job.name
1171 | }
1172 | dispatchMessages[#dispatchMessages+1] = Item
1173 | TriggerClientEvent('mdt:client:dashboardMessage', -1, Item)
1174 | -- Send to all clients, for auto updating stuff, ya dig.
1175 | end)
1176 | end
1177 | end
1178 | end)
1179 |
1180 | RegisterNetEvent('mdt:server:refreshDispatchMsgs', function()
1181 | local src = source
1182 | local PlayerData = GetPlayerData(src)
1183 | if IsJobAllowedToMDT(PlayerData.job.name) then
1184 | TriggerClientEvent('mdt:client:dashboardMessages', src, dispatchMessages)
1185 | end
1186 | end)
1187 |
1188 | RegisterNetEvent('mdt:server:getCallResponses', function(callid)
1189 | local src = source
1190 | local Player = QBCore.Functions.GetPlayer(src)
1191 | if IsPolice(Player.PlayerData.job.name) then
1192 | local calls = exports['ps-dispatch']:GetDispatchCalls()
1193 | TriggerClientEvent('mdt:client:getCallResponses', src, calls[callid]['responses'], callid)
1194 | end
1195 | end)
1196 |
1197 | RegisterNetEvent('mdt:server:sendCallResponse', function(message, time, callid)
1198 | local src = source
1199 | local Player = QBCore.Functions.GetPlayer(src)
1200 | local name = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname
1201 | if IsPolice(Player.PlayerData.job.name) then
1202 | TriggerEvent('dispatch:sendCallResponse', src, callid, message, time, function(isGood)
1203 | if isGood then
1204 | TriggerClientEvent('mdt:client:sendCallResponse', -1, message, time, callid, name)
1205 | end
1206 | end)
1207 | end
1208 | end)
1209 |
1210 | RegisterNetEvent('mdt:server:setRadio', function(cid, newRadio)
1211 | local src = source
1212 | local Player = QBCore.Functions.GetPlayer(src)
1213 | if Player.PlayerData.citizenid ~= cid then
1214 | TriggerClientEvent("QBCore:Notify", src, 'You can only change your radio!', 'error')
1215 | return
1216 | else
1217 | local radio = Player.Functions.GetItemByName("radio")
1218 | if radio ~= nil then
1219 | TriggerClientEvent('mdt:client:setRadio', src, newRadio)
1220 | else
1221 | TriggerClientEvent("QBCore:Notify", src, 'You do not have a radio!', 'error')
1222 | end
1223 | end
1224 |
1225 | end)
1226 |
1227 | local function isRequestVehicle(vehId)
1228 | local found = false
1229 | for i=1, #impound do
1230 | if impound[i]['vehicle'] == vehId then
1231 | found = true
1232 | impound[i] = nil
1233 | break
1234 | end
1235 | end
1236 | return found
1237 | end
1238 | exports('isRequestVehicle', isRequestVehicle) -- exports['erp_mdt']:isRequestVehicle()
1239 |
1240 | RegisterNetEvent('mdt:server:impoundVehicle', function(sentInfo, sentVehicle)
1241 | local src = source
1242 | local Player = QBCore.Functions.GetPlayer(src)
1243 | if Player then
1244 | if GetJobType(Player.PlayerData.job.name) == 'police' then
1245 | if sentInfo and type(sentInfo) == 'table' then
1246 | local plate, linkedreport, fee, time = sentInfo['plate'], sentInfo['linkedreport'], sentInfo['fee'], sentInfo['time']
1247 | if (plate and linkedreport and fee and time) then
1248 | local vehicle = MySQL.query.await("SELECT id, plate FROM `player_vehicles` WHERE plate=:plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1") })
1249 | if vehicle and vehicle[1] then
1250 | local data = vehicle[1]
1251 | MySQL.insert('INSERT INTO `mdt_impound` (`vehicleid`, `linkedreport`, `fee`, `time`) VALUES (:vehicleid, :linkedreport, :fee, :time)', {
1252 | vehicleid = data['id'],
1253 | linkedreport = linkedreport,
1254 | fee = fee,
1255 | time = os.time() + (time * 60)
1256 | }, function(res)
1257 | local data = {
1258 | vehicleid = data['id'],
1259 | plate = plate,
1260 | beingcollected = 0,
1261 | vehicle = sentVehicle,
1262 | officer = Player.PlayerData.charinfo.firstname.. " "..Player.PlayerData.charinfo.lastname,
1263 | number = Player.PlayerData.charinfo.phone,
1264 | time = os.time() * 1000,
1265 | src = src,
1266 | }
1267 | local vehicle = NetworkGetEntityFromNetworkId(sentVehicle)
1268 | FreezeEntityPosition(vehicle, true)
1269 | impound[#impound+1] = data
1270 |
1271 | TriggerClientEvent("police:client:ImpoundVehicle", src, true, fee)
1272 | end)
1273 | end
1274 | end
1275 | end
1276 | end
1277 | end
1278 | end)
1279 |
1280 | RegisterNetEvent('mdt:server:getImpoundVehicles', function()
1281 | TriggerClientEvent('mdt:client:getImpoundVehicles', source, impound)
1282 | end)
1283 |
1284 | RegisterNetEvent('mdt:server:removeImpound', function(plate, currentSelection)
1285 | print("Removing impound", plate, currentSelection)
1286 | local src = source
1287 | local Player = QBCore.Functions.GetPlayer(src)
1288 | if Player then
1289 | if GetJobType(Player.PlayerData.job.name) == 'police' then
1290 | local result = MySQL.single.await("SELECT id, vehicle FROM `player_vehicles` WHERE plate=:plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1")})
1291 | if result and result[1] then
1292 | local data = result[1]
1293 | MySQL.update("DELETE FROM `mdt_impound` WHERE vehicleid=:vehicleid", { vehicleid = data['id'] })
1294 | TriggerClientEvent('police:client:TakeOutImpound', src, currentSelection)
1295 | end
1296 | end
1297 | end
1298 | end)
1299 |
1300 | RegisterNetEvent('mdt:server:statusImpound', function(plate)
1301 | local src = source
1302 | local Player = QBCore.Functions.GetPlayer(src)
1303 | if Player then
1304 | if GetJobType(Player.PlayerData.job.name) == 'police' then
1305 | local vehicle = MySQL.query.await("SELECT id, plate FROM `player_vehicles` WHERE plate=:plate LIMIT 1", { plate = string.gsub(plate, "^%s*(.-)%s*$", "%1")})
1306 | if vehicle and vehicle[1] then
1307 | local data = vehicle[1]
1308 | local impoundinfo = MySQL.query.await("SELECT * FROM `mdt_impound` WHERE vehicleid=:vehicleid LIMIT 1", { vehicleid = data['id'] })
1309 | if impoundinfo and impoundinfo[1] then
1310 | TriggerClientEvent('mdt:client:statusImpound', src, impoundinfo[1], plate)
1311 | end
1312 | end
1313 | end
1314 | end
1315 | end)
1316 |
1317 | RegisterServerEvent("mdt:server:AddLog", function(text)
1318 | AddLog(text)
1319 | end)
1320 |
1321 | function GetBoloStatus(plate)
1322 | local result = MySQL.query.await("SELECT * FROM mdt_bolos where plate = @plate", {['@plate'] = plate})
1323 | if result and result[1] then
1324 | return true
1325 | end
1326 |
1327 | return false
1328 | end
1329 |
1330 | function GetVehicleInformation(plate)
1331 | local result = MySQL.query.await('SELECT * FROM mdt_vehicleinfo WHERE plate = @plate', {['@plate'] = plate})
1332 | if result[1] then
1333 | return result[1]
1334 | else
1335 | return false
1336 | end
1337 | end
1338 |
1339 |
--------------------------------------------------------------------------------