diff --git a/resources/[qb]/[qb_jobs]/cad-diving/README.md b/resources/[qb]/[qb_jobs]/cad-diving/README.md new file mode 100644 index 0000000..99f5210 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-diving/README.md @@ -0,0 +1,2 @@ +# cad-diving +Sunken Ship Diving Script for QBCore (Legacy Inspired) diff --git a/resources/[qb]/[qb_jobs]/cad-diving/cl_diving.lua b/resources/[qb]/[qb_jobs]/cad-diving/cl_diving.lua new file mode 100644 index 0000000..e22a22b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-diving/cl_diving.lua @@ -0,0 +1,73 @@ +QBCore = exports['qb-core']:GetCoreObject() + +local locations = { + [1] = {x = 3144.94, y = -280.54, z = -10.31}, + [2] = {x = 3151.75, y = -286.02, z = -27.16}, + [3] = {x = 3127.14, y = -341.26, z = -23.14}, + [4] = {x = 3162.18, y = -357.39, z = -27.6}, + [5] = {x = 3195.47, y = -388.18, z = -32.16}, + [6] = {x = 3188.67, y = -395.82, z = -27.51}, + [7] = {x = 3221.45, y = -405.6, z = -48.48}, + [8] = {x = 3192.30, y = -385.23, z = -16.81}, +} + +local normal = { + [1] = {item = 'steel'}, + [2] = {item = 'iron'}, + [3] = {item = 'plastic'}, +} + +local rare = { + [1] = {item = 'goldbar'}, + [2] = {item = 'diamond'}, +} + +local pickup = math.random(1, #locations) + +Citizen.CreateThread(function() + Wait(1000) + CreateBlip() + while true do + inRange = false + x = locations[pickup].x + y = locations[pickup].y + z = locations[pickup].z + local playerPed = PlayerPedId() + local coords = GetEntityCoords(playerPed) + local distance = #(vector3(coords.x, coords.y, coords.z) - vector3(x, y, z)) + if distance < 250 then + inRange = true + if distance > 3 then + QBCore.Functions.DrawText3D(x, y, z, "Distance: "..(math.floor(distance*10)/10).."m") + else + pickup = math.random(1, #locations) + local random = math.random(1, 1000) + if random > 0 and random < 600 then + TriggerServerEvent("cad-diving:collected", "normal", normal[math.random(1,#normal)].item, math.random(1, 4)) + elseif random > 980 and random < 1000 then + TriggerServerEvent("cad-diving:collected", "rare", rare[math.random(1,#rare)].item, 1) + else + TriggerServerEvent("cad-diving:collected", "none", nil) + end + Citizen.Wait(2000) + end + end + if inRange then + Citizen.Wait(4) + else + Citizen.Wait(2000) + end + end +end) + +function CreateBlip() + local divingblip = AddBlipForCoord(3146.24, -280.84, -8.44) + SetBlipSprite(divingblip, 465) + SetBlipDisplay(diving, 4) + SetBlipScale(divingblip, 0.9) + SetBlipColour(divingblip, 3) + SetBlipAsShortRange(divingblip, true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString('Sunket skib') + EndTextCommandSetBlipName(divingblip) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/cad-diving/fxmanifest.lua b/resources/[qb]/[qb_jobs]/cad-diving/fxmanifest.lua new file mode 100644 index 0000000..562225c --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-diving/fxmanifest.lua @@ -0,0 +1,7 @@ +fx_version 'cerulean' +game "gta5" + +author "Cadburry#7547" + +client_script "cl_diving.lua" +server_script 'sv_diving.lua' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/cad-diving/sv_diving.lua b/resources/[qb]/[qb_jobs]/cad-diving/sv_diving.lua new file mode 100644 index 0000000..b34aa85 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-diving/sv_diving.lua @@ -0,0 +1,17 @@ +QBCore = exports['qb-core']:GetCoreObject() + +RegisterServerEvent("cad-diving:collected") +AddEventHandler("cad-diving:collected", function(type, item, count) + local xPlayer = QBCore.Functions.GetPlayer(source) + if xPlayer ~= nil then + if type == "normal" then + xPlayer.Functions.AddItem(item, count) + TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items[item], "add") + elseif type == "rare" then + xPlayer.Functions.AddItem(item, count) + TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items[item], "add") + else + TriggerClientEvent("QBCore:Notify", source, "Du fangede intet") + end + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/README.md b/resources/[qb]/[qb_jobs]/cad-postalop/README.md new file mode 100644 index 0000000..2b9cdb8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/README.md @@ -0,0 +1,15 @@ +# Postal Op Delivery Job +This is a job where you sign in near the postal op and put in a deposit for a truck which will be used to deliver packages to store, banks, etc + +# Dependencies +- qb-core +- qb-target +- PolyZone + +# How to install? +- Download latest version from releases +- Put in resources and ensure in server.cfg +- Thats all! + +# Support +Join Discord: https://discord.gg/qxGPARNwNP diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/client.lua b/resources/[qb]/[qb_jobs]/cad-postalop/client.lua new file mode 100644 index 0000000..7b80c3e --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/client.lua @@ -0,0 +1,283 @@ +local QBCore = exports['qb-core']:GetCoreObject() +--=================================================== +-- LOCALS +--=================================================== +local currentJob = {} +local onJob = false +local onDelivery = false +local goPostalVehicle = nil +local currentJobPay = 0 +local totalpayamount = 0 +local MaxDelivery = 0 +local PackageObject = nil +local missionblip = nil +local isDeliverySignedIn = false +local PlayerJob = {} +--=================================================== +-- CONFIG +--=================================================== +local locations = Config.deliveryLocations +local vehicleSpawnLocations = Config.vehicleSpawnLocations +--=================================================== +-- FUNCTIONS +--=================================================== +CreateThread(function() + local bCfg = Config.blip + PostalBlip = AddBlipForCoord(bCfg.coords) + SetBlipSprite(PostalBlip, bCfg.sprite) + SetBlipScale(PostalBlip, bCfg.scale) + SetBlipDisplay(PostalBlip, 4) + SetBlipColour(PostalBlip, bCfg.color) + SetBlipAsShortRange(PostalBlip, true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(bCfg.label) + EndTextCommandSetBlipName(PostalBlip) +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + PlayerJob = QBCore.Functions.GetPlayerData().job +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function() + PlayerJob = QBCore.Functions.GetPlayerData().job +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() == resourceName then + PlayerJob = QBCore.Functions.GetPlayerData().job + end +end) + +function NewDeliveryShift() + if MaxDelivery >= 0 then + local jobLocation = locations[math.random(1, #locations)] + SetDeliveryJobBlip(jobLocation[1], jobLocation[2], jobLocation[3]) + currentJob = jobLocation + currentJobPay = CalculateTravelDistanceBetweenPoints(GetEntityCoords(goPostalVehicle), currentJob[1], + currentJob[2], currentJob[3]) / 2 / 4 + if currentJobPay > 60 then + currentJobPay = math.random(1200, 1500) + end + QBCore.Functions.Notify("Kør til næste leverings punkt!") + else + onJob = false + RemoveJobBlip() + SetNewWaypoint(-425.44, -2787.76, 6.0) + QBCore.Functions.Notify("Du er færdig! Kør tilbage til depottet.") + end +end + +function SpawnGoPostal(x, y, z, h) + local vehicleHash = GetHashKey(Config.vehicleModel) + RequestModel(vehicleHash) + while not HasModelLoaded(vehicleHash) do + Wait(0) + end + goPostalVehicle = CreateVehicle(vehicleHash, x, y, z, h, true, false) + local id = NetworkGetNetworkIdFromEntity(goPostalVehicle) + SetNetworkIdCanMigrate(id, true) + SetNetworkIdExistsOnAllMachines(id, true) + SetVehicleDirtLevel(goPostalVehicle, 0) + SetVehicleHasBeenOwnedByPlayer(goPostalVehicle, true) + SetEntityAsMissionEntity(goPostalVehicle, true, true) + SetVehicleEngineOn(goPostalVehicle, true) + SetVehicleColours(goPostalVehicle, 131, 74) + TaskWarpPedIntoVehicle(PlayerPedId(), goPostalVehicle, -1) + TriggerEvent('vehiclekeys:client:SetOwner', GetVehicleNumberPlateText(goPostalVehicle)) + exports['qb-fuel']:SetFuel(goPostalVehicle, 100.0) +end + +function getParkingPosition(spots) + for id, v in pairs(spots) do + if GetClosestVehicle(v.x, v.y, v.z, 3.0, 0, 70) == 0 then + return true, v + end + end + QBCore.Functions.Notify("Parkeringspladsen er fuld, vent venligst.") +end + +function SetDeliveryJobBlip(x, y, z) + if DoesBlipExist(missionblip) then RemoveBlip(missionblip) end + missionblip = AddBlipForCoord(x, y, z) + SetBlipSprite(missionblip, 164) + SetBlipColour(missionblip, 53) + SetNewWaypoint(x, y) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Destination") + EndTextCommandSetBlipName(missionblip) +end + +function RemoveJobBlip() + if DoesBlipExist(missionblip) then RemoveBlip(missionblip) end +end + +function LoadAnim(animDict) + RequestAnimDict(animDict) + while not HasAnimDictLoaded(animDict) do + Wait(10) + end +end + +function LoadModel(model) + RequestModel(model) + while not HasModelLoaded(model) do + Wait(10) + end +end + +--=================================================== +-- JOB WORK +--=================================================== + +CreateThread(function() + local pedModel = GetHashKey(Config.pedModel) + RequestModel(pedModel) + while not HasModelLoaded(pedModel) do + Wait(1) + end + local ped = CreatePed(4, pedModel, Config.pedCoords.x, Config.pedCoords.y, Config.pedCoords.z, + Config.pedCoords.w, false, false) + SetBlockingOfNonTemporaryEvents(ped, true) + SetPedDiesWhenInjured(ped, false) + SetEntityHeading(ped, Config.pedCoords.w) + SetPedCanPlayAmbientAnims(ped, true) + SetPedCanRagdollFromPlayerImpact(ped, false) + SetEntityInvincible(ped, true) + FreezeEntityPosition(ped, true) + + if PlayerJob.name == Config.JobName then + exports['qb-target']:AddTargetModel('s_m_m_postal_01', { + options = { + { + type = "client", + event = "cad-postalop:startwork", + icon = "fas fa-sign-in-alt", + label = "Gå på arbejde", + canInteract = function(entity, data) + return not isDeliverySignedIn + end, + }, + { + type = "client", + event = "cad-postalop:finishwork", + icon = "fas fa-money-check-alt", + label = "Modtag løn og afslut arbejde", + canInteract = function(entity, data) + return isDeliverySignedIn + end, + }, + }, + distance = 1.5 + }) + end + exports['qb-target']:AddTargetBone('boot', { + options = { + { + type = "client", + event = "cad-postalop:takepackage", + icon = "fas fa-box", + label = "Tag pakke", + canInteract = function(entity, data) + return onJob and (entity == goPostalVehicle) + end, + } + }, + distance = 2.5, + }) + +end) + +CreateThread(function() + while true do + local inRange = false + if isDeliverySignedIn then + if (GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId()), currentJob[1], currentJob[2], currentJob[3], true) < 50) and onJob and onDelivery then + inRange = true + DrawMarker(2, currentJob[1], currentJob[2], currentJob[3], 0, 0, 0, 0, 0, 0, 0.3, 0.2, -0.2, 100, 100, + 155, 255, true, true, 0, 0) + if (GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId()), currentJob[1], currentJob[2], currentJob[3], true) < 1.5) and onJob and onDelivery then + LoadAnim("creatures@rottweiler@tricks@") + TaskPlayAnim(PlayerPedId(), "creatures@rottweiler@tricks@", "petting_franklin", 8.0, 8.0, -1, 50, 0, + false, false, false) + FreezeEntityPosition(PlayerPedId(), true) + Wait(5000) + DeleteObject(PackageObject) + FreezeEntityPosition(PlayerPedId(), false) + ClearPedTasksImmediately(PlayerPedId()) + PackageObject = nil + onDelivery = false + totalpayamount = totalpayamount + currentJobPay + MaxDelivery = MaxDelivery - 1 + NewDeliveryShift() + end + end + end + if not inRange then + Wait(1000) + end + Wait(4) + end +end) + +RegisterNetEvent('cad-postalop:startwork', function() + if not isDeliverySignedIn and not onJob then + if not DoesEntityExist(goPostalVehicle) then + local freespot, v = getParkingPosition(vehicleSpawnLocations) + if freespot then SpawnGoPostal(v.x, v.y, v.z, v.h) end + MaxDelivery = math.random(2, 8) + NewDeliveryShift() + onJob = true + isDeliverySignedIn = true + else + QBCore.Functions.Notify("Du har allerede et køretøj!") + end + else + QBCore.Functions.Notify("Du er allerede igang med et job, færdiggør det først.") + end +end) + +RegisterNetEvent('cad-postalop:takepackage', function() + if not onDelivery and onJob and not IsPedInAnyVehicle(PlayerPedId()) and GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId()), currentJob[1], currentJob[2], currentJob[3], true) < 40 then + LoadModel("hei_prop_heist_box") + local pos = GetEntityCoords(PlayerPedId(), false) + PackageObject = CreateObject(GetHashKey("hei_prop_heist_box"), pos.x, pos.y, pos.z, true, true, true) + AttachEntityToEntity(PackageObject, PlayerPedId(), GetPedBoneIndex(PlayerPedId(), 28422), 0.0, -0.03, 0.0, 5.0, + 0.0, 0.0, 1, 1, 0, 1, 0, 1) + LoadAnim("anim@heists@box_carry@") + TaskPlayAnim(PlayerPedId(), "anim@heists@box_carry@", "idle", 8.0, 8.0, -1, 50, 0, false, false, false) + onDelivery = true + end +end) + +RegisterNetEvent('cad-postalop:finishwork', function() + if isDeliverySignedIn then + if not onJob then + if DoesEntityExist(goPostalVehicle) then + DeleteVehicle(goPostalVehicle) + RemoveJobBlip() + if IsVehicleDamaged(goPostalVehicle) then + totalpayamount = totalpayamount - 1000 + QBCore.Functions.Notify("Din lastbil blev beskadiget, du er blevet trukket 1000,- for at dække skaderne.") + end + isDeliverySignedIn = false + onJob = false + TriggerServerEvent('cad-delivery:cash', totalpayamount, 0) + Wait(500) + totalpayamount = 0 + else + isDeliverySignedIn = false + onJob = false + QBCore.Functions.Notify("Den lastbil var altså dyr... Du får ingen løn denne omgang.") + end + else + QBCore.Functions.Notify("Du er nødt til at afslutte dit job først.") + end + else + QBCore.Functions.Notify("Gå på arbejde før du kan få dine penge!") + end +end) + + +--=================================================== +-- END +--===================================================s diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/config.lua b/resources/[qb]/[qb_jobs]/cad-postalop/config.lua new file mode 100644 index 0000000..a599acf --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/config.lua @@ -0,0 +1,44 @@ +Config = {} + +Config.blip = { + label = 'HPNord', + coords = vector3(-425.44, -2787.76, 6.0), + sprite = 304, + scale = 0.5, + color = 10 +} + +Config.JobName = "delivery" +Config.pedModel = 's_m_m_postal_01' +Config.pedCoords = vector4(-425.44, -2787.76, 5.0, 326.65) + +Config.vehicleModel = 'benson' + +Config.vehicleSpawnLocations = { + { x = -446.24, y = -2789.72, z = 5.96, h = 46.04 }, + { x = -451.24, y = -2793.8, z = 5.96, h = 47.51 }, + { x = -455.8, y = -2798.48, z = 5.96, h = 44.91 } +} + +Config.deliveryLocations = { + [1] = { 441.12, -981.12, 30.68 }, + [2] = { 306.72, -594.88, 43.28 }, + [3] = { -37.2, -1110.36, 26.44 }, + [4] = { -267.08, -955.64, 31.24 }, + [5] = { -1200.36, -891.12, 14.0 }, + [6] = { -705.72, -906.68, 19.2 }, + [7] = { 26.04, -1339.24, 29.48 }, + [8] = { -41.52, -1752.52, 29.44 }, + [9] = { -534.64, -165.96, 38.32 }, + [10] = { -633.08, 233.88, 81.88 }, + [11] = { 246.92, 222.2, 106.28 }, + [12] = { 375.64, 333.72, 103.56 }, + [13] = { 314.48, -278.6, 54.16 }, + [14] = { 149.44, -1040.0, 29.36 }, + [15] = { -1081.96, -248.24, 37.76 }, + [16] = { -350.76, -48.84, 49.04 }, + [17] = { -1484.2, -380.24, 40.16 }, + [18] = { 2550.24, 382.0, 108.64 }, + [19] = { -1816.56, -1193.48, 14.32 }, + [20] = { -2966.64, 388.0, 15.04 }, +} diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/fxmanifest.lua b/resources/[qb]/[qb_jobs]/cad-postalop/fxmanifest.lua new file mode 100644 index 0000000..e61442a --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/fxmanifest.lua @@ -0,0 +1,19 @@ +fx_version 'cerulean' +game "gta5" +lua54 'yes' + +author "Cadburry" +description "Postal Op Job which uses qb-target & polyzone" +version "1.1" + +shared_scripts { + 'config.lua', +} +server_script 'server.lua' +client_script 'client.lua' + +files { + 'handling.meta', +} + +data_file 'HANDLING_FILE' 'handling.meta' diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/handling.meta b/resources/[qb]/[qb_jobs]/cad-postalop/handling.meta new file mode 100644 index 0000000..0f51875 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/handling.meta @@ -0,0 +1,62 @@ + + + + + benson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 224048 + 0 + 0 + TRUCK + + + + + + + + \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/cad-postalop/server.lua b/resources/[qb]/[qb_jobs]/cad-postalop/server.lua new file mode 100644 index 0000000..c971336 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/cad-postalop/server.lua @@ -0,0 +1,18 @@ +local QBCore = exports['qb-core']:GetCoreObject() +--=================================================== +-- JOB CASH +--=================================================== +RegisterNetEvent('cad-delivery:cash', function(currentJobPay, value) + local _source = source + local Player = QBCore.Functions.GetPlayer(_source) + local job = Player.PlayerData.job.name + if value ~= 0 then + --User triggering anti-cheat + DropPlayer(_source, "Anti-cheat triggered") + else + if job == Config.JobName then + Player.Functions.AddMoney("bank", currentJobPay, "HPNord Indbetaling") + TriggerClientEvent("QBCore:Notify", _source, "Du modtog en indbetaling på " .. currentJobPay..",-") + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/.gitignore b/resources/[qb]/[qb_jobs]/keep-oilwell/.gitignore new file mode 100644 index 0000000..cb13fa4 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/.gitignore @@ -0,0 +1,2 @@ +/test +watch.cjs \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/LICENSE b/resources/[qb]/[qb_jobs]/keep-oilwell/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/README.md b/resources/[qb]/[qb_jobs]/keep-oilwell/README.md new file mode 100644 index 0000000..e225b8b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/README.md @@ -0,0 +1,223 @@ +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/banner3.png) + +# Preview + +- [Youtube video](https://youtu.be/lGgsUonmXmw) + +# Dependencies + +- [qb-target](https://github.com/BerkieBb/qb-target) +- [qb-menu](https://github.com/qbcore-framework/qb-menu) + +# Key Features + +- NoPixel inspired oil company +- Owning oilwells +- ... + +## Patch 1.1.0 (employees) + +- new notifications when an oilwell part breaks. +- oilwell owners can employ a person to operate their oilwells for them. (employees have access to crude oil transfer, but when they use it, it sends available oil to the owner's storage, not the employee's storage.) +- employees should have `oilwell` job. +- owners can fire their employees at will employees access will be revoked immediately. +- removed some data which should not be available on client-side. +- added script loading report. +- the CEO have ability to remove any oilwell from now on (this is not a permanent removal therefore oil wells are just flagged as deleted for easy recovery). +- information menu is now recives data directly from server. + +### How to update to new patch (database changes): + +- 1. update your `oilrig_position` by using ALTER TABLE available at end of sql.sql +- 2. import new table `oilcompany_employees` + +## Patch 1.0.0 + +- (important) if you are using old version make sure you have a backup. + +- balanced oil production for 1 hour +- to be able to operate oilwells players must be on duty +- oilwells now take damege and players should fix them or they will stop working +- new items to fix oilwells +- transport accepts all oil types +- new oil types +- blender new formula and new elemnts +- qb-target won't despawn with objects +- fixed qb-target not showing up +- fixed props blinking +- fixed props not spawning if players don't have oilwell job +- better check for job and onduty +- new withdraw system +- withdraw purge menu +- added octane calculation +- showing oilwell prop before assigning them +- oilbarell props +- to be honest there was so many changes i don't remember most of them! + +## Usage + +- add oilwell by "/create oilwell" and then place and asign it to a player. (admins) +- or use 'oilwell' item to spawn oilwell + +## Installation + +## Step 0: + +- import sql.sql in your database + +## Step 1: + +\*\* qb-core shared items.lua + +```lua +["oilbarell"] = { + ["name"] = "oilbarell", + ["label"] = "Oil barell", + ["weight"] = 15000, + ["type"] = "item", + ["image"] = "oilBarrel.png", + ["unique"] = true, + ["useable"] = false, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oil Barrel" +}, +["oilwell"] = { + ["name"] = "oilwell", + ["label"] = "Oilwell", + ["weight"] = 50000, + ["type"] = "item", + ["image"] = "oilwell.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oilwell" +}, +["reliefvalvestring"] = { + ["name"] = "reliefvalvestring", + ["label"] = "Relief Valve String", + ["weight"] = 4000, + ["type"] = "item", + ["image"] = "relief_valve_string.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Relief Valve String" +}, +["oilfilter"] = { + ["name"] = "oilfilter", + ["label"] = "Oil Filter", + ["weight"] = 5000, + ["type"] = "item", + ["image"] = "oil_filter.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oil Filter" +}, +["skewgear"] = { + ["name"] = "skewgear", + ["label"] = "Skew Gear", + ["weight"] = 6000, + ["type"] = "item", + ["image"] = "skew_gear.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Skew Gear" +}, +["timingchain"] = { + ["name"] = "timingchain", + ["label"] = "Timing Chain", + ["weight"] = 7000, + ["type"] = "item", + ["image"] = "timing_chain.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Timing Chain" +}, +["driveshaft"] = { + ["name"] = "driveshaft", + ["label"] = "Drive Shaft", + ["weight"] = 5000, + ["type"] = "item", + ["image"] = "drive_shaft.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Drive Shaft" +}, + +``` + +## Step 2: + +\*\* qb-core shared jobs.lua + +```lua +['oilwell'] = { + label = 'Oil Company', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Oilwell Operator', + payment = 50 + }, + ['1'] = { + name = 'Oilwell Operator tier 2', + payment = 75 + }, + ['2'] = { + name = 'Event Driver tier 2', + payment = 100 + }, + ['3'] = { + name = 'Sales', + payment = 125 + }, + ['4'] = { + name = 'CEO', + isboss = true, + payment = 150 + }, + }, +}, +``` + +## Step 3: tooltip + +- in qb-inventory\js\app.js find FormatItemInfo() there is if statement like: if (itemData.name == "id_card") +- track where all of elseif statments are ended then add code below. + +```javascript +else if (itemData.name == "oilbarell") { + $(".item-info-title").html("

" + itemData.label + "

"); + $(".item-info-description").html("

Gal: " + itemData.info.gal + "

" + "

Type: " + itemData.info.type + "

" + "

Octane: " + itemData.info.avg_gas_octane + "

"); +} +``` + +# Support + +- [Discord](https://discord.gg/ccMArCwrPV) + +# Donation + +- [Donation](https://swkeep.github.io) + +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_00_11-000275.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_00_18-000276.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_00_34-000277.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_00_46-000278.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_00_50-000279.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_01_04-000280.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_01_09-000281.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_01_11-000282.jpg) +![Keep oilwell](https://raw.githubusercontent.com/swkeep/keep-oilwell/main/.github/images/screenshots/2022-05-17-16_01_13-000283.jpg) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client.lua new file mode 100644 index 0000000..830d74f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client.lua @@ -0,0 +1,407 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +PlayerJob = {} +OnDuty = nil +OBJECT = nil +local rigmodel = GetHashKey('p_oil_pjack_03_s') + +function CheckJob() + return (PlayerJob.name == 'oilwell') +end + +function CheckOnduty() + return (PlayerJob.name == 'oilwell' and PlayerJob.onduty) +end + +-- class +OilRigs = { + dynamicSpawner_state = false, + data_table = {}, -- this table holds oilwells data and defined by server + core_entities = {} -- this table holds objects that has some functions to them and filled by dynamic spawner +} + +function OilRigs:add(s_res, id) + if self.data_table[id] ~= nil then + return + end + self.data_table[id] = {} + self.data_table[id] = s_res + if self.data_table[id].isOwner == true then + local blip_settings = Oilwell_config.Settings.oil_well.blip + blip_settings.type = 'oil_well' + blip_settings.id = id + self.data_table[id].blip_handle = createCustom(self.data_table[id].position.coord, blip_settings) + end +end + +function OilRigs:update(s_res, id) + if self.data_table[id] == nil then return end + s_res.entity = self.data_table[id].entity + s_res.Qbtarget = self.data_table[id].Qbtarget + self.data_table[id] = s_res + QBCore.Functions.TriggerCallback('keep-oilwell:server:oilwell_metadata', function(metadata) + self:syncSpeed(self.data_table[id].entity, metadata.speed) + end, self.data_table[id].oilrig_hash) +end + +function OilRigs:startUpdate(cb) + QBCore.Functions.TriggerCallback('keep-oilrig:server:getNetIDs', function(result) + for key, value in pairs(result) do + self:update(value, key) + Wait(15) + end + cb(true) + end) +end + +function OilRigs:syncSpeed(entity, speed) + local anim_speed = Round((speed / Oilwell_config.AnimationSpeedDivider), 2) + SetEntityAnimSpeed(entity, 'p_v_lev_des_skin', 'p_oil_pjack_03_s', anim_speed + .0) +end + +function OilRigs:getById(id) + for key, value in pairs(self.data_table) do + if value.id == id then + return value + end + end + return false +end + +function OilRigs:getByEntityHandle(handle) + for key, value in pairs(self.data_table) do + if value.entity == handle then + return value + end + end + return false +end + +function OilRigs:readAll() + return self.data_table +end + +function OilRigs:DynamicSpawner() + self.dynamicSpawner_state = true + local object_spawn_distance = 125.0 + + CreateThread(function() + -- create core blips + Wait(50) + for index, value in pairs(Oilwell_config.locations) do + value.blip.type = index + if not value.blip.handle and PlayerJob.name == 'oilwell' then + value.blip.handle = createCustom(value.position, value.blip) + end + if not value.qbtarget then + Add_3rd_eye(value.position, index) + value.qbtarget = true + end + end + + for _, oilwell in pairs(self.data_table) do + if not oilwell.qbtarget then + local c = oilwell.position.coord + local coord = vector3(c.x, c.y, c.z) + createOwnerQbTarget(oilwell.oilrig_hash, coord) + oilwell.qbtarget = true + end + end + + while self.dynamicSpawner_state do + local pedCoord = GetEntityCoords(PlayerPedId()) + -- oilwells/pumps + for index, value in pairs(self.data_table) do + local c = value.position.coord + c = vector3(c.x, c.y, c.z) + local distance = #(c - pedCoord) + if distance < object_spawn_distance and self.data_table[index].entity == nil then + self.data_table[index].entity = spawnObjects(rigmodel, self.data_table[index].position) + QBCore.Functions.TriggerCallback('keep-oilwell:server:oilwell_metadata', function(metadata) + self:syncSpeed(self.data_table[index].entity, metadata.speed) + end, self.data_table[index].oilrig_hash) + elseif distance > object_spawn_distance and self.data_table[index].entity ~= nil then + DeleteEntity(self.data_table[index].entity) + self.data_table[index].entity = nil + end + end + + for index, value in pairs(Oilwell_config.locations) do + local position = vector3(value.position.x, value.position.y, value.position.z) + local distance = #(position - pedCoord) + if self.core_entities[index] == nil then + self.core_entities[index] = {} + end + if distance < object_spawn_distance and self.core_entities[index].entity == nil then + self.core_entities[index].entity = spawnObjects(value.model, { + coord = { x = position.x, y = position.y, z = position.z, }, + rotation = { x = value.rotation.x, y = value.rotation.y, z = value.rotation.z, } + }) + elseif distance > object_spawn_distance and self.core_entities[index].entity ~= nil then + DeleteEntity(self.core_entities[index].entity) + self.core_entities[index].entity = nil + end + end + Wait(1250) + end + end) +end + +function OilRigs:Flush_Entities() + for _, oilwell in pairs(self.data_table) do + if oilwell.entity then + DeleteObject(oilwell.entity) + end + RemoveBlip(oilwell.blip_handle) + end + self.dynamicSpawner_state = false + Wait(5) + self.data_table = {} +end + +-- +RegisterNetEvent('keep-oilrig:client:changeRigSpeed', function(qbtarget) + if not CheckJob() then + QBCore.Functions.Notify('Du er ikke hyret af et oliefirma', "error") + return false + end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + return false + end + local rig = OilRigs:getByEntityHandle(qbtarget.entity) + if not rig then + return --print('oilwell not found') + end + QBCore.Functions.TriggerCallback('keep-oilwell:server:oilwell_metadata', function(metadata) + OilRigs:startUpdate(function() + + local inputData = exports['qb-input']:ShowInput({ + header = "Skift hastighed", + submitText = "change", + inputs = { + { + type = 'text', + isRequired = true, + name = 'Hastighed', + text = 'Nuværrende hastighed ' .. metadata.speed + }, + } + }) + if inputData then + local speed = tonumber(inputData.speed) + if not inputData.speed then + return + end + if not (0 <= speed and speed <= 100) then + QBCore.Functions.Notify('Hastighed skal være mellem 0-100', "error") + return + end + QBCore.Functions.Notify('Hanstighed er nu ' .. speed, "success") + TriggerServerEvent('keep-oilrig:server:updateSpeed', inputData, rig.id) + end + end) + end, rig.oilrig_hash) +end) + +local function loadData() + OilRigs:Flush_Entities() + QBCore.Functions.GetPlayerData(function(PlayerData) + PlayerJob = PlayerData.job + OnDuty = PlayerData.job.onduty + QBCore.Functions.TriggerCallback('keep-oilrig:server:getNetIDs', function(result) + for key, value in pairs(result) do + OilRigs:add(value, key) + end + + OilRigs:DynamicSpawner() + end) + end) +end + +RegisterNetEvent('keep-oilrig:client:syncSpeed', function(id, speed) + local rig = OilRigs:getById(id) + if rig then + OilRigs:syncSpeed(rig.entity, speed) + end +end) + +function spawnObjects(model, position) + TriggerEvent('keep-oilrig:client:clearArea', position.coord) + -- every oilwell exist only on client side! + local entity = CreateObject(model, position.coord.x, position.coord.y, position.coord.z, 0, 0, 0) + while not DoesEntityExist(entity) do Wait(10) end + SetEntityRotation(entity, position.rotation.x, position.rotation.y, position.rotation.z, 0.0, true) + FreezeEntityPosition(entity, true) + SetEntityProofs(entity, 1, 1, 1, 1, 1, 1, 1, 1) + return entity +end + +-- -------------------------------------------------------------- + +RegisterNetEvent('keep-oilrig:client:spawn') +AddEventHandler('keep-oilrig:client:spawn', function() + local coords = ChooseSpawnLocation() + QBCore.Functions.TriggerCallback('keep-oilrig:server:createNewOilrig', function(NetId) + if NetId ~= nil then + local entity = NetworkGetEntityFromNetworkId(NetId) + OBJECT = entity + exports['qb-target']:AddEntityZone("oil-rig-" .. entity, entity, { + name = "oil-rig-" .. entity, + heading = GetEntityHeading(entity), + debugPoly = false, + }, { + options = { + { + type = "client", + event = "keep-oilrig:client:enterInformation", + icon = "fa-regular fa-file-lines", + label = "Tildel personel", + canInteract = function(entity) + if not CheckJob() then return false end + if not (PlayerJob.grade.level == 4) then + TriggerEvent('QBCore:Notify', 'Du skal være på job!', "error") + Wait(2000) + return false + end + if not CheckOnduty() then + TriggerEvent('QBCore:Notify', 'Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + { + type = "client", + event = "keep-oilwell:menu:OPENMENU", + icon = "fa-regular fa-file-lines", + label = "Adjust position", + canInteract = function(entity) + if not CheckJob() then + TriggerEvent('QBCore:Notify', 'Kun chefen kan dette', "error") + Wait(2000) + return false + end + if not (PlayerJob.grade.level == 4) then + TriggerEvent('QBCore:Notify', 'Kun chefen kan dette', "error") + Wait(2000) + return false + end + if not CheckOnduty() then + TriggerEvent('QBCore:Notify', 'Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 2.5 + }) + end + end, coords) +end) + + +RegisterNetEvent('keep-oilrig:client:enterInformation', function(qbtarget) + local inputData = exports['qb-input']:ShowInput({ + header = "Tildel oliebrønd: ", + submitText = "Tildel", + inputs = { { + type = 'text', + isRequired = true, + name = 'Navn', + text = "Navn på oliebrønd" + }, + { + type = 'number', + isRequired = true, + name = 'BorgerID', + text = "Borgerens ID" + }, + } + }) + if inputData then + if not inputData.name and not inputData.cid then + return + end + local netId = NetworkGetNetworkIdFromEntity(qbtarget.entity) + + inputData.netId = netId + QBCore.Functions.TriggerCallback('keep-oilrig:server:regiserOilrig', function(result) + DeleteEntity(qbtarget.entity) + if result == true then + Wait(1500) + QBCore.Functions.Notify('Registrerer oliebrønd til: ' .. inputData.cid, "success") + loadData() + end + end, inputData) + end +end) + +RegisterNetEvent('keep-oilwell:client:force_reload', function() + Wait(25) + loadData() +end) + +AddEventHandler('onResourceStart', function(resourceName) + if (GetCurrentResourceName() ~= resourceName) then + return + end + Wait(500) + + QBCore.Functions.GetPlayerData(function(PlayerData) + PlayerJob = PlayerData.job + OnDuty = PlayerData.job.onduty + loadData() + end) + StartBarellAnimation() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + Wait(3000) + QBCore.Functions.GetPlayerData(function(PlayerData) + PlayerJob = PlayerData.job + OnDuty = PlayerData.job.onduty + loadData() + end) + StartBarellAnimation() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + OilRigs.dynamicSpawner_state = false +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + PlayerJob = JobInfo + OnDuty = PlayerJob.onduty + loadData() +end) + +RegisterNetEvent('QBCore:Client:SetDuty', function(duty) + OnDuty = duty + loadData() +end) + +RegisterNetEvent('keep-oilrig:client:local_mail_sender', function(data) + local Lang = Oilwell_config.Locale + Lang.mail.message = string.format(Lang.mail.message, data.gender, data.charinfo.lastname, data.money, data.amount, + data.refund) + TriggerServerEvent('qb-phone:server:sendNewMail', { + sender = Lang.mail.sender, + subject = Lang.mail.subject, + message = Lang.mail.message, + button = {} + }) +end) + +RegisterNetEvent('keep-oilwell:server_lib:AddExplosion', function(bullding_type) + local c = Oilwell_config.locations[bullding_type].position + local t = 0 + for i = 1, 5, 1 do + AddExplosion(c.x, c.y, c.z + 0.5, 9, 10.0, true, false, true) + t = t + 1000 + Wait(t) + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/client_lib_entry.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/client_lib_entry.lua new file mode 100644 index 0000000..4db940d --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/client_lib_entry.lua @@ -0,0 +1,203 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +function isOwner(entity) + local oilrig = OilRigs:getByEntityHandle(entity) + if not oilrig then + return --print('failed to get oilwell') + end + local is_employee = nil + local is_owner = nil + -- await didn't work! + QBCore.Functions.TriggerCallback('keep-oilwell:server:is_employee', function(_is_employee, _is_owner) + is_employee, is_owner = _is_employee, _is_owner + end, oilrig.oilrig_hash) + for i = 1, 5, 1 do + if is_employee ~= nil then + break + end + Wait(50) + end + return is_employee, is_owner +end + +local function Draw2DText(content, font, colour, scale, x, y) + SetTextFont(font) + SetTextScale(scale, scale) + SetTextColour(colour[1], colour[2], colour[3], 255) + SetTextEntry("STRING") + SetTextDropShadow(0, 0, 0, 0, 255) + SetTextDropShadow() + SetTextEdge(4, 0, 0, 0, 255) + SetTextOutline() + AddTextComponentString(content) + DrawText(x, y) +end + +local function RotationToDirection(rotation) + local adjustedRotation = { + x = (math.pi / 180) * rotation.x, + y = (math.pi / 180) * rotation.y, + z = (math.pi / 180) * rotation.z + } + local direction = { + x = -math.sin(adjustedRotation.z) * + math.abs(math.cos(adjustedRotation.x)), + y = math.cos(adjustedRotation.z) * + math.abs(math.cos(adjustedRotation.x)), + z = math.sin(adjustedRotation.x) + } + return direction +end + +local function RayCastGamePlayCamera(distance) + local cameraRotation = GetGameplayCamRot() + local cameraCoord = GetGameplayCamCoord() + local direction = RotationToDirection(cameraRotation) + local destination = { + x = cameraCoord.x + direction.x * distance, + y = cameraCoord.y + direction.y * distance, + z = cameraCoord.z + direction.z * distance + } + local a, b, c, d, e = GetShapeTestResult( + StartShapeTestRay(cameraCoord.x, cameraCoord.y, + cameraCoord.z, destination.x, + destination.y, destination.z, + -1, PlayerPedId(), 0)) + return c, e +end + +function ChooseSpawnLocation() + local plyped = PlayerPedId() + local pedCoord = GetEntityCoords(plyped) + local activeLaser = true + local oilrig = CreateObject(GetHashKey('p_oil_pjack_03_s'), pedCoord.x, pedCoord.y, pedCoord.z, 1, 1, 0) + SetEntityAlpha(oilrig, 150, true) + + while activeLaser do + Wait(0) + local color = { + r = 2, + g = 241, + b = 181, + a = 200 + } + local position = GetEntityCoords(plyped) + local coords, entity = RayCastGamePlayCamera(1000.0) + Draw2DText('Tryk ~g~E~w~ for at placere oliebrønd', 4, { 255, 255, 255 }, 0.4, 0.43, + 0.888 + 0.025) + if IsControlJustReleased(0, 38) then + activeLaser = false + DeleteEntity(oilrig) + return coords + end + DrawLine(position.x, position.y, position.z, coords.x, coords.y, + coords.z, color.r, color.g, color.b, color.a) + SetEntityCollision(oilrig, false, false) + SetEntityCoords(oilrig, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0) + end +end + +function createCustom(coord, o) + local blip = AddBlipForCoord( + coord.x, + coord.y, + coord.z + ) + SetBlipSprite(blip, o.sprite) + SetBlipColour(blip, o.colour) + if o.range == 'short' then + SetBlipAsShortRange(blip, true) + else + SetBlipAsShortRange(blip, false) + end + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(replaceString(o)) + EndTextCommandSetBlipName(blip) + return blip +end + +function replaceString(o) + local s = o.name + if o.id ~= nil then + -- oilwells + local oilrig = OilRigs:getById(o.id) + s = s:gsub("OILWELLNAME", oilrig.name) + s = s:gsub("OILWELL_HASH", oilrig.oilrig_hash) + s = s:gsub("DB_ID_RAW", o.id) + s = s:gsub("TYPE", o.type) + + else + s = s:gsub("TYPE", o.type) + end + return s +end + +function createOwnerQbTarget(hash, coord) + exports['qb-target']:RemoveZone("oil-rig-" .. hash) + Targets.qb_target.oilwell(coord, hash) +end + +RegisterNetEvent('keep-oilwell:client:remove_oilwell', function(data) + local oilwell = OilRigs:getByEntityHandle(data.entity) + for i = 1, 3, 1 do + local value = RandomHash(4) + local inputData = exports['qb-input']:ShowInput({ + header = 'Gentag: ' .. value .. '', + inputs = { + { + type = 'text', + isRequired = true, + name = 'Gentag', + text = '' + }, + } + }) + if not inputData then + QBCore.Functions.Notify('Annulleret', "primary") + return + end + if inputData.RandomHash ~= value then + QBCore.Functions.Notify('Fejlede', "primary") + return + end + end + TriggerServerEvent('keep-oilwell:server:remove_oilwell', oilwell.oilrig_hash) +end) + +function Add_3rd_eye(coord, Type) + local key = Type + if key == 'storage' then + Targets.qb_target.storage(coord, key) + elseif key == 'distillation' then + Targets.qb_target.distillation(coord, key) + elseif key == 'blender' then + Targets.qb_target.blender(coord, key) + elseif key == 'barrel_withdraw' then + Targets.qb_target.barrel_withdraw(coord, key) + elseif key == 'crude_oil_transport' then + Targets.qb_target.crude_oil_transport(coord, key) + elseif key == 'toggle_job' then + Targets.qb_target.toggle_job(coord, key) + end +end + +---force remove objects in area +---@param coord table +RegisterNetEvent('keep-oilrig:client:clearArea', function(coord) + ClearAreaOfObjects(coord.x, coord.y, coord.z, 5.0, 1) +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(PlayerJob) + if CheckJob() then + OnDuty = CheckOnduty() + end +end) + +RegisterNetEvent('keep-oilrig:client:goOnDuty', function(PlayerJob) + TriggerServerEvent("QBCore:ToggleDuty") + if CheckJob() and CheckOnduty() == false then + OnDuty = true + else + OnDuty = false + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/CDU_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/CDU_menu.lua new file mode 100644 index 0000000..36778d7 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/CDU_menu.lua @@ -0,0 +1,122 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local function showCDU(data) + if not data then return end + local state = '' + if data.metadata.state == true then + state = 'Aktiv' + else + state = 'Inaktiv' + end + local header = "Råoile destilations-enhed (" .. state .. ')' + -- header + local CDU_Temperature = data.metadata.temp + local CDU_Gal = data.metadata.oil_storage + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-gear' + }, { + header = 'Temperatur', + icon = 'fa-solid fa-temperature-high', + txt = "" .. CDU_Temperature .. " °C", + }, + { + header = 'Råoile i CDU', + icon = 'fa-solid fa-oil-can', + txt = CDU_Gal .. " Liter", + }, + { + header = 'Pump råoile til CDU', + icon = 'fa-solid fa-arrows-spin', + params = { + event = "keep-oilrig:CDU_menu:pumpCrudeOil_to_CDU" + } + }, + { + header = 'Skift temperatur', + icon = 'fa-solid fa-temperature-arrow-up', + params = { + event = "keep-oilrig:CDU_menu:set_CDU_temp" + } + }, + { + header = 'Toggle CDU', + icon = 'fa-solid fa-sliders', + params = { + event = "keep-oilrig:CDU_menu:switchPower_of_CDU" + } + }, + { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + } + exports['qb-menu']:openMenu(openMenu) +end + +AddEventHandler('keep-oilrig:CDU_menu:ShowCDU', function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:get_CDU_Data', function(result) + showCDU(result) + end) +end) + +AddEventHandler('keep-oilrig:CDU_menu:switchPower_of_CDU', function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:switchPower_of_CDU', function(result) + showCDU(result) + end) +end) + +AddEventHandler('keep-oilrig:CDU_menu:set_CDU_temp', function() + local inputData = exports['qb-input']:ShowInput({ + header = "CDU Temperatur", + submitText = "Angiv ny temperatur", + inputs = { { + type = 'number', + isRequired = true, + name = 'temp', + text = "Angiv ny temperatur" + }, + } + }) + if inputData then + if not inputData.temp then + return + end + QBCore.Functions.TriggerCallback('keep-oilrig:server:set_CDU_temp', function(result) + showCDU(result) + end, inputData) + end +end) + +AddEventHandler('keep-oilrig:CDU_menu:pumpCrudeOil_to_CDU', function() + local inputData = exports['qb-input']:ShowInput({ + header = "Pump råoile til CDU", + submitText = "Enter", + inputs = { { + type = 'number', + isRequired = true, + name = 'mændge', + text = "Angiv mængde råoile" + }, + } + }) + if inputData then + inputData.amount = tonumber(inputData.amount) + if not inputData.amount then + return + end + + if inputData.amount <= 0 then + QBCore.Functions.Notify('Mængde skal være mere end 0', "error") + return + end + QBCore.Functions.TriggerCallback('keep-oilrig:server:pumpCrudeOil_to_CDU', function(result) + showCDU(result) + end, inputData) + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/blender_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/blender_menu.lua new file mode 100644 index 0000000..e8edf2a --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/blender_menu.lua @@ -0,0 +1,199 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local function showblender(data) + local state = '' + local start_btn = 'Start' + local start_icon = 'fa-solid fa-square-caret-right' + if type(data) == "table" and data.metadata.state == false then + state = 'Inactive' + start_btn = 'Start' + start_icon = 'fa-solid fa-square-caret-right' + else + state = 'Active' + start_btn = 'Stop' + start_icon = "fa-solid fa-circle-stop" + end + + local header = "Blender unit (" .. state .. ')' + -- header + local heavy_naphtha = data.metadata.heavy_naphtha + local light_naphtha = data.metadata.light_naphtha + local other_gases = data.metadata.other_gases + -- new elements + local diesel = data.metadata.diesel + local kerosene = data.metadata.kerosene + local fuel_oil = data.metadata.fuel_oil + + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-blender' + }, { + header = 'Tung råoile', + icon = 'fa-solid fa-circle', + txt = heavy_naphtha .. " liter", + disabled = true + }, + { + header = 'Let råoile', + icon = 'fa-solid fa-circle', + txt = light_naphtha .. " liter", + disabled = true + }, + { + header = 'Andre gasser', + icon = 'fa-solid fa-circle', + txt = other_gases .. " liter", + disabled = true + }, + } + -- new elements + if diesel then + openMenu[#openMenu + 1] = { + header = 'Diesel', + icon = 'fa-solid fa-circle', + txt = diesel .. " liter", + disabled = true + } + end + + if kerosene then + openMenu[#openMenu + 1] = { + header = 'Petroleum', + icon = 'fa-solid fa-circle', + txt = kerosene .. " liter", + disabled = true + } + end + + if fuel_oil then + openMenu[#openMenu + 1] = { + header = 'Brændselsolie', + icon = 'fa-solid fa-circle', + txt = fuel_oil .. " Liter (Bruges ikke i blandingsprocessen)", + disabled = true + } + end + + openMenu[#openMenu + 1] = { + header = 'Skift opskrift', + icon = 'fa-solid fa-scroll', + params = { + event = "keep-oilrig:blender_menu:recipe_blender" + } + } + + openMenu[#openMenu + 1] = { + header = start_btn .. ' Blander', + icon = start_icon, + params = { + event = "keep-oilrig:blender_menu:toggle_blender" + } + } + + openMenu[#openMenu + 1] = { + header = 'Pump brændselsolie til tank', + icon = 'fa-solid fa-arrows-spin', + params = { + event = "keep-oilrig:blender_menu:pump_fueloil" + } + } + + openMenu[#openMenu + 1] = { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + + exports['qb-menu']:openMenu(openMenu) +end + +AddEventHandler('keep-oilrig:blender_menu:pump_fueloil', function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:pump_fueloil', function(result) + showblender(result) + end) +end) + +AddEventHandler('keep-oilrig:blender_menu:ShowBlender', function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:ShowBlender', function(result) + showblender(result) + end) +end) + +AddEventHandler('keep-oilrig:blender_menu:toggle_blender', function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:toggle_blender', function(result) + showblender(result) + end) +end) + +local function inRange(x, min, max) + return (x >= min and x <= max) +end + +AddEventHandler('keep-oilrig:blender_menu:recipe_blender', function() + local inputData = exports['qb-input']:ShowInput({ + header = "Pump råoile til CDU", + submitText = "Enter", + inputs = { + { + type = 'number', + isRequired = true, + name = 'heavy_naphtha', + text = "Tung råoile" + }, + { + type = 'number', + isRequired = true, + name = 'light_naphtha', + text = "Let råoile" + }, + { + type = 'number', + isRequired = true, + name = 'other_gases', + text = "Andre gasser" + }, + -- new elements + + { + type = 'number', + isRequired = true, + name = 'diesel', + text = "Diesel" + }, + + { + type = 'number', + isRequired = true, + name = 'kerosene', + text = "Petroleum" + }, + } + }) + if inputData then + if not + ( + inputData.heavy_naphtha + and inputData.light_naphtha + and inputData.other_gases + and inputData.diesel + and inputData.kerosene + ) then + return + end + + for _, value in pairs(inputData) do + if not inRange(tonumber(value), 0, 100) then + QBCore.Functions.Notify('Nummer skal være mellem 0-100', "primary") + return + end + end + + QBCore.Functions.TriggerCallback('keep-oilrig:server:recipe_blender', function(result) + showblender(result) + end, inputData) + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/edit_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/edit_menu.lua new file mode 100644 index 0000000..2af8e20 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/edit_menu.lua @@ -0,0 +1,83 @@ +local menu = MenuV:CreateMenu('Swkeep Oliebrønd', 'Menu', 'topright', 0, 0, 0, 'size-125', 'default', 'menuv', 'swkeep_oilwell', 'default') +menu.Title = ('Entity: %s'):format(OBJECT) + +local slider = menu:AddSlider({ icon = '❓', label = 'Præcision', value = '', values = { + { label = 'X1', value = 1 }, + { label = 'X2', value = 2 }, + { label = 'X3', value = 3 }, + { label = 'X4', value = 4 }, + { label = 'X5', value = 5 }, + { label = 'X6', value = 6 } +} }) + +local range = menu:AddRange({ + icon = '↔️', + label = 'Roter på Z', + min = -10, + max = 10, + value = 0, + saveOnUpdate = true +}) +local range2 = menu:AddRange({ + icon = '↕️', + label = 'Roter på Y', + min = -10, + max = 10, + value = 0, + saveOnUpdate = true +}) + +local range3 = menu:AddRange({ + icon = '↕️', + label = 'Roter på X', + min = -10, + max = 10, + value = 0, + saveOnUpdate = true +}) + +--- Events + +slider:On('change', function(item, newValue, oldValue) + local m = 10 * newValue + range.Max = m + range.Min = -m + + range2.Max = m + range2.Min = -m + + range3.Max = m + range3.Min = -m +end) + +range:On('change', function(item, newValue, oldValue) + menu.Title = ('Enhed: %s'):format(OBJECT) + range.Description = ('Nuværrende værdi (x) : %s'):format(newValue) + local roration = GetEntityRotation(OBJECT, 0) + SetEntityRotation(OBJECT, roration.x, roration.y, 0.0 + newValue * 6, 0.0, true) +end) + +range2:On('change', function(item, newValue, oldValue) + menu.Title = ('Enhed: %s'):format(OBJECT) + range2.Description = ('Nuværrende værdi (y) : %s'):format(newValue) + local roration = GetEntityRotation(OBJECT, 0) + SetEntityRotation(OBJECT, roration.x, 0.0 + newValue * 6, roration.z, 0.0, true) +end) + +range3:On('change', function(item, newValue, oldValue) + menu.Title = ('Enhed: %s'):format(OBJECT) + range3.Description = ('Nuværrende værdi (z) : %s'):format(newValue) + local roration = GetEntityRotation(OBJECT, 0) + SetEntityRotation(OBJECT, 0.0 + newValue * 3, roration.y, roration.z, 0.0, true) +end) + +local isOpen = false +AddEventHandler('keep-oilwell:menu:OPENMENU', function() + if not IsPauseMenuActive() and IsNuiFocused() ~= 1 and not isOpen then + MenuV:OpenMenu(menu) + isOpen = true + elseif isOpen == true then + MenuV:CloseMenu(menu) + isOpen = false + end +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/pump_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/pump_menu.lua new file mode 100644 index 0000000..9ff4f44 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/pump_menu.lua @@ -0,0 +1,290 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local function showInfo(data) + QBCore.Functions.TriggerCallback('keep-oilwell:server:oilwell_metadata', function(selected_oilrig) + local header = "Navn: " .. data.name + local partInfoString = "Bælte: " .. + selected_oilrig.part_info.belt .. + " Polish: " .. selected_oilrig.part_info.polish .. " Clutch: " .. selected_oilrig.part_info.clutch + local duration = math.floor(selected_oilrig.duration / 60) + -- header + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-oil-well' + }, { + header = 'Hastighed', + icon = 'fa-solid fa-gauge', + txt = "" .. selected_oilrig.speed .. " RPM", + disabled = true, + }, + { + header = 'Køretid', + icon = 'fa-solid fa-clock', + txt = "" .. duration .. " Min", + disabled = true, + }, + { + header = 'Temperatur', + icon = 'fa-solid fa-temperature-high', + txt = "" .. selected_oilrig.temp .. " °C", + disabled = true, + }, + { + header = 'Olie i tanken', + icon = 'fa-solid fa-oil-can', + txt = "" .. selected_oilrig.oil_storage .. "/L", + disabled = true, + }, + { + header = 'Part Info', + icon = 'fa-solid fa-oil-can', + txt = partInfoString, + disabled = true, + }, + { + header = 'Pump olie til tank', + icon = 'fa-solid fa-arrows-spin', + params = { + event = 'keep-oilrig:storage_menu:PumpOilToStorage', + args = { + oilrig_hash = data.oilrig_hash + } + } + }, + { + header = 'Manage ansatte', + icon = 'fa-solid fa-people-group', + params = { + event = 'keep-oilwell:menu:ManageEmployees', + args = data.oilrig_hash + + } + }, + { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + } + + exports['qb-menu']:openMenu(openMenu) + end, data.oilrig_hash) +end + +RegisterNetEvent('keep-oilwell:menu:ManageEmployees', function(oilrig_hash) + QBCore.Functions.TriggerCallback('keep-oilwell:server:employees_list', function(result) + if not result then return end + -- header + local Menu = { + { + header = 'Oliebrønd ansatte', + isMenuHeader = true, + icon = 'fa-solid fa-vest' + }, + } + + Menu[#Menu + 1] = { + header = 'Tilføj ansat', + icon = 'fa-solid fa-person-circle-plus', + params = { + event = "keep-oilwell:client:add_employee", + args = { + oilrig_hash = oilrig_hash, + state_id = 1 + } + } + } + + for index, employee in ipairs(result) do + local name = employee.charinfo.firstname .. ' ' .. employee.charinfo.lastname + local gender = (employee.charinfo.gender == 0 and 'Mand' or employee.charinfo.gender ~= 0 and 'Kvinde') + local information = 'Navn: %s
Telefon: %s
Køn: %s
' + local other = ' (Online: %s)' + local online = (employee.online and '🟢' or not employee.online and '🔴') + + Menu[#Menu + 1] = { + header = 'Ansat #' .. index .. string.format(other, online), + txt = string.format(information, name, employee.charinfo.phone, gender), + icon = 'fa-solid fa-person', + params = { + event = "keep-oilwell:menu:remove_employee", + args = { + employee = employee, + oilrig_hash = oilrig_hash + } + } + } + end + + Menu[#Menu + 1] = { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + + exports['qb-menu']:openMenu(Menu) + end, oilrig_hash) +end) + +RegisterNetEvent('keep-oilwell:client:add_employee', function(data) + local inputData = exports['qb-input']:ShowInput({ + header = 'BorgerID', + inputs = { + { + type = 'number', + isRequired = true, + name = 'BorgerID', + text = 'Skriv BorgerID' + }, + } + }) + if inputData then + if not inputData.stateId then return end + inputData.stateId = tonumber(inputData.stateId) + TriggerServerEvent('keep-oilwell:server:add_employee', data.oilrig_hash, inputData.stateId) + end +end) + +RegisterNetEvent('keep-oilwell:menu:remove_employee', function(data) + local employee = data.employee + local name = employee.charinfo.firstname .. ' ' .. employee.charinfo.lastname + -- header + local Menu = { + { + header = 'Tilbage', + icon = 'fa-solid fa-angle-left', + params = { + event = "keep-oilwell:menu:ManageEmployees", + args = data.oilrig_hash + } + }, + { + header = 'Fyr ansat', + txt = 'Name: ' .. name, + isMenuHeader = true, + icon = 'fa-solid fa-vest' + }, + { + header = 'Ja', + icon = 'fa-solid fa-circle-check', + params = { + event = "keep-oilwell:menu:fire_employee", + args = { + employee = data.employee, + oilrig_hash = data.oilrig_hash + } + } + } + } + + Menu[#Menu + 1] = { + header = 'Annuller', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + + exports['qb-menu']:openMenu(Menu) +end) + +RegisterNetEvent('keep-oilwell:menu:fire_employee', function(data) + TriggerServerEvent('keep-oilwell:server:remove_employee', data.oilrig_hash, data.employee.citizenid) +end) + +local function show_oilwell_stash(data) + QBCore.Functions.TriggerCallback('keep-oilwell:server:oilwell_metadata', function(selected_oilrig) + local header = "Navn: " .. data.name + local partInfoString = "Bælte: " .. + selected_oilrig.part_info.belt .. + " Polish: " .. selected_oilrig.part_info.polish .. " Clutch: " .. selected_oilrig.part_info.clutch + -- header + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-oil-well' + }, + { + header = 'Part Info', + icon = 'fa-solid fa-oil-can', + txt = partInfoString, + disabled = true, + }, + { + header = 'Åben stash', + icon = 'fa-solid fa-cart-flatbed', + params = { + event = 'keep-oilwell:client:openOilPump', + args = { + oilrig_hash = data.oilrig_hash + } + } + }, + { + header = 'Fiks oliebrønd', + icon = 'fa-solid fa-screwdriver-wrench', + + params = { + event = 'keep-oilwell:client:fix_oilwell', + args = { + oilrig_hash = data.oilrig_hash + } + } + }, + { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + } + + exports['qb-menu']:openMenu(openMenu) + end, data.oilrig_hash) +end + +-- Events +AddEventHandler('keep-oilrig:storage_menu:PumpOilToStorage', function(data) + QBCore.Functions.TriggerCallback('keep-oilrig:server:PumpOilToStorageCallback', function(result) + + end, data.oilrig_hash) +end) + +AddEventHandler('keep-oilrig:client:viewPumpInfo', function(qbtarget) + -- ask for updated data + OilRigs:startUpdate(function() + showInfo(OilRigs:getByEntityHandle(qbtarget.entity)) + end) +end) + + +AddEventHandler('keep-oilrig:client:show_oilwell_stash', function(qbtarget) + -- ask for updated data + OilRigs:startUpdate(function() + show_oilwell_stash(OilRigs:getByEntityHandle(qbtarget.entity)) + end) +end) + +-- Open oil pump stash. +RegisterNetEvent("keep-oilwell:client:openOilPump", function(data) + if not data then return end + TriggerServerEvent("inventory:server:OpenInventory", "stash", "oilPump_" .. data.oilrig_hash, + { maxweight = 100000, slots = 5 }) + TriggerEvent("inventory:client:SetCurrentStash", "oilPump_" .. data.oilrig_hash) +end) + +AddEventHandler('keep-oilwell:client:fix_oilwell', function(data) + -- ask for updated data + QBCore.Functions.TriggerCallback('keep-oilwell:server:fix_oil_well', function(result) + -- print(result) + end, data.oilrig_hash) + +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/storage_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/storage_menu.lua new file mode 100644 index 0000000..4304e16 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/storage_menu.lua @@ -0,0 +1,322 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local function showStorage(storage_data) + local header = storage_data.name + -- header + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-warehouse' + }, { + header = 'Råoile', + icon = 'fa-solid fa-oil-can', + txt = "" .. storage_data.metadata.crudeOil .. " /l", + params = { + event = 'keep-oilrig:storage_menu:StorageActions', + args = { + type = 'crudeOil', + storage_data = storage_data + } + } + }, + { + header = 'Brændstof', + icon = 'fa-solid fa-oil-can', + txt = "" .. storage_data.metadata.gasoline .. " /l | Oktan: " .. storage_data.metadata.avg_gas_octane, + params = { + event = 'keep-oilrig:storage_menu:StorageActions', + args = { + type = 'gasoline', + storage_data = storage_data + } + } + }, + + } + + if storage_data.metadata.fuel_oil then + openMenu[#openMenu + 1] = { + header = 'Brændselsolie', + icon = 'fa-solid fa-oil-can', + txt = "" .. storage_data.metadata.fuel_oil .. " /l", + params = { + event = 'keep-oilrig:storage_menu:StorageActions', + args = { + type = 'fuel_oil', + storage_data = storage_data + } + } + } + end + + + openMenu[#openMenu + 1] = { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + + exports['qb-menu']:openMenu(openMenu) +end + +local function showStorageActions(data) + local header = "Actions " .. data.type + local storage_data = data.storage_data + -- header + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-pump' + }, { + header = 'Tag fra lager', + icon = 'fa-solid fa-truck-ramp-box', + txt = "", + params = { + event = 'keep-oilrig:storage_menu:StorageWithdraw', + args = data + } + }, + { + header = 'Lagerhandling', + icon = 'fa-solid fa-arrow-right-arrow-left', + params = { + event = '', + } + }, + { + header = 'Tilbage', + icon = 'fa-solid fa-angle-left', + params = { + event = "keep-oilrig:storage_menu:ShowStorage" + } + } + } + + exports['qb-menu']:openMenu(openMenu) +end + +local function showStorageWithdraw(data) + local header = "Tag fra lager (" .. data.type .. ")" + local currentWithdrawTarget = data.storage_data.metadata[data.type] -- oil or gas + -- header + local openMenu = { + { + header = header, + isMenuHeader = true, + icon = 'fa-solid fa-boxes-packing' + }, + { + header = 'Du har ' .. currentWithdrawTarget .. ' liter ' .. data.type, + isMenuHeader = true, + icon = 'fa-solid fa-boxes-packing' + }, { + header = 'Gem i tønde', + icon = 'fa-solid fa-bottle-droplet', + txt = "Depositum: 500,- Kapacitet: 5000 /l", + params = { + event = 'keep-oilrig:storage_menu:Callback', + args = { + eventName = 'keep-oilrig:server:Withdraw', + citizenid = data.storage_data.citizenid, + type = data.type, + truck = false + } + } + }, + { + header = 'Fyld tankbil', + icon = 'fa-solid fa-truck-droplet', + txt = "Depositum: 25.000,- Kapacitet: 100.000 /l", + params = { + event = 'keep-oilrig:storage_menu:Callback', + args = { + eventName = 'keep-oilrig:server:Withdraw', + citizenid = data.storage_data.citizenid, + type = data.type, + truck = true + } + } + }, + { + header = 'Tilbage', + icon = 'fa-solid fa-angle-left', + params = { + event = "keep-oilrig:storage_menu:StorageActions", + args = data + } + } + } + exports['qb-menu']:openMenu(openMenu) +end + +MakeVehicle = function(model, Coord, TriggerLocation, DinstanceToTrigger, items) + local plyped = PlayerPedId() + local pedCoord = GetEntityCoords(plyped) + local finished = false + local distance = GetDistanceBetweenCoords(pedCoord.x, pedCoord.y, pedCoord.z, TriggerLocation.x, TriggerLocation.y, + TriggerLocation.z, true) + CreateThread(function() + while distance > DinstanceToTrigger do + local pedCoord = GetEntityCoords(plyped) + distance = GetDistanceBetweenCoords(pedCoord.x, pedCoord.y, pedCoord.z, TriggerLocation.x, + TriggerLocation.y, TriggerLocation.z, true) + Wait(1000) + end + finished = true + end) + + -- wait for player at delivery coord + while finished == false do + DrawMarker(2, TriggerLocation.x, TriggerLocation.y, TriggerLocation.z + 2, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 1.0 + , 1.0, + 1.0, 255, 128, 0, 50, false, true, 2, nil, nil, false) + Wait(0) + end + + local vehiclePlate = "HPO" .. math.random(1, 9) .. math.random(1, 9) .. math.random(1, 9) + model = GetHashKey(model) + RequestModel(model) + while not HasModelLoaded(model) do + Wait(10) + end + + local veh = CreateVehicle(model, Coord.x, Coord.y, Coord.z, Coord.w, true, false) + local netid = NetworkGetNetworkIdFromEntity(veh) + SetVehicleHasBeenOwnedByPlayer(veh, true) + + SetNetworkIdCanMigrate(netid, true) + SetVehicleNeedsToBeHotwired(veh, false) + SetVehRadioStation(veh, "OFF") + + SetVehicleNumberPlateText(veh, vehiclePlate) + + exports[Oilwell_config.fuel_script]:SetFuel(veh, math.random(80, 90)) + SetVehicleEngineOn(veh, true, true) + + SetNetworkIdAlwaysExistsForPlayer(NetworkGetNetworkIdFromEntity(veh), PlayerPedId(), true) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + TriggerEvent("vehiclekeys:client:SetOwner", vehiclePlate) + SetModelAsNoLongerNeeded(model) + Targets.qb_target.truck(vehiclePlate, veh) + + TriggerServerEvent('keep-oilwell:server_lib:update_vehicle', vehiclePlate, items) +end + + +RegisterNetEvent('keep-oilrig:client_lib:withdraw_from_queue', function(data) + QBCore.Functions.TriggerCallback('keep-oilrig:server:withdraw_from_queue', function(result) + -- res >> table of items + if result == false then + return + end + if not result.truck then + return + end + local SpawnLocation = Oilwell_config.Delivery.SpawnLocation + local TriggerLocation = Oilwell_config.Delivery.TriggerLocation + local DinstanceToTrigger = Oilwell_config.Delivery.DinstanceToTrigger + local model = Oilwell_config.Delivery.vehicleModel + + MakeVehicle(model, SpawnLocation, TriggerLocation, DinstanceToTrigger, result) + end, data.truck) +end) + +-- Events + +AddEventHandler('keep-oilrig:storage_menu:ShowStorage', function(data) + QBCore.Functions.TriggerCallback('keep-oilrig:server:getStorageData', function(result) + showStorage(result) + end) +end) + +AddEventHandler('keep-oilrig:storage_menu:StorageActions', function(storage_data) + showStorageActions(storage_data) +end) + +AddEventHandler('keep-oilrig:storage_menu:StorageWithdraw', function(data) + showStorageWithdraw(data) +end) + +AddEventHandler('keep-oilrig:storage_menu:Callback', function(data) + local inputData = exports['qb-input']:ShowInput({ + header = "Angiv mængde", + submitText = "Bekræft", + inputs = { + { + type = 'number', + isRequired = true, + name = 'Mængde', + text = "Mængde" + }, + } + }) + if inputData then + if not inputData.amount then + return + end + data.amount = inputData.amount + QBCore.Functions.TriggerCallback(data.eventName, function(res) + + end, data) + end +end) + + +-- withdraw spot +AddEventHandler("keep-oilwell:client:openWithdrawStash", function(data) + local player = QBCore.Functions.GetPlayerData() + if not data then return end + local settings = { maxweight = 100000, slots = 5 } + TriggerServerEvent("inventory:server:OpenInventory", "stash", "Withdraw_" .. player.citizenid, settings) + TriggerEvent("inventory:client:SetCurrentStash", "Withdraw_" .. player.citizenid) +end) + +-- purge menu +local function purge_menu() + local openMenu = { + { + header = 'TØM', + txt = 'Ønsker du at tømme lageret?', + icon = 'fa-solid fa-trash-can', + isMenuHeader = true, + }, + { + header = 'Bekræft', + icon = 'fa-solid fa-square-check', + params = { + event = 'keep-oilwell:client:purgeWithdrawStash', + } + }, + { + header = 'Annuller', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + } + exports['qb-menu']:openMenu(openMenu) +end + +AddEventHandler('keep-oilwell:client:open_purge_menu', function() + purge_menu() +end) + +local purge_conf = 0 +AddEventHandler('keep-oilwell:client:purgeWithdrawStash', function() + if purge_conf == 0 then + QBCore.Functions.Notify('Prøv igen! (Resetter om 5 sekunder)', "primary") + purge_conf = purge_conf + 1 + SetTimeout(5000, function() + purge_conf = 0 + end) + purge_menu() + return + end + purge_conf = 0 + TriggerServerEvent('keep-oilwell:server:purgeWithdrawStash') +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/transport_menu.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/transport_menu.lua new file mode 100644 index 0000000..7eb560f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/client_lib/menu/transport_menu.lua @@ -0,0 +1,205 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local function show_transport_menu() + + -- header + local openMenu = { + { + header = 'Transport', + txt = "Sælg råoile for at tjene penge", + isMenuHeader = true, + icon = 'fa-solid fa-ship' + }, + { + header = 'Kontroller nuværende pris/lager', + icon = 'fa-solid fa-hand-holding-dollar', + txt = "", + params = { + event = 'keep-oilwell:menu:show_transport_menu:ask_stock_price', + } + }, + { + header = 'Anmod om salgsorder', + icon = 'fa-solid fa-diagram-successor', + txt = "", + params = { + event = 'keep-oilwell:menu:show_transport_menu:ask_to_sell_amount', + } + }, + { + header = 'Forlad', + icon = 'fa-solid fa-circle-xmark', + params = { + event = "qb-menu:closeMenu" + } + } + } + + exports['qb-menu']:openMenu(openMenu) +end + +AddEventHandler('keep-oilwell:menu:show_transport_menu', function() + show_transport_menu() +end) + +AddEventHandler('keep-oilwell:menu:show_transport_menu:ask_stock_price', function() + TriggerServerEvent('keep-oilrig:server:oil_transport:checkPrice') +end) + +local function disableCombat() + DisablePlayerFiring(PlayerId(), true) -- Disable weapon firing + DisableControlAction(0, 24, true) -- disable attack + DisableControlAction(0, 25, true) -- disable aim + DisableControlAction(1, 37, true) -- disable weapon select + DisableControlAction(0, 47, true) -- disable weapon + DisableControlAction(0, 58, true) -- disable weapon + DisableControlAction(0, 140, true) -- disable melee + DisableControlAction(0, 141, true) -- disable melee + DisableControlAction(0, 142, true) -- disable melee + DisableControlAction(0, 143, true) -- disable melee + DisableControlAction(0, 263, true) -- disable melee + DisableControlAction(0, 264, true) -- disable melee + DisableControlAction(0, 257, true) -- disable melee +end + +function LoadAnim(dict) + while not HasAnimDictLoaded(dict) do + RequestAnimDict(dict) + Wait(10) + end +end + +function LoadPropDict(model) + while not HasModelLoaded(GetHashKey(model)) do + RequestModel(GetHashKey(model)) + Wait(10) + end +end + +local active_prop = nil +function AttachProp(model, bone, x, y, z, rot1, rot2, rot3) + local playerped = PlayerPedId() + local model_hash = GetHashKey(model) + local playercoord = GetEntityCoords(playerped) + local bone_index = GetPedBoneIndex(playerped, bone) + local _x, _y, _z = table.unpack(playercoord) + + if not HasModelLoaded(model) then + LoadPropDict(model) + end + + active_prop = CreateObject(model_hash, _x, _y, _z + 0.2, true, true, true) + AttachEntityToEntity(active_prop, playerped, bone_index, x, y, z, rot1, rot2, rot3, true, true, false, true, 1, true) + SetModelAsNoLongerNeeded(model) +end + +local function start_barell_animation() + local playerped = PlayerPedId() + local dict = 'anim@heists@box_carry@' + local anim = 'idle' + local PropName = 'prop_barrel_exp_01a' + local PropBone = 60309 + + LoadAnim(dict) + ClearPedTasks(playerped) + RemoveAnimDict(dict) + Wait(250) + AttachProp(PropName, PropBone, 0.0, 0.41, 0.3, 130.0, 290.0, 0.0) + CreateThread(function() + while active_prop do + local not_animation = IsEntityPlayingAnim(playerped, dict, anim, 3) + if not_animation ~= 1 then + TaskPlayAnim(playerped, dict, anim, 2.0, 2.0, -1, 51, 0, false, false, false) + DisableControlAction(0, 22, true) + end + Wait(1500) + end + end) + CreateThread(function() + while active_prop do + --disable combat while player have barell in their hands + disableCombat() + Wait(1) + end + end) +end + +local function end_barell_animaiton() + local playerped = PlayerPedId() + local dict = 'anim@heists@box_carry@' + local anim = 'idle' + + if active_prop then + DeleteObject(active_prop) + active_prop = nil + end + StopAnimTask(playerped, dict, anim, 1.0) +end + +AddEventHandler('keep-oilwell:menu:show_transport_menu:ask_to_sell_amount', function() + local inputData = exports['qb-input']:ShowInput({ + header = "Antal tønder", + submitText = "Sælg", + inputs = { + { + type = 'number', + isRequired = true, + name = 'Mængde', + text = "Mængde" + }, + } + }) + if inputData then + if not inputData.amount then + return + end + if type(inputData.amount) == 'string' then + inputData.amount = math.floor(tonumber(inputData.amount)) + end + -- start_barell_animation() + QBCore.Functions.Progressbar("keep_oilwell_transport", 'Fylder', Oilwell_config.Transport.duration * 1000, + false, false, { + disableMovement = true, + disableCarMovement = false, + disableMouse = false, + disableCombat = true + }, {}, {}, {}, function() + QBCore.Functions.TriggerCallback('keep-oilrig:server:oil_transport:fillTransportWell', function(res) + -- end_barell_animaiton() + end, inputData.amount) + end) + end +end) + +local inventory_max_size = Oilwell_config.inventory_max_size + +local function isBarellInInventory() + local items = QBCore.Functions.GetPlayerData().items + for slot = 1, inventory_max_size, 1 do + if items[slot] and items[slot].name == 'oilbarell' then + return true + end + end + return false +end + +local already_started = false +function StartBarellAnimation() + if already_started then return end + already_started = true + CreateThread(function() + while true do + local b = isBarellInInventory() + if b then + if not active_prop then + start_barell_animation() + end + else + if active_prop then + end_barell_animaiton() + end + end + Wait(1500) + end + end) +end diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/qb_target.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/qb_target.lua new file mode 100644 index 0000000..a2c4772 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/qb_target.lua @@ -0,0 +1,285 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local debugPoly = false + +Targets['qb_target'] = {} + +function Targets.qb_target.storage(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 2) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 1, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilrig:storage_menu:ShowStorage", + icon = "fa-solid fa-arrows-spin", + label = "Vis lager", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.distillation(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 1.1) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 1.2, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilrig:CDU_menu:ShowCDU", + icon = "fa-solid fa-gear", + label = "Åben CDU panel", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 1.5 + }) +end + +function Targets.qb_target.toggle_job(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 1.1) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 0.75, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilrig:client:goOnDuty", + icon = "fa-solid fa-boxes-packing", + label = "Gå hjem/på arbejde", + canInteract = function(entity) + if not CheckJob() then return false end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.barrel_withdraw(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 1.1) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 1.0, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilrig:client_lib:withdraw_from_queue", + icon = "fa-solid fa-boxes-packing", + label = "Overfør til lager", + truck = false, + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + { + type = "client", + event = "keep-oilwell:client:openWithdrawStash", + icon = "fa-solid fa-boxes-packing", + label = "Open Withdraw Stash", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + { + type = "client", + event = "keep-oilwell:client:open_purge_menu", + icon = "fa-solid fa-trash-can", + label = "Tøm lager", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.blender(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 2.5) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 3.5, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilrig:blender_menu:ShowBlender", + icon = "fa-solid fa-gear", + label = "Åben blandingspanel", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.crude_oil_transport(coords, name) + local tmp_coord = vector3(coords.x, coords.y, coords.z + 2.5) + + exports['qb-target']:AddCircleZone(name, tmp_coord, 2, { + name = name, + debugPoly = debugPoly, + useZ = true + }, { + options = { + { + type = "client", + event = "keep-oilwell:menu:show_transport_menu", + icon = "fa-solid fa-boxes-packing", + label = "Fyld transportbrønd", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then + QBCore.Functions.Notify('Du skal være på job!', "error") + Wait(2000) + return false + end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.oilwell(coords, name) + local coord = vector3(coords.x, coords.y, coords.z + 2.5) + + exports['qb-target']:AddCircleZone("oil-rig-" .. name, coord, 3.5, { + name = "oil-rig-" .. name, + debugPoly = false, + useZ = true, + }, { + options = { + { + type = "client", + event = "keep-oilrig:client:viewPumpInfo", + icon = "fa-solid fa-info", + label = "Se pumpe info", + canInteract = function(entity) + return true + end, + }, + { + type = "client", + event = "keep-oilrig:client:changeRigSpeed", + icon = "fa-solid fa-gauge-high", + label = "Modificer pumpe indstillinger", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then return false end + return isOwner(entity) + end, + }, + { + type = "client", + event = "keep-oilrig:client:show_oilwell_stash", + icon = "fa-solid fa-gears", + label = "Håndter dele", + canInteract = function(entity) + if not CheckJob() then return false end + if not CheckOnduty() then return false end + return isOwner(entity) + end, + }, + { + type = "client", + event = "keep-oilwell:client:remove_oilwell", + icon = "fa-regular fa-file-lines", + label = "Fjern oliebrønd", + canInteract = function(entity) + if not CheckJob() then + return false + end + if not (PlayerJob.grade.level == 4) then + return false + end + if not CheckOnduty() then + return false + end + return true + end, + }, + }, + distance = 2.5 + }) +end + +function Targets.qb_target.truck(plate, truck) + exports['qb-target']:AddEntityZone("device-" .. plate, truck, { + name = "device-" .. plate, + debugPoly = false, + }, { + options = { + { + type = "client", + event = "keep-oilwell:client:refund_truck", + icon = "fa-solid fa-location-arrow", + label = "Refunder køretøj", + vehiclePlate = plate + }, + }, + distance = 2.5 + }) +end diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/target.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/target.lua new file mode 100644 index 0000000..116d627 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/client/target/target.lua @@ -0,0 +1,137 @@ +Targets = {} +local QBCore = exports['qb-core']:GetCoreObject() + +local loaded = false +local PED = nil +local function setPedVariation(pedHnadle, variation) + for componentId, v in pairs(variation) do + if IsPedComponentVariationValid(pedHnadle, componentId, v.drawableId, v.textureId) then + SetPedComponentVariation(pedHnadle, componentId, v.drawableId, v.textureId) + end + end +end + +function GETPED() + return PED +end + +function SETPED(ped) + PED = ped +end + +local function spawn_ped(data) + RequestModel(data.model) + while not HasModelLoaded(data.model) do + Wait(0) + end + + if type(data.model) == 'string' then data.model = GetHashKey(data.model) end + + local ped = CreatePed(1, data.model, data.coords, data.networked or false, true) + + if data.variant then setPedVariation(ped, data.variant) end + if data.freeze then FreezeEntityPosition(ped, true) end + if data.invincible then SetEntityInvincible(ped, true) end + if data.blockevents then SetBlockingOfNonTemporaryEvents(ped, true) end + if data.animDict and data.anim then + RequestAnimDict(data.animDict) + while not HasAnimDictLoaded(data.animDict) do + Wait(0) + end + + if type(data.anim) == "table" then + CreateThread(function() + while true do + local anim = data.anim[math.random(0, #data.anim)] + ClearPedTasks(ped) + TaskPlayAnim(ped, data.animDict, anim, 8.0, 0, -1, data.flag or 1, 0, 0, 0, 0) + SETPED(ped) + Wait(7000) + end + end) + else + TaskPlayAnim(ped, data.animDict, data.anim, 8.0, 0, -1, data.flag or 1, 0, 0, 0, 0) + end + end + + if data.scenario then + SetPedCanPlayAmbientAnims(ped, true) + TaskStartScenarioInPlace(ped, data.scenario, 0, true) + end + + if data.voice then + SetAmbientVoiceName(ped, 'A_F_Y_BUSINESS_01_WHITE_FULL_01') + end + SETPED(ped) +end + +local function makeCore() + if loaded then return end + Citizen.CreateThread(function() + local c = Oilwell_config.TruckWithdraw.npc.coords + local vec3_coord = vector3(c.x, c.y, c.z) + PED = spawn_ped(Oilwell_config.TruckWithdraw.npc) + + exports['qb-target']:AddBoxZone("keep_oilwell_withdraw_truck_target", vec3_coord, + Oilwell_config.TruckWithdraw.box.l, + Oilwell_config.TruckWithdraw.box.w, + { + name = "keep_oilwell_withdraw_truck_target", + heading = Oilwell_config.TruckWithdraw.box.heading, + debugPoly = false, + minZ = vec3_coord.z + Oilwell_config.TruckWithdraw.box.minz_offset, + maxZ = vec3_coord.z + Oilwell_config.TruckWithdraw.box.maxz_offset, + }, { + options = { + { + event = "keep-oilrig:client_lib:withdraw_from_queue", + icon = "fa-solid fa-truck-droplet", + label = 'Tag lastbil', + truck = true + }, + }, + distance = 2.0 + }) + loaded = true + end) +end + +AddEventHandler('keep-oilwell:client:refund_truck', function(data) + local coord = GetEntityCoords(data.entity) + local spawnLocation = vector3(Oilwell_config.Delivery.SpawnLocation.x, Oilwell_config.Delivery.SpawnLocation.y, + Oilwell_config.Delivery.SpawnLocation.z) + + local plate = data.vehiclePlate + + if #(coord - spawnLocation) > 5.0 then + QBCore.Functions.Notify('Du er ikke tæt nok på, for at kunne refundere', "primary") + return + end + QBCore.Functions.TriggerCallback('keep-oilwell:server:refund_truck', function(result) + if result == true then + local netId = NetworkGetNetworkIdFromEntity(data.entity) + local entity = NetworkGetEntityFromNetworkId(netId) + NetworkRequestControlOfEntity(entity) + DeleteEntity(entity) + end + end, plate) +end) + + +AddEventHandler('onResourceStart', function(resourceName) + if (GetCurrentResourceName() ~= resourceName) then return end + Wait(1000) + makeCore() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + Wait(1000) + makeCore() +end) + +AddEventHandler('onResourceStop', function(resourceName) + if resourceName ~= GetCurrentResourceName() then + return + end + DeleteEntity(GETPED()) +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/config.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/config.lua new file mode 100644 index 0000000..3088b9d --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/config.lua @@ -0,0 +1,167 @@ +Oilwell_config = Oilwell_config or {} + +Oilwell_config.inventory_max_size = 41 +Oilwell_config.AnimationSpeedDivider = 20 -- higher value => less animation speed at 100% +Oilwell_config.actionSpeed = 5 -- how fast oilpump actionspeed is updated to new action speed / just visual +Oilwell_config.fuel_script = 'qb-fuel' + +Oilwell_config.Settings = { + size = { + oilwell_storage = 10000, + }, + oil_well = { + blip = { + sprite = 436, + colour = 5, + range = 'short', + -- CITIZENID | OILWELLNAME | DB_ID_RAW | TYPE | OILWELL_HASH + -- if scirpt detect this keywords inside string it will replace them. + name = 'Oil DB_ID_RAW' + } + }, + capacity = { + oilbarell = { + size = 5000, -- gal + cost = 500 + }, + truck = { + size = 5000, -- gal placeholder + cost = 25000 + } + } +} + +Oilwell_config.locations = { + storage = { + position = vector4(1710.67, -1662.0, 110.8, 325.22), + rotation = vector3(0.0, 0.0, 0.0), + model = 'prop_storagetank_06', + blip = { + sprite = 478, + colour = 5, + range = 'short', + name = 'Olie-type' + } + }, + distillation = { + position = vector4(1674, -1650.5, 110.2, 10), + rotation = vector3(0.0, 0.0, 10.0), + model = 'prop_gas_tank_01a', + blip = { + sprite = 467, + colour = 5, + range = 'short', + name = 'Olie-type' + } + }, + blender = { + position = vector4(1737.56, -1635.58, 110.88, 190), + rotation = vector3(0.0, 0.0, 190.0), + model = 'prop_storagetank_01', + blip = { + sprite = 365, + colour = 5, + range = 'short', + name = 'Olie-type' + } + }, + barrel_withdraw = { + position = vector4(1712.23, -1622.53, 111.48, 214.88), + rotation = vector3(0.0, 0.0, 0.0), + model = 'imp_prop_groupbarrel_03', + blip = { + sprite = 549, + colour = 5, + range = 'short', + name = 'Olie-type' + } + }, + -- placeholder + -- oil_wellhead = { + -- position = vector4(1480.9, -1850.85, 70.1, 246.85), + -- rotation = vector3(0.0, 0.0, 0.0), + -- model = 'prop_oil_wellhead_01', + -- }, + toggle_job = { + position = vector4(1703.5, -1635, 111.49, 100.11), + rotation = vector3(0.0, 0.0, 100.0), + model = 'xm_base_cia_server_02', + blip = { + sprite = 306, + colour = 5, + range = 'short', + name = 'Olie-type' + } + }, + crude_oil_transport = { + position = vector4(1220.0, -2986.0, 4.7, 180), + rotation = vector3(0.0, 0.0, 180.0), + model = 'prop_oil_wellhead_04', + blip = { + sprite = 306, + colour = 5, + range = 'short', + name = 'Olie-type' + } + } +} + +Oilwell_config.Delivery = { + refund = 20000, + TriggerLocation = vector3(1737.45, -1691.28, 112.73), + SpawnLocation = vector4(1741.19, -1694.61, 112.73, 125.57), + DinstanceToTrigger = 5.0, + vehicleModel = 'rallytruck' +} + +Oilwell_config.Transport = { + max_stock = 20000, --gal per type + prices = { + crudeOil = 3, + gasoline = 7, + fuel_oil = 3.5 + }, + barell_refund = 200, + duration = 5 --sec +} + +-- Make separate file for locale +Oilwell_config.Locale = { + mail = { + sender = 'Olie-firma', + subject = 'Betalings kvittering', + message = 'Kære %s %s,

Denne email er en kopi af din kvittering.
Din betaling var: %.2f,-
Solgt mængde : %d (liter)
Tønde refundering : %d,-' + }, + info = { + mr = 'Hr.', + mrs = 'Fr.', + } +} + +Oilwell_config.TruckWithdraw = { + npc = { + model = 'S_M_Y_Construct_02', + variant = {}, + coords = vector4(1737.49, -1691.76, 111.73, 116.07), + scenario = 'WORLD_HUMAN_CLIPBOARD', + flag = 1, + freeze = true, + invincible = true, + blockevents = true, + }, + box = { + minz_offset = -1, + maxz_offset = 1.75, + w = 1.5, + l = 2.35, + heading = 160.0 + } +} + +-- prop_barrel_exp_01a.yft ron +-- prop_barrel_exp_01b.yft glob oil + +-- prop_oil_wellhead_01 +-- prop_oilcan_02a + +-- vector3(998.08, -1859.08, 30.89) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/fxmanifest.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/fxmanifest.lua new file mode 100644 index 0000000..308884f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/fxmanifest.lua @@ -0,0 +1,33 @@ +fx_version 'cerulean' +games { 'gta5' } + +author "Swkeep#7049" + +shared_script { 'config.lua', 'shared/shared_main.lua' } + +client_scripts { + '@menuv/menuv.lua', + 'client/client.lua', + 'client/client_lib/client_lib_entry.lua', + 'client/client_lib/menu/CDU_menu.lua', + 'client/client_lib/menu/edit_menu.lua', + 'client/client_lib/menu/pump_menu.lua', + 'client/client_lib/menu/storage_menu.lua', + 'client/client_lib/menu/blender_menu.lua', + 'client/client_lib/menu/transport_menu.lua', + 'client/target/target.lua', + 'client/target/qb_target.lua', +} + +server_script { + '@oxmysql/lib/MySQL.lua', + 'server/server_lib/server_lib_entry.lua', + 'server/server_lib/Server_GlobalScirptData.lua', + 'server/server_lib/refund.lua', + 'server/server_main.lua', +} + + +dependency 'oxmysql' + +lua54 'yes' diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/drive_shaft.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/drive_shaft.png new file mode 100644 index 0000000..8658ae9 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/drive_shaft.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilBarrel.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilBarrel.png new file mode 100644 index 0000000..19dcf66 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilBarrel.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oil_filter.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oil_filter.png new file mode 100644 index 0000000..804fa05 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oil_filter.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilwell.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilwell.png new file mode 100644 index 0000000..025909b Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/oilwell.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/relief_valve_string.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/relief_valve_string.png new file mode 100644 index 0000000..da43c62 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/relief_valve_string.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/skew_gear.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/skew_gear.png new file mode 100644 index 0000000..a047206 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/skew_gear.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/timing_chain.png b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/timing_chain.png new file mode 100644 index 0000000..f6c27fa Binary files /dev/null and b/resources/[qb]/[qb_jobs]/keep-oilwell/inventoryicons/timing_chain.png differ diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/Server_GlobalScirptData.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/Server_GlobalScirptData.lua new file mode 100644 index 0000000..f2c7acd --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/Server_GlobalScirptData.lua @@ -0,0 +1,715 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +GlobalScirptData = { + oldTable = { 'deepcopy of oil_well' }, + oil_well = { + ['id'] = { + id = 'integer', + citizenid = 'string', + position = { + coord = { 'table' }, + rotation = { 'table' } + }, + name = 'string', + metadata = { + temp = 'float', + secduration = 'integer', + speed = 'integer', + oil_storage = 'float', + part_info = { + belt = 'float', + clutch = 'float', + polish = 'float' + } + }, + state = 'bool', + oilrig_hash = 'string' + } + }, + devices = { + oilrig_storage = { + { + id = 0, + citizenid = '', + name = '', + metadata = { + avg_gas_octane = 0, + gasoline = 0.0, + crudeOil = 0.0 + }, + } + }, + oilrig_cdu = { + { + id = 0, + citizenid = '', + metadata = { + temp = 0.0, + req_temp = 0.0, + state = false, + oil_storage = 0.0, + }, + } + }, + oilrig_blender = { + { + id = 0, + citizenid = '', + metadata = { + heavy_naphtha = 0.0, + light_naphtha = 0.0, + other_gases = 0.0, + state = false, + recipe = { + heavy_naphtha = 0.0, + light_naphtha = 0.0, + other_gases = 0.0, + } + }, + } + }, + } +} + +local serverUpdateInterval = 10000 -- database update interval + +function GlobalScirptData:newOilwell(oilwell, employees) + if self.oil_well[oilwell] ~= nil then return end + local id = #employees + 1 + employees[id] = { + id = id, + oilrig_hash = oilwell.oilrig_hash, + citizenid = oilwell.citizenid + } + + self.oil_well[oilwell.id] = {} + self.oil_well[oilwell.id] = oilwell + -- last employee is owner of oilwell + self.oil_well[oilwell.id].employees = employees + + self.oil_well[oilwell.id].is_employee = function(citizenid) + for key, value in ipairs(self.oil_well[oilwell.id].employees) do + if value.citizenid == citizenid then + if self.oil_well[oilwell.id].citizenid == citizenid then + return true, true + end + return true, false + end + end + return false, false + end + + self.oil_well[oilwell.id].employees_list = function() + return self.oil_well[oilwell.id].employees + end +end + +function GlobalScirptData:newDevice(device, Type) + if self.devices[Type][device.id] == nil then + self.devices[Type][device.id] = {} + end + + if Type == 'oilrig_storage' then + device.metadata = json.decode(device.metadata) + self.devices.oilrig_storage[device.id] = device + elseif Type == 'oilrig_cdu' then + device.metadata = json.decode(device.metadata) + self.devices.oilrig_cdu[device.id] = device + elseif Type == 'oilrig_blender' then + device.metadata = json.decode(device.metadata) + self.devices.oilrig_blender[device.id] = device + end +end + +function GlobalScirptData:saveThread() + CreateThread(function() + while true do + self.oldTable_oilwells = deepcopy(self.oil_well) + self.oldTable_oilrig_storage = deepcopy(self.devices.oilrig_storage) + self.oldTable_oilrig_cdu = deepcopy(self.devices.oilrig_cdu) + self.oldTable_oilrig_blender = deepcopy(self.devices.oilrig_blender) + + Wait(serverUpdateInterval) + for id, value in pairs(self.oil_well) do + if not equals(self.oldTable_oilwells[id], self.oil_well[id]) then + GeneralUpdate_2({ + type = 'oilrig_oilwell', + citizenid = value.citizenid, + oilrig_hash = value.oilrig_hash, + metadata = value.metadata + }) + end + end + + -- save storage data + for id, storage in pairs(self.devices.oilrig_storage) do + if not equals(self.oldTable_oilrig_storage[id], self.devices.oilrig_storage[id]) then + + GeneralUpdate_2({ + type = 'oilrig_storage', + citizenid = storage.citizenid, + metadata = storage.metadata + }) + end + end + + -- save CDU data + for id, storage in pairs(self.devices.oilrig_cdu) do + if not equals(self.oldTable_oilrig_cdu[id], self.devices.oilrig_cdu[id]) then + GeneralUpdate_2({ + type = 'oilrig_cdu', + citizenid = storage.citizenid, + metadata = storage.metadata + }) + end + end + + for id, blender in pairs(self.devices.oilrig_blender) do + if not equals(self.oldTable_oilrig_blender[id], self.devices.oilrig_blender[id]) then + GeneralUpdate_2({ + type = 'oilrig_blender', + citizenid = blender.citizenid, + metadata = blender.metadata + }) + end + end + end + end) +end + +--- wipes all data +function GlobalScirptData:wipeALL() + self.oil_well = {} + self.devices = { + oilrig_storage = {}, + oilrig_cdu = {}, + oilrig_blender = {}, + } + self.oldTable_oilwells = {} + self.oldTable_oilrig_storage = {} + self.oldTable_oilrig_cdu = {} + self.oldTable_oilrig_blender = {} +end + +function GlobalScirptData:getByHash(oilrig_hash) + for key, value in pairs(self.oil_well) do + if value.oilrig_hash == oilrig_hash then + return value, key + end + end + return false +end + +function GlobalScirptData:read(id) + return self.oil_well[id] +end + +function GlobalScirptData:readAll() + return self.oil_well +end + +function GlobalScirptData:getDeviceById(Type, id) + return self.devices[Type][id] +end + +function GlobalScirptData:getDeviceByCitizenId(Type, citizenid) + for key, value in pairs(self.devices[Type]) do + if value.citizenid == citizenid then + return value + end + end + return false +end + +local function cal_avg_octane(res) + local avg = 0 + for key, Type in pairs(res) do + avg = avg + Type.octane + end + return math.ceil((avg / 5) + 0.5) +end + +local function blender_calculations(blender) + if blender.metadata.state == false then + return + end + + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', blender.citizenid) + + if storage == false then + -- failsafe + local player = QBCore.Functions.GetPlayerByCitizenId(blender.citizenid) + TriggerClientEvent('QBCore:Notify', player.PlayerData.source, "Fatal fejl!", 'error') + TriggerClientEvent('QBCore:Notify', player.PlayerData.source, "Nødsikring aktiveret. Lukker ned!", 'primary') + blender.metadata.state = false + return + end + + if blender.metadata.heavy_naphtha <= 0.0 then + blender.metadata.heavy_naphtha = 0.0 + blender.metadata.state = false + return + end + -- blender.metadata.diesel + -- blender.metadata.kerosene + if blender.metadata.light_naphtha <= 0.0 then + blender.metadata.light_naphtha = 0.0 + blender.metadata.state = false + return + end + + if blender.metadata.other_gases <= 0.0 then + blender.metadata.other_gases = 0.0 + blender.metadata.state = false + return + end + + if blender.metadata.diesel <= 0.0 then + blender.metadata.diesel = 0.0 + blender.metadata.state = false + return + end + + if blender.metadata.kerosene <= 0.0 then + blender.metadata.kerosene = 0.0 + blender.metadata.state = false + return + end + + if not blender.metadata.recipe.diesel then + blender.metadata.recipe.diesel = 0 + end + if not blender.metadata.recipe.kerosene then + blender.metadata.recipe.kerosene = 0 + end + + local res = { + light_naphtha = BalanceRecipe:Blender(tonumber(blender.metadata.recipe.light_naphtha), 'light_naphtha'), + heavy_naphtha = BalanceRecipe:Blender(tonumber(blender.metadata.recipe.heavy_naphtha), 'heavy_naphtha'), + other_gases = BalanceRecipe:Blender(tonumber(blender.metadata.recipe.other_gases), 'other_gases'), + --new elements + diesel = BalanceRecipe:Blender(tonumber(blender.metadata.recipe.diesel), 'diesel'), + kerosene = BalanceRecipe:Blender(tonumber(blender.metadata.recipe.kerosene), 'kerosene'), + } + blender.metadata.light_naphtha = blender.metadata.light_naphtha - res.light_naphtha.usage + blender.metadata.heavy_naphtha = blender.metadata.heavy_naphtha - res.heavy_naphtha.usage + blender.metadata.other_gases = blender.metadata.other_gases - res.other_gases.usage + -- new elements + blender.metadata.diesel = blender.metadata.diesel - res.diesel.usage + blender.metadata.kerosene = blender.metadata.kerosene - res.kerosene.usage + + res.avg_octane = cal_avg_octane(res) + storage.metadata.avg_gas_octane = math.ceil((storage.metadata.avg_gas_octane + res.avg_octane) / 2) + storage.metadata.gasoline = Round(storage.metadata.gasoline + 0.75, 2) +end + +local function CDUs_calculations(CDU) + if CDU.metadata.state == false then + if CDU.metadata.temp > 0 then + CDU.metadata.temp = CDU.metadata.temp - 15.0 + else + CDU.metadata.temp = 0.0 + end + return + end + + -- increase temp until reach requestd temp + if CDU.metadata.req_temp > CDU.metadata.temp then + CDU.metadata.temp = CDU.metadata.temp + 15.0 + elseif CDU.metadata.req_temp == CDU.metadata.temp then + CDU.metadata.temp = CDU.metadata.req_temp + end + + -- a little bit of fun xd + if CDU.metadata.temp >= 1000 then + local player = QBCore.Functions.GetPlayerByCitizenId(CDU.citizenid) + CDU.metadata.temp = 0 + CDU.metadata.state = false + TriggerClientEvent('keep-oilwell:server_lib:AddExplosion', player.PlayerData.source, 'distillation') + return + end + -- oil_storage > 1.0 min buffer + -- CDU functions on current temp if we have something in oil_storage + if CDU.metadata.oil_storage > 1.0 then + -- get storage to export CDU products + local blender = GlobalScirptData:getDeviceByCitizenId('oilrig_blender', CDU.citizenid) + if blender == false then + -- CUD's failsafe + local player = QBCore.Functions.GetPlayerByCitizenId(CDU.citizenid) + local source = player.PlayerData.source + TriggerClientEvent('QBCore:Notify', source, "Fatal fejl!", 'error') + TriggerClientEvent('QBCore:Notify', source, "Nødsikring aktiveret. Lukker ned!", 'primary') + CDU.metadata.state = false + return + end + + local multi, o_type = BalanceRecipe:CDU(CDU.metadata.temp) + if multi and o_type then + CDU.metadata.oil_storage = CDU.metadata.oil_storage - multi + if blender.metadata[o_type] == nil then + blender.metadata[o_type] = 0 + end + blender.metadata[o_type] = blender.metadata[o_type] + multi + end + end +end + +local function oilwell_calculations(oil_well) + local pumpOverHeat = 327 + local sotrage_size = Oilwell_config.Settings.size.oilwell_storage + + if oil_well.metadata.speed > 0 then + oil_well.metadata.duration = oil_well.metadata.duration + 1 + oil_well.metadata.secduration = oil_well.metadata.duration + if oil_well.metadata.temp ~= nil and pumpOverHeat >= oil_well.metadata.temp then + local temp = oil_well.metadata.temp + local speed = oil_well.metadata.speed + oil_well.metadata.temp = Round(tempGrowth(temp, speed, 'increase', pumpOverHeat), 2) + else + oil_well.metadata.temp = pumpOverHeat + end + + if oil_well.metadata.speed <= 0 then return end + -- parts functions + if oil_well.metadata.part_info.belt > 0 then + local res = BalanceRecipe:SpeedRelated('OilwellBeltDegradation', oil_well.metadata.speed) + oil_well.metadata.part_info.belt = Round((oil_well.metadata.part_info.belt - res), 2) + elseif oil_well.metadata.part_info.belt <= 0 then + oil_well.metadata.part_info.belt = 0 + oil_well.metadata.speed = 0 + local player = QBCore.Functions.GetPlayerByCitizenId(oil_well.citizenid) + TriggerClientEvent('QBCore:Notify', player.PlayerData.source, 'Lukker ned. Ødelagt bælte', 'error') + TriggerClientEvent('keep-oilrig:client:syncSpeed', -1, oil_well.id, 0) + end + + if oil_well.metadata.part_info.polish > 0 then + local res = BalanceRecipe:SpeedRelated('OilwellPolishDegradation', oil_well.metadata.speed) + oil_well.metadata.part_info.polish = Round((oil_well.metadata.part_info.polish - res), 2) + elseif oil_well.metadata.part_info.polish <= 0 then + oil_well.metadata.part_info.polish = 0 + oil_well.metadata.speed = 0 + local player = QBCore.Functions.GetPlayerByCitizenId(oil_well.citizenid) + TriggerClientEvent('QBCore:Notify', player.PlayerData.source, 'Lukker ned. Polish-værdi ramte 0', 'error') + TriggerClientEvent('keep-oilrig:client:syncSpeed', -1, oil_well.id, 0) + end + + if oil_well.metadata.part_info.clutch > 0 then + local res = BalanceRecipe:SpeedRelated('OilwellClutchDegradation', oil_well.metadata.speed) + oil_well.metadata.part_info.clutch = Round((oil_well.metadata.part_info.clutch - res), 2) + elseif oil_well.metadata.part_info.clutch <= 0 then + oil_well.metadata.part_info.clutch = 0 + oil_well.metadata.speed = 0 + local player = QBCore.Functions.GetPlayerByCitizenId(oil_well.citizenid) + TriggerClientEvent('QBCore:Notify', player.PlayerData.source, 'Lukker ned. Ødelagt kobling', 'error') + TriggerClientEvent('keep-oilrig:client:syncSpeed', -1, oil_well.id, 0) + end + + -- skip player oil if player one part is 0 + if oil_well.metadata.part_info.clutch == 0 or oil_well.metadata.part_info.polish == 0 or + oil_well.metadata.part_info.belt == 0 then + return + end + if oil_well.metadata.temp > 0 and oil_well.metadata.temp < pumpOverHeat and + oil_well.metadata.oil_storage <= sotrage_size then + local res = BalanceRecipe:SpeedRelated('OilwellProdoction', oil_well.metadata.speed) + oil_well.metadata.oil_storage = oil_well.metadata.oil_storage + res + end + else + -- reset duration + oil_well.metadata.duration = 0 + -- start cooling procces + if oil_well.metadata.secduration > 0 then + local temp = oil_well.metadata.temp + local speed = oil_well.metadata.speed + oil_well.metadata.secduration = oil_well.metadata.secduration - 1 + oil_well.metadata.temp = Round(tempGrowth(temp, speed, 'decrease', pumpOverHeat), 2) + elseif oil_well.metadata.secduration == 0 then + oil_well.metadata.temp = 0 + end + + if oil_well.metadata.secduration > 0 and oil_well.metadata.temp == 0 then + oil_well.metadata.secduration = 0 + end + end +end + +-- Storage +function SendOilToStorage(oilrig, src, cb) + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', oilrig.citizenid) + if storage == false then + InitStorage({ + citizenid = oilrig.citizenid, + name = "'s inventar", + }) + TriggerClientEvent('QBCore:Notify', src, "Kunne ikke tilgå inventar. Prøv igen!", 'error') + cb(false) + return + end + -- add to storage + if not storage then + TriggerClientEvent('QBCore:Notify', src, "Kunne ikke tilgå inventar. Prøv igen!", 'error') + return + end + storage.metadata.crudeOil = Round(storage.metadata.crudeOil + oilrig.metadata.oil_storage, 2) + TriggerClientEvent('QBCore:Notify', src, oilrig.metadata.oil_storage .. " liter råoile pumpet til lager") + -- remove from oilwell + oilrig.metadata.oil_storage = 0.0 + cb(true) +end + +function SendOilFuelToStorage(player, src, cb) + local citizenid = player.PlayerData.citizenid + local blender = GlobalScirptData:getDeviceByCitizenId('oilrig_blender', citizenid) + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', citizenid) + + if storage == false then + InitStorage({ + citizenid = citizenid, + name = player.PlayerData.name .. "'s inventar", + }) + TriggerClientEvent('QBCore:Notify', src, "Kunne ikke tilgå inventar. Prøv igen!", 'error') + cb(false) + return + end + + if not blender then + TriggerClientEvent('QBCore:Notify', src, "Kunne ikke tilgå inventar. Prøv igen!", 'error') + cb(false) + return + end + + if not storage.metadata.fuel_oil then + storage.metadata.fuel_oil = 0 + end + + if not blender.metadata.fuel_oil then + blender.metadata.fuel_oil = 0 + end + + if blender.metadata.fuel_oil == 0 then + TriggerClientEvent('QBCore:Notify', src, "Du har ingen brændselsolie!", 'error') + return + end + -- add to storage + storage.metadata.fuel_oil = Round((storage.metadata.fuel_oil + blender.metadata.fuel_oil), 2) + TriggerClientEvent('QBCore:Notify', src, blender.metadata.fuel_oil .. " liter brændselsolie pumpet til lager") + -- remove from oilwell + blender.metadata.fuel_oil = 0.0 + cb(true) +end + +function InitStorage(o, cb) + local sqlQuery = 'INSERT INTO oilrig_storage (citizenid,name,metadata) VALUES (?,?,?)' + local metadata = { + queue = {}, + avg_gas_octane = 0, + gasoline = 0.0, + crudeOil = 0.0 + } + + MySQL.Async.fetchAll('SELECT * FROM oilrig_storage WHERE citizenid = ?', { o.citizenid }, function(res) + if next(res) then cb(false) return false end + + local QueryData = { + o.citizenid, + o.name, + json.encode(metadata), + } + res = MySQL.Sync.insert(sqlQuery, QueryData) + if res ~= 0 then + -- inject into runtime + GlobalScirptData:newDevice({ + id = res, + citizenid = o.citizenid, + name = o.name, + metadata = json.encode(metadata) + }, 'oilrig_storage') + + if cb then + cb(GlobalScirptData:getDeviceByCitizenId('oilrig_storage', o.citizenid)) + end + return true + end + cb(false) + return false + end) +end + +-- End Storage + +-- CDU + +function Init_CDU(citizenid, cb) + local sqlQuery = 'INSERT INTO oilrig_cdu (citizenid,metadata) VALUES (?,?)' + local metadata = { + temp = 0.0, + req_temp = 0.0, + state = false, + oil_storage = 0.0 + } + + MySQL.Async.fetchAll('SELECT * FROM oilrig_cdu WHERE citizenid = ?', { citizenid }, function(res) + if next(res) then cb(false) return end + local QueryData = { citizenid, json.encode(metadata) } + res = MySQL.Sync.insert(sqlQuery, QueryData) + if res ~= 0 then + -- inject into runtime + GlobalScirptData:newDevice({ + id = res, + citizenid = citizenid, + metadata = json.encode(metadata) + }, 'oilrig_cdu') + cb(GlobalScirptData:getDeviceByCitizenId('oilrig_cdu', citizenid)) + return + end + cb(false) + end) +end + +-- End CDU + +-- Blender + +function Init_Blender(citizenid, cb) + local sqlQuery = 'INSERT INTO oilrig_blender (citizenid,metadata) VALUES (?,?)' + local metadata = { + heavy_naphtha = 0.0, + light_naphtha = 0.0, + other_gases = 0.0, + state = false, + recipe = { + heavy_naphtha = 0.0, + light_naphtha = 0.0, + other_gases = 0.0, + } + } + MySQL.Async.fetchAll('SELECT * FROM oilrig_blender WHERE citizenid = ?', { citizenid }, function(res) + if next(res) then cb(false) end + + local QueryData = { + citizenid, + json.encode(metadata), + } + res = MySQL.Sync.insert(sqlQuery, QueryData) + + if res ~= 0 then + -- inject into runtime + GlobalScirptData:newDevice({ + id = res, + citizenid = citizenid, + metadata = json.encode(metadata) + }, 'oilrig_blender') + cb(GlobalScirptData:getDeviceByCitizenId('oilrig_blender', citizenid)) + return + end + cb(false) + end) +end + +-- End Blender + +---------------------- +-- Data Manipulations +---------------------- + +local function startServerTick() + CreateThread(function() + while true do + for _, oil_well in pairs(GlobalScirptData.oil_well) do + oilwell_calculations(oil_well) + end + for _, CDU in pairs(GlobalScirptData.devices.oilrig_cdu) do + CDUs_calculations(CDU) + end + for _, blender in pairs(GlobalScirptData.devices.oilrig_blender) do + blender_calculations(blender) + end + Wait(1000) + end + end) +end + +-------------------- +-- DATABASE WRAPPER +-------------------- +function Sync_with_database() + local o_w_sql = 'SELECT * FROM oilrig_position WHERE id = ? and deleted = false' + local e_sql = 'SELECT * FROM oilcompany_employees WHERE oilrig_hash = ?' + + local fetch_oil_well = function(id) + local oil_well = {} + local oil_well_employees = {} + oil_well = MySQL.Sync.fetchAll(o_w_sql, { id }) + oil_well_employees = MySQL.Sync.fetchAll(e_sql, { oil_well[1].oilrig_hash }) + + -- -- convert strings to josn type + oil_well[1].position = json.decode(oil_well[1].position) + oil_well[1].metadata = json.decode(oil_well[1].metadata) + + return oil_well[1], oil_well_employees + end + + local oil_wells = MySQL.Sync.fetchAll('SELECT id FROM `oilrig_position` WHERE deleted = false', {}) + local oilrig_storage = {} + local oilrig_cdu = {} + local oilrig_blender = {} + for _, well in ipairs(oil_wells) do + local oil_well, employees = fetch_oil_well(well.id) + GlobalScirptData:newOilwell(oil_well, employees) + end + + + oilrig_storage = MySQL.Sync.fetchAll('SELECT * FROM oilrig_storage', {}) + for _, value in ipairs(oilrig_storage) do + GlobalScirptData:newDevice(value, 'oilrig_storage') + end + + oilrig_cdu = MySQL.Sync.fetchAll('SELECT * FROM oilrig_cdu', {}) + for _, value in ipairs(oilrig_cdu) do + GlobalScirptData:newDevice(value, 'oilrig_cdu') + end + + oilrig_blender = MySQL.Sync.fetchAll('SELECT * FROM oilrig_blender', {}) + for _, value in ipairs(oilrig_blender) do + GlobalScirptData:newDevice(value, 'oilrig_blender') + end + + -- print(Colors.blue .. 'Indlæser rapport (' .. GetCurrentResourceName() .. ')') + -- print(Colors.green .. '' .. #oil_wells .. ' oilebrønde') + -- print(Colors.green .. '' .. #oilrig_storage .. ' lagre') + -- print(Colors.green .. '' .. #oilrig_cdu .. ' CDU\'er') + -- print(Colors.green .. '' .. #oilrig_blender .. ' Blandere') + -- print(Colors.blue .. 'End of loading (' .. GetCurrentResourceName() .. ')') + + GlobalScirptData:saveThread() + startServerTick() +end + +function GeneralUpdate_2(options) + if options.type == nil then return end + local sqlQuery = '' + local QueryData = {} + for key, value in pairs(options.metadata) do + if type(value) == "number" then + options.metadata[key] = Round(value, 2) + end + end + if options.type == 'oilrig_storage' or options.type == 'oilrig_cdu' or options.type == 'oilrig_blender' then + sqlQuery = 'UPDATE ' .. options.type .. ' SET metadata = ? WHERE citizenid = ? AND metadata <> ?' + QueryData = { + json.encode(options.metadata), -- check if data is cahnged + options.citizenid, + json.encode(options.metadata) -- check if data is cahnged + } + elseif options.type == 'oilrig_oilwell' then + sqlQuery = 'UPDATE oilrig_position SET metadata = ? WHERE citizenid = ? AND oilrig_hash = ? AND metadata <> ?' + QueryData = { + json.encode(options.metadata), -- check if data is cahnged + options.citizenid, + options.oilrig_hash, + json.encode(options.metadata) -- check if data is cahnged + } + end + MySQL.Async.execute(sqlQuery, QueryData, function(e) + end) +end diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/refund.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/refund.lua new file mode 100644 index 0000000..4f06790 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/refund.lua @@ -0,0 +1,24 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local vehicles = {} + +RegisterNetEvent('keep-oilwell:server_lib:update_vehicle', function(vehiclePlate, items) + local src = source + if not vehicles[src] then + vehicles[src] = {} + end + vehicles[src][vehiclePlate] = vehiclePlate + exports['ps-inventory']:addTrunkItems(vehiclePlate, items) +end) + +QBCore.Functions.CreateCallback('keep-oilwell:server:refund_truck', function(source, cb, vehiclePlate) + if vehicles[source] then + if vehicles[source][vehiclePlate] then + local player = QBCore.Functions.GetPlayer(source) + player.Functions.AddMoney('bank', Oilwell_config.Delivery.refund, 'oil_barells') + vehicles[source][vehiclePlate] = nil + cb(true) + return + end + end + cb(false) +end) diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/server_lib_entry.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/server_lib_entry.lua new file mode 100644 index 0000000..d906e88 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_lib/server_lib_entry.lua @@ -0,0 +1,294 @@ +BalanceRecipe = {} + +function GeneralInsert(options) + local sqlQuery = 'INSERT INTO oilrig_position (citizenid,name,oilrig_hash,position,metadata,state) VALUES (?,?,?,?,?,?)' + local QueryData = { + options.citizenid, + options.name, + options.oilrig_hash, + json.encode(options.position), + json.encode(options.metadata), + options.state + } + return MySQL.Sync.insert(sqlQuery, QueryData) +end + +function isTableChanged(oldTable, newTable) + if equals(oldTable, newTable, true) == false then + return true + else + return false + end +end + +function equals(o1, o2, ignore_mt) + if o1 == o2 then return true end + local o1Type = type(o1) + local o2Type = type(o2) + if o1Type ~= o2Type then return false end + if o1Type ~= 'table' then return false end + + if not ignore_mt then + local mt1 = getmetatable(o1) + if mt1 and mt1.__eq then + --compare using built in method + return o1 == o2 + end + end + + local keySet = {} + + for key1, value1 in pairs(o1) do + local value2 = o2[key1] + if value2 == nil or equals(value1, value2, ignore_mt) == false then + return false + end + keySet[key1] = true + end + + for key2, _ in pairs(o2) do + if not keySet[key2] then return false end + end + return true +end + +function deepcopy(orig, copies) + copies = copies or {} + local orig_type = type(orig) + local copy + if orig_type == 'table' then + if copies[orig] then + copy = copies[orig] + else + copy = {} + copies[orig] = copy + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key, copies)] = deepcopy(orig_value, copies) + end + setmetatable(copy, deepcopy(getmetatable(orig), copies)) + end + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +local function inRange(x, min, max) + return (x >= min and x <= max) +end + +local function getCurrentSpeed_maxTemp(speed) + if inRange(speed, 0, 10) then return 75 + elseif inRange(speed, 10, 20) then return 100 + elseif inRange(speed, 30, 40) then return 125 + elseif inRange(speed, 40, 50) then return 170 + elseif inRange(speed, 50, 60) then return 215 + elseif inRange(speed, 60, 70) then return 260 + elseif inRange(speed, 70, 80) then return 305 + elseif inRange(speed, 80, 100) then return 327 + else return 0 + end +end + +local function isOverHeatTemp(temp, max) + return (temp >= max) +end + +function GetSpeedProdoctionMulti(speed) + local logic = { + [1] = { range = { 0, 10 }, multi = 0.02 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.04 }, + [4] = { range = { 30, 40 }, multi = 0.05 }, + [5] = { range = { 40, 50 }, multi = 0.06 }, + [6] = { range = { 50, 60 }, multi = 0.07 }, + [7] = { range = { 60, 70 }, multi = 0.08 }, + [8] = { range = { 70, 80 }, multi = 0.09 }, + [9] = { range = { 80, 90 }, multi = 0.1 }, + [10] = { range = { 90, 100 }, multi = 0.12 }, + } + for key, value in pairs(logic) do + if inRange(speed, value.range[1], value.range[2]) then + return value.multi + end + end + return 0 +end + +function GetSpeed_degradationMulti(speed) + local logic = { + [1] = { range = { 0, 10 }, multi = 0.025 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.035 }, + [4] = { range = { 30, 40 }, multi = 0.040 }, + [5] = { range = { 40, 50 }, multi = 0.045 }, + [6] = { range = { 50, 60 }, multi = 0.050 }, + [7] = { range = { 60, 70 }, multi = 0.055 }, + [8] = { range = { 70, 80 }, multi = 0.06 }, + [9] = { range = { 80, 90 }, multi = 0.068 }, + [10] = { range = { 90, 100 }, multi = 0.075 }, + } + for key, value in pairs(logic) do + if inRange(speed, value.range[1], value.range[2]) then + return value.multi + end + end + return 0 +end + +function BalanceRecipe:SpeedRelated(type, condition) + local data = { + ['OilwellTemperatureGrowth'] = { + [1] = { range = { 0, 10 }, multi = 0.02 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.04 }, + [4] = { range = { 30, 40 }, multi = 0.05 }, + [5] = { range = { 40, 50 }, multi = 0.06 }, + [6] = { range = { 50, 60 }, multi = 0.07 }, + [7] = { range = { 60, 70 }, multi = 0.08 }, + [8] = { range = { 70, 80 }, multi = 0.09 }, + [9] = { range = { 80, 90 }, multi = 0.1 }, + [10] = { range = { 90, 100 }, multi = 0.12 }, + }, + ['OilwellProdoction'] = { + [1] = { range = { 0, 10 }, multi = 0.02 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.04 }, + [4] = { range = { 30, 40 }, multi = 0.05 }, + [5] = { range = { 40, 50 }, multi = 0.06 }, + [6] = { range = { 50, 60 }, multi = 0.07 }, + [7] = { range = { 60, 70 }, multi = 0.08 }, + [8] = { range = { 70, 80 }, multi = 0.09 }, + [9] = { range = { 80, 90 }, multi = 0.1 }, + [10] = { range = { 90, 100 }, multi = 0.12 }, + }, + ['OilwellClutchDegradation'] = { + [1] = { range = { 0, 10 }, multi = 0.025 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.035 }, + [4] = { range = { 30, 40 }, multi = 0.040 }, + [5] = { range = { 40, 50 }, multi = 0.045 }, + [6] = { range = { 50, 60 }, multi = 0.050 }, + [7] = { range = { 60, 70 }, multi = 0.055 }, + [8] = { range = { 70, 80 }, multi = 0.06 }, + [9] = { range = { 80, 90 }, multi = 0.065 }, + [10] = { range = { 90, 100 }, multi = 0.07 }, + }, + ['OilwellPolishDegradation'] = { + [1] = { range = { 0, 10 }, multi = 0.02 }, + [2] = { range = { 10, 20 }, multi = 0.025 }, + [3] = { range = { 20, 30 }, multi = 0.03 }, + [4] = { range = { 30, 40 }, multi = 0.035 }, + [5] = { range = { 40, 50 }, multi = 0.04 }, + [6] = { range = { 50, 60 }, multi = 0.045 }, + [7] = { range = { 60, 70 }, multi = 0.05 }, + [8] = { range = { 70, 80 }, multi = 0.055 }, + [9] = { range = { 80, 90 }, multi = 0.060 }, + [10] = { range = { 90, 100 }, multi = 0.065 }, + }, + ['OilwellBeltDegradation'] = { + [1] = { range = { 0, 10 }, multi = 0.025 }, + [2] = { range = { 10, 20 }, multi = 0.03 }, + [3] = { range = { 20, 30 }, multi = 0.035 }, + [4] = { range = { 30, 40 }, multi = 0.040 }, + [5] = { range = { 40, 50 }, multi = 0.045 }, + [6] = { range = { 50, 60 }, multi = 0.050 }, + [7] = { range = { 60, 70 }, multi = 0.055 }, + [8] = { range = { 70, 80 }, multi = 0.06 }, + [9] = { range = { 80, 90 }, multi = 0.065 }, + [10] = { range = { 90, 100 }, multi = 0.07 }, + }, + } + + for key, value in pairs(data[type]) do + if inRange(condition, value.range[1], value.range[2]) then + return value.multi + end + end + return 0 +end + +function BalanceRecipe:CDU(condition) + local data = { + [1] = { range = { 20, 50 }, multi = 0.65, o_type = 'other_gases' }, + [2] = { range = { 50, 100 }, multi = 0.3, o_type = 'light_naphtha' }, + [3] = { range = { 100, 150 }, multi = 0.5, o_type = 'light_naphtha' }, + [4] = { range = { 150, 175 }, multi = 0.2, o_type = 'kerosene' }, + [5] = { range = { 175, 200 }, multi = 0.25, o_type = 'heavy_naphtha' }, + [6] = { range = { 200, 230 }, multi = 0.3, o_type = 'heavy_naphtha' }, + [7] = { range = { 230, 260 }, multi = 0.35, o_type = 'diesel' }, + [8] = { range = { 260, 30 }, multi = 0.4, o_type = 'diesel' }, + [9] = { range = { 300, 600 }, multi = 0.8, o_type = 'fuel_oil' }, + } + + for key, value in pairs(data) do + if inRange(condition, value.range[1], value.range[2]) then + return value.multi, value.o_type + end + end + return 0, 'other_gases' +end + +function BalanceRecipe:Blender(condition, Type) + local data = { + ['other_gases'] = { + [1] = { range = { 0, 10 }, octane = 93, usage = 0.1 }, + [2] = { range = { 10, 20 }, octane = 91, usage = 0.2 }, + [3] = { range = { 20, 25 }, octane = 89, usage = 0.25 }, + }, + ['kerosene'] = { + [1] = { range = { 5, 10 }, octane = 89, usage = 0.1 }, + [2] = { range = { 10, 15 }, octane = 91, usage = 0.15 }, + [3] = { range = { 15, 25 }, octane = 93, usage = 0.25 }, + }, + ['diesel'] = { + [1] = { range = { 0, 0 }, octane = 93, usage = 0.0 }, + [2] = { range = { 10, 20 }, octane = 91, usage = 0.25 }, + [3] = { range = { 15, 25 }, octane = 89, usage = 0.35 }, + }, + ['light_naphtha'] = { + [1] = { range = { 10, 20 }, octane = 89, usage = 0.06 }, + [2] = { range = { 20, 40 }, octane = 91, usage = 0.16 }, + [3] = { range = { 40, 60 }, octane = 93, usage = 0.39 }, + }, + ['heavy_naphtha'] = { + [1] = { range = { 80, 60 }, octane = 93, usage = 0.24 }, + [2] = { range = { 60, 40 }, octane = 91, usage = 0.24 }, + [3] = { range = { 40, 0 }, octane = 89, usage = 0.26 }, + }, + } + + for key, value in pairs(data[Type]) do + if inRange(condition, value.range[1], value.range[2]) then + return { octane = value.octane, usage = value.usage } + end + end + return { octane = 87, usage = 0.4 } +end + +function tempGrowth(tmp, speed, Type, max) + if tmp == nil then return 0 end + + if Type == 'increase' then + if isOverHeatTemp(tmp, max) then return tmp end + + if inRange(speed, 0, 100) then + local max_temp = getCurrentSpeed_maxTemp(speed) + tmp = tmp + BalanceRecipe:SpeedRelated('OilwellTemperatureGrowth', speed) + if tmp >= max_temp then + tmp = max_temp + end + return tmp + else + return 0 + end + return 0 + end + -- decrease + if tmp > 0 then + tmp = tmp - 10 + else + tmp = 0 + end + return tmp +end diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_main.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_main.lua new file mode 100644 index 0000000..f32bf4e --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/server/server_main.lua @@ -0,0 +1,1034 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +--devices +-- =========================================== +-- Spawn / object Control +-- =========================================== +AddEventHandler('onResourceStart', function(resourceName) + if (GetCurrentResourceName() ~= resourceName) then + return + end + GlobalScirptData:wipeALL() + Sync_with_database() +end) +-- ========================================== +-- Update / server Side +-- ========================================== + +QBCore.Functions.CreateCallback('keep-oilrig:server:pump_fueloil', function(source, cb, data) + local player = QBCore.Functions.GetPlayer(source) + if player == nil then + TriggerClientEvent('QBCore:Notify', source, "Spiller ikke fundet!") + cb(false) + return + end + SendOilFuelToStorage(player, source, cb) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:PumpOilToStorageCallback', function(source, cb, data) + local player = QBCore.Functions.GetPlayer(source) + if player == nil then + TriggerClientEvent('QBCore:Notify', source, "Spiller ikke fundet!") + cb(false) + return + end + local oilrig, id = GlobalScirptData:getByHash(data) + if not oilrig then + cb(false) + return + end + local is_employee, is_owner = oilrig.is_employee(player.PlayerData.citizenid) + if not is_employee and not is_owner then + TriggerClientEvent('QBCore:Notify', source, "Du har ikke adgang til denne del!") + cb(false) + return + end + if oilrig.metadata.oil_storage <= 0 then + TriggerClientEvent('QBCore:Notify', source, "Lager er tomt!") + cb(false) + return + end + SendOilToStorage(oilrig, source, cb) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:getStorageData', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', citizenid) + if storage == false then + InitStorage({ + citizenid = citizenid, + name = player.PlayerData.name .. "'s inventar", + }, cb) + return + end + cb(storage) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:Withdraw', function(source, cb, data) + if not data then cb(false) return end + if not data.amount then cb(false) return end + if not data.type then cb(false) return end + if type(data.amount) == "string" then data.amount = tonumber(data.amount) end + if data.amount <= 0 then + TriggerClientEvent('QBCore:Notify', source, "Værdi skal være større end 0!", 'error') + return + end + + if not data.truck then + local barrel_max_size = Oilwell_config.Settings.capacity.oilbarell.size + local stash_size = 5 + + if data.amount > (barrel_max_size * stash_size) then + TriggerClientEvent('QBCore:Notify', source, "Ingen plads i inventar!", 'error') + TriggerClientEvent('QBCore:Notify', source, "Maksimum: " .. (barrel_max_size * stash_size) .. "/L", + 'error') + return + end + else + if data.amount > 100000 then + TriggerClientEvent('QBCore:Notify', source, "Maksimum: 100.000/L", + 'error') + return + end + end + + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', citizenid) + + if storage == false then + InitStorage({ + citizenid = citizenid, + name = player.PlayerData.name .. "'s inventar", + }) + TriggerClientEvent('QBCore:Notify', source, "Kunne ikke tilgå inventar!", 'error') + cb(false) + return + end + + local value = storage.metadata[data.type] + if value < data.amount then + TriggerClientEvent('QBCore:Notify', source, "Du kan ikke tage denne mængde!", 'error') + TriggerClientEvent('QBCore:Notify', source, "Anmodet: " .. data.amount .. " Nuværrende: " .. value, 'error') + cb(false) + return + end + + storage.metadata[data.type] = storage.metadata[data.type] - data.amount + storage.metadata.queue[#storage.metadata.queue + 1] = { + truck = data.truck, + type = data.type, + gal = data.amount, + avg_gas_octane = storage.metadata.avg_gas_octane + } + + if storage.metadata[data.type] < 1.0 then + -- remove waste + storage.metadata.avg_gas_octane = 87 + storage.metadata[data.type] = 0 + end + TriggerClientEvent('QBCore:Notify', source, "Vi gennemførte din anmodning!", 'success') + cb(true) +end) + +local function isWithdrawStashEmpty(Player) + local stash = 'Withdraw_' .. Player.PlayerData.citizenid + local result = MySQL.Sync.fetchScalar("SELECT items FROM stashitems WHERE stash= ?", { stash }) + if result == nil then + -- need to init stash + return false, -1 + end + result = json.decode(result) + local size = Tablelength(result) + if size >= 1 then + return false, size + else + return true, size + end +end + +local function divide_barells(barrel) + local barrel_max_size = Oilwell_config.Settings.capacity.oilbarell.size + local divide = math.floor(barrel.gal / barrel_max_size) + local leftover = barrel.gal % barrel_max_size + + local count = { + full_size = 0, + leftover = 0, + leftover_value = 0 + } + for i = 1, divide + 1, 1 do + if i ~= (divide + 1) then + count.full_size = count.full_size + 1 + else + if leftover ~= 0 then + count.leftover = count.leftover + 1 + count.leftover_value = leftover + end + end + end + return count +end + +local function add_oilbarell_2(Player, divide_res, barrel_type, barrel_avg_gas_octane) + -- send barells to withdraw stash + local barrel_max_size = Oilwell_config.Settings.capacity.oilbarell.size + local items = {} + local stash = 'Withdraw_' .. Player.PlayerData.citizenid + local result = MySQL.Sync.fetchAll("SELECT items FROM stashitems WHERE stash=?", { stash }) + local res = result[1] + if res == nil then return false end + if res.items == nil then return false end + res.items = json.decode(res.items) + if res.items == nil then return false end + local item_name = 'oilbarell' + local itemInfo = QBCore.Shared.Items[item_name:lower()] + + if barrel_type ~= 'gasoline' then + barrel_avg_gas_octane = 0 + end + + for i = 1, divide_res.full_size, 1 do + items[#items + 1] = { + name = itemInfo["name"], + amount = 1, + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], -- can not set weight + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = #items + 1, + info = { + type = barrel_type, + gal = barrel_max_size, + avg_gas_octane = barrel_avg_gas_octane + } + } + end + + for i = 1, divide_res.leftover, 1 do + items[#items + 1] = { + name = itemInfo["name"], + amount = 1, + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], -- can not set weight + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = #items + 1, + info = { + type = barrel_type, + gal = divide_res.leftover_value, + avg_gas_octane = barrel_avg_gas_octane + } + } + end + + MySQL.Async.execute("UPDATE stashitems SET items = ? WHERE stash = ?", { json.encode(items), stash }) +end + +RegisterNetEvent('keep-oilwell:server:purgeWithdrawStash', function() + local Player = QBCore.Functions.GetPlayer(source) + local stash = 'Withdraw_' .. Player.PlayerData.citizenid + MySQL.Async.execute("UPDATE stashitems SET items = '[]' WHERE stash = ?", { stash }) + TriggerClientEvent('QBCore:Notify', source, "Tømning fuldført!", 'success') +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:withdraw_from_queue', function(source, cb, Type) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', citizenid) + if storage == false then + InitStorage({ + citizenid = citizenid, + name = player.PlayerData.name .. "'s inventar", + }) + TriggerClientEvent('QBCore:Notify', source, "Kunne ikke tilgå inventar!", 'error') + cb(false) + return + end + if type(storage.metadata.queue) ~= "table" then + -- failsafe + storage.metadata.queue = {} + cb(false) + return + end + if type(storage.metadata.queue) == "table" and next(storage.metadata.queue) == nil then + TriggerClientEvent('QBCore:Notify', source, "Intet i kø!", 'error') + cb(false) + return + end + for key, barrel in pairs(storage.metadata.queue) do + + if barrel == nil then + goto here + end + + if not (barrel.truck == Type) then + goto here + end + if not barrel.truck then + local stashEmpty, size = isWithdrawStashEmpty(player) + if not stashEmpty and not (size == -1) then + TriggerClientEvent('QBCore:Notify', source, "Inventar er ikke tomt!", 'error') + cb(false) + return + elseif not stashEmpty and size == -1 then + TriggerClientEvent('QBCore:Notify', source, "Inventar skal være åbnet en enkelt gang!", + 'error') + cb(false) + return + end + local divide_res = divide_barells(barrel) + + -- calcualte barell cost + local cost_of_1 = Oilwell_config.Settings.capacity.oilbarell.cost + local total_cost = cost_of_1 * (divide_res.full_size + divide_res.leftover) + + local removemoeny = player.Functions.RemoveMoney('bank', total_cost, 'oil_barells') + if removemoeny then + add_oilbarell_2(player, divide_res, barrel.type, barrel.avg_gas_octane) + TriggerClientEvent('QBCore:Notify', source, "Anmodning fuldført!", 'success') + cb({ truck = false }) + storage.metadata.queue[key] = nil + return + else + TriggerClientEvent('QBCore:Notify', source, "Ikke nok penge i banken!", 'error') + end + cb(storage) + return + elseif barrel.truck and barrel.truck == true then + local divide_res = divide_barells(barrel) + + -- calcualte barell cost + local removemoeny = player.Functions.RemoveMoney('bank', 25000, 'oil_barells') + if removemoeny then + local items = Split_oilbarrel_size(divide_res, barrel.type, barrel.avg_gas_octane) + items.truck = true + TriggerClientEvent('QBCore:Notify', source, "Anmodning fuldført!", 'success') + cb(items) + storage.metadata.queue[key] = nil + return + else + TriggerClientEvent('QBCore:Notify', source, "Ikke nok penge i banken!", 'error') + end + cb(storage) + return + end + ::here:: + end + TriggerClientEvent('QBCore:Notify', source, "Du har intet i kø her!", 'error') + cb(false) +end) + +QBCore.Functions.CreateUseableItem('oilbarell', function(source, item) + local Player = QBCore.Functions.GetPlayer(source) +end) + +QBCore.Functions.CreateUseableItem('oilwell', function(source, item) + local Player = QBCore.Functions.GetPlayer(source) + local RemovedItem = Player.Functions.RemoveItem('oilwell', 1) + TriggerClientEvent('ps-inventory:client:ItemBox', source, QBCore.Shared.Items['oilwell'], "remove") + + if item.amount >= 1 and RemovedItem == true then + TriggerClientEvent('keep-oilrig:client:spawn', source) + end +end) + +function Split_oilbarrel_size(divide_res, barrel_type, barrel_avg_gas_octane) + local barrel_max_size = Oilwell_config.Settings.capacity.oilbarell.size + local item_name = 'oilbarell' + local itemInfo = QBCore.Shared.Items[item_name:lower()] + local items = {} + + for i = 1, divide_res.full_size, 1 do + items[#items + 1] = { + name = itemInfo["name"], + amount = 1, + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], -- can not set weight + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = #items + 1, + info = { + type = barrel_type, + gal = barrel_max_size, + avg_gas_octane = barrel_avg_gas_octane + } + } + end + + for i = 1, divide_res.leftover, 1 do + items[#items + 1] = { + name = itemInfo["name"], + amount = 1, + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], -- can not set weight + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = #items + 1, + info = { + type = barrel_type, + gal = divide_res.leftover_value, + avg_gas_octane = barrel_avg_gas_octane + } + } + end + return items +end + +RegisterNetEvent('keep-oilrig:server:updateSpeed', function(inputData, id) + local player = QBCore.Functions.GetPlayer(source) + if player == nil then return end + -- validate speed for 0 - 100 + local oilrig = GlobalScirptData:read(id) + local is_employee, is_owner = oilrig.is_employee(player.PlayerData.citizenid) + if not is_employee and not is_owner then + TriggerClientEvent('QBCore:Notify', source, "Du har ikke adgang til denne oliebrønd!", 'error') + return + end + + local speed = tonumber(inputData.speed) + if not (0 <= speed and speed <= 100) then + TriggerClientEvent('QBCore:Notify', source, 'Hastighed skal være mellem 0-100', "error") + return + end + + oilrig.metadata.speed = speed + -- sync speed on other clients + TriggerClientEvent('keep-oilrig:client:syncSpeed', -1, id, speed) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:get_CDU_Data', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local CDU = GlobalScirptData:getDeviceByCitizenId('oilrig_cdu', citizenid) + + if CDU == false then + Init_CDU(citizenid, cb) + return + end + + -- callback must return CDU's object reason ==> reopen menu with new values + cb(CDU) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:set_CDU_temp', function(source, cb, inputData) + if type(inputData.temp) == "string" then + inputData.temp = tonumber(inputData.temp) + end + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local CDU = GlobalScirptData:getDeviceByCitizenId('oilrig_cdu', citizenid) + CDU.metadata.req_temp = inputData.temp + -- callback must return CDU's object reason ==> reopen menu with new values + cb(CDU) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:switchPower_of_CDU', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local CDU = GlobalScirptData:getDeviceByCitizenId('oilrig_cdu', citizenid) + if CDU.metadata.state == false then + CDU.metadata.state = true + else + CDU.metadata.state = false + end + + -- callback must return CDU's object reason ==> reopen menu with new values + cb(CDU) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:pumpCrudeOil_to_CDU', function(source, cb, inputData) + if type(inputData.amount) == "string" then + inputData.amount = tonumber(inputData.amount) + end + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local CDU = GlobalScirptData:getDeviceByCitizenId('oilrig_cdu', citizenid) + local storage = GlobalScirptData:getDeviceByCitizenId('oilrig_storage', citizenid) + + if storage == false then + InitStorage({ + citizenid = citizenid, + name = player.PlayerData.name .. "'s inventar", + }) + TriggerClientEvent('QBCore:Notify', source, "Kunne ikke tilgå inventar!", 'error') + cb(false) + return + end + + if inputData.amount <= 0 then + TriggerClientEvent('QBCore:Notify', source, "Skal være mere end 0", 'error') + cb(CDU) + return + end + + if storage.metadata.crudeOil == 0.0 then + TriggerClientEvent('QBCore:Notify', source, "Inventar tomt", 'error') + cb(CDU) + return + end + + if storage.metadata.crudeOil >= inputData.amount then + storage.metadata.crudeOil = storage.metadata.crudeOil - inputData.amount + CDU.metadata.oil_storage = CDU.metadata.oil_storage + inputData.amount + end + -- callback must return CDU's object reason ==> reopen menu with new values + cb(CDU) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:ShowBlender', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local blender = GlobalScirptData:getDeviceByCitizenId('oilrig_blender', citizenid) + if blender == false then + Init_Blender(citizenid, cb) + return + end + + cb(blender) +end) + +local function inRange(x, min, max) + return (x >= min and x <= max) +end + +QBCore.Functions.CreateCallback('keep-oilrig:server:toggle_blender', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local blender = GlobalScirptData:getDeviceByCitizenId('oilrig_blender', citizenid) + if blender.metadata.state == false then + blender.metadata.state = true + else + blender.metadata.state = false + end + cb(blender) +end) + +QBCore.Functions.CreateCallback('keep-oilrig:server:recipe_blender', function(source, cb, inputData) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local blender = GlobalScirptData:getDeviceByCitizenId('oilrig_blender', citizenid) + + for _, value in pairs(inputData) do + local current_num = tonumber(value) + if not inRange(current_num, 0, 100) then + TriggerClientEvent('QBCore:Notify', source, "Skal være mellem 0-100", 'error') + return + end + inputData[_] = current_num + end + + blender.metadata.recipe.heavy_naphtha = inputData.heavy_naphtha or blender.metadata.recipe.heavy_naphtha + blender.metadata.recipe.light_naphtha = inputData.light_naphtha or blender.metadata.recipe.light_naphtha + blender.metadata.recipe.other_gases = inputData.other_gases or blender.metadata.recipe.other_gases + + --new elements + blender.metadata.recipe.diesel = inputData.diesel or blender.metadata.recipe.diesel + blender.metadata.recipe.kerosene = inputData.kerosene or blender.metadata.recipe.kerosene + + cb(blender) +end) + +local current_transport_stock = { + crudeOil = 0, + fuel_oil = 0, + gasoline = 0 +} +local TRANSPORT = Oilwell_config.Transport + +local function change_item_info(Player, slot, info) + if Player.PlayerData.items[slot] then + Player.PlayerData.items[slot].info = info + end + Player.Functions.SetInventory(Player.PlayerData.items, true) +end + +local function reachedMaxStock(Type) + local max = TRANSPORT.max_stock + return (current_transport_stock[Type] >= max) +end + +local function canWeAcceptMoreStock(Type, amount) + local max = TRANSPORT.max_stock + return not (current_transport_stock[Type] + amount >= max) +end + +local function remove_item(source, Player, name, slot) + Player.Functions.RemoveItem(name, 1, slot) + TriggerClientEvent('ps-inventory:client:ItemBox', source, QBCore.Shared.Items[name], "remove") +end + +QBCore.Functions.CreateCallback('keep-oilrig:server:oil_transport:fillTransportWell', function(source, cb, amount) + amount = tonumber(amount) -- just in case + local player = QBCore.Functions.GetPlayer(source) + local oil_barrel = player.Functions.GetItemByName('oilbarell') + local msg_string = "" + + if not oil_barrel then + TriggerClientEvent('QBCore:Notify', source, 'Du har ikke en olietønde!', 'error') + return + end + local current_info = oil_barrel.info + + if not current_info.type then + TriggerClientEvent('QBCore:Notify', source, 'Kunne ikke finde oile-type', 'error') + return + end + + if not (current_info.type == 'crudeOil' or current_info.type == 'fuel_oil' or current_info.type == 'gasoline') then + TriggerClientEvent('QBCore:Notify', source, 'Vi eksporterer ikke denne type olie!', 'error') + return + end + + if reachedMaxStock(current_info.type) then + -- when we reached max stock + TriggerClientEvent('QBCore:Notify', source, 'Vi tager ikke imod flere tilbud. Kom igen senere!', + 'primary') + return + end + + if not canWeAcceptMoreStock(current_info.type, amount) then + -- when buying results in more oil than what we need + local max_amount = math.floor(TRANSPORT.max_stock - current_transport_stock) + msg_string = "Vi kan kun acceptere op til %d liter" + msg_string = string.format(msg_string, max_amount) + TriggerClientEvent('QBCore:Notify', source, '', 'error') + return + end + + if current_info.gal < amount then + -- when they don't have what they want to sell + msg_string = 'Du vil sælge: %d, men har kun: %d' + msg_string = string.format(msg_string, amount, current_info.gal) + TriggerClientEvent('QBCore:Notify', source, msg_string, 'error') + cb(false) + return + end + + local gender = Oilwell_config.Locale.info.mr + if player.PlayerData.charinfo.gender == 1 then + gender = Oilwell_config.Locale.info.mrs + end + local charinfo = player.PlayerData.charinfo + + local cost = TRANSPORT.prices[current_info.type] * amount + if current_info.gal > amount then + -- asking less than what they have + current_info.gal = math.floor(current_info.gal - amount) + -- this function can be called just once after conditions but this should prevent switching slots + change_item_info(player, oil_barrel.slot, oil_barrel.info) + + player.Functions.AddMoney("bank", cost, 'crude_oil_transport') + + msg_string = 'Du solgte: %d liter for: %.2f,-' + msg_string = string.format(msg_string, amount, cost) + TriggerClientEvent('QBCore:Notify', source, msg_string, 'success') + + TriggerClientEvent('keep-oilrig:client:local_mail_sender', source, { + gender = gender, + charinfo = charinfo, + refund = 0, + money = cost, + amount = amount + }) + elseif current_info.gal == amount and amount ~= 0 then + -- asking for all they have + current_info.gal = 0 + -- this function can be called just once after conditions but this should prevent switching slots + change_item_info(player, oil_barrel.slot, oil_barrel.info) + remove_item(source, player, 'oilbarell', oil_barrel.slot) + -- money for what they sold + local money = (cost) + TRANSPORT.barell_refund + player.Functions.AddMoney("bank", money, 'crude_oil_transport') + + msg_string = 'Du solgte: %d liter for: %.2f,- + tønde refundering: %.2f,-' + msg_string = string.format(msg_string, amount, cost, TRANSPORT.barell_refund) + TriggerClientEvent('QBCore:Notify', source, msg_string, 'success') + + TriggerClientEvent('keep-oilrig:client:local_mail_sender', source, { + gender = gender, + charinfo = charinfo, + refund = TRANSPORT.barell_refund, + money = cost, + amount = amount + }) + else + -- invalid + -- or they ask for much more than they have + TriggerClientEvent('QBCore:Notify', source, 'Du har ikke en tønde, ellers er den tom!', 'error') + cb(false) + return + end + + current_transport_stock[current_info.type] = current_transport_stock[current_info.type] + amount + cb(true) +end) + +RegisterNetEvent('keep-oilrig:server:oil_transport:checkPrice', function() + local names = { + crudeOil = 'Råoile', + gasoline = 'Brændstof', + fuel_oil = 'Brændselsolie' + } + local msg_string = "Vores nuværrende lager af [%s] er: %d/%d. Pris per liter: %.2f,-" + for key, value in pairs(current_transport_stock) do + local s = string.format(msg_string, names[key], math.floor(value), TRANSPORT.max_stock, TRANSPORT.prices[key]) + TriggerClientEvent('QBCore:Notify', source, s, 'primary', 7500) + end + +end) + +-- ======================================= +-- Send Data / to Client +-- ======================================= + +---send oilrigs data to loaded player +---@param source integer +---@param cb table +QBCore.Functions.CreateCallback('keep-oilrig:server:getNetIDs', function(source, cb) + local player = QBCore.Functions.GetPlayer(source) + local citizenid = player.PlayerData.citizenid + local temp = {} + for key, value in pairs(GlobalScirptData:readAll()) do + temp[key] = deepcopy(value) + temp[key].employees_list = nil + temp[key].employees = nil + temp[key].is_employee = nil + temp[key].metadata = nil + temp[key].citizenid = nil + + if value.citizenid == citizenid then + temp[key].isOwner = true + else + temp[key].isOwner = false + end + end + cb(temp) +end) + +-- ====================================== +-- Register / from Client +-- ====================================== + +--- create oilrig and initialize it's data into database +---@param source integer +---@param cb 'calback' +---@param coords table +---@return 'NetId' +QBCore.Functions.CreateCallback('keep-oilrig:server:createNewOilrig', function(source, cb, coords) + local rigmodel = GetHashKey('p_oil_pjack_03_s') + + local oilrig = CreateObject(rigmodel, coords.x, coords.y, coords.z, 1, 1, 0) + while not DoesEntityExist(oilrig) do + Wait(50) + end + local NetId = NetworkGetNetworkIdFromEntity(oilrig) + cb(NetId) +end) + +---register oilrig to player by their current cid +QBCore.Functions.CreateCallback('keep-oilrig:server:regiserOilrig', function(source, cb, inputData) + -- get player by entered cid + local cid = tonumber(inputData.cid) + local player = QBCore.Functions.GetPlayer(cid) + if player ~= nil then + local PlayerData = player.PlayerData + local entity = NetworkGetEntityFromNetworkId(inputData.netId) + local coord = GetEntityCoords(entity) + local rotation = GetEntityRotation(entity) + local position = { + coord = { + x = coord.x, + y = coord.y, + z = coord.z, + }, + rotation = { + x = rotation.x, + y = rotation.y, + z = rotation.z, + } + } + local metadata = { + speed = 0, + temp = 0, + duration = 0, + secduration = 0, + oil_storage = 0, + part_info = { + belt = 0, + polish = 0, + clutch = 0, + } + } + local hash = RandomHash(15) + local id = GeneralInsert({ + citizenid = PlayerData.citizenid, + name = inputData.name, + oilrig_hash = hash, + position = position, + metadata = metadata, + state = false + }) + GlobalScirptData:newOilwell({ + id = id, + citizenid = PlayerData.citizenid, + position = position, + name = inputData.name, + state = false, + oilrig_hash = hash, + metadata = metadata + }, {}) + TriggerClientEvent('keep-oilwell:client:force_reload', -1) + cb(true) + else + TriggerClientEvent('QBCore:Notify', source, "Kunne ikke finde spiller med det BorgerID!") + cb(false) + end +end) + +function GetOilPumpItems(oilrig_hash) + local items = {} + local stash = 'oilPump_' .. oilrig_hash + local result = MySQL.Sync.fetchAll("SELECT items FROM stashitems WHERE stash=?", { stash }) + local res = result[1] + if res == nil then return false end + if res.items == nil then return false end + res.items = json.decode(res.items) + if res.items == nil then return false end + + for k, item in pairs(res.items) do + local itemInfo = QBCore.Shared.Items[item.name:lower()] + items[item.slot] = { + name = itemInfo["name"], + amount = tonumber(item.amount), + info = item.info ~= nil and item.info or "", + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = item.slot, + } + end + return items +end + +local function isOneOfItems(item) + local s = { + ['oilfilter'] = 'polish', + ['reliefvalvestring'] = 'polish', + ['skewgear'] = 'kobling', + ['timingchain'] = 'bælte', + ['driveshaft'] = 'drivaksel' + } + + for _, part in pairs(s) do + if item.name == _ then + return item, part + end + end + return nil +end + +QBCore.Functions.CreateCallback('keep-oilwell:server:fix_oil_well', function(source, cb, oilrig_hash) + local Player = QBCore.Functions.GetPlayer(source) + local items = GetOilPumpItems(oilrig_hash) + local stash = 'oilPump_' .. oilrig_hash + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then cb(false) return end + local is_employee, is_owner = oil_well.is_employee(Player.PlayerData.citizenid) + if not is_employee and not is_owner then + cb(false) + return + end + for _, data in pairs(items) do + local _item, part = isOneOfItems(data) + if _item then + local increase = oil_well.metadata.part_info[part] + 10 * _item.amount + if increase >= 0 and increase <= 100 then + oil_well.metadata.part_info[part] = increase + elseif increase >= 100 then + oil_well.metadata.part_info[part] = 100 + else + oil_well.metadata.part_info[part] = 0 + end + end + end + + TriggerClientEvent('QBCore:Notify', source, "Dele brugt til at fikse oliebrønd.", 'primary') + MySQL.Async.execute("UPDATE stashitems SET items = '[]' WHERE stash = ?", { stash }) + cb(true) +end) + +QBCore.Functions.CreateCallback('keep-oilwell:server:is_employee', function(source, cb, oilrig_hash) + local Player = QBCore.Functions.GetPlayer(source) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then cb(false) return end + cb(oil_well.is_employee(Player.PlayerData.citizenid)) +end) + +QBCore.Functions.CreateCallback('keep-oilwell:server:employees_list', function(source, cb, oilrig_hash) + local Player = QBCore.Functions.GetPlayer(source) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then cb(false) return end + local is_employee, is_owner = oil_well.is_employee(Player.PlayerData.citizenid) + if not is_employee and not is_owner then + TriggerClientEvent('QBCore:Notify', source, "Du kan ikke se denne liste!", 'error') + cb(false) + return + end + local list = deepcopy(oil_well.employees_list()) + for index, value in ipairs(list) do + value.id = nil + local Player = QBCore.Functions.GetPlayerByCitizenId(value.citizenid) + if Player then + value.charinfo = Player.PlayerData.charinfo + value.online = true + else + Player = QBCore.Player.GetOfflinePlayer(value.citizenid) + if not Player then + value.charinfo = { + firstname = 'Slettet', + lastname = '' + } + value.online = false + end + end + end + cb(list) +end) + +RegisterNetEvent('keep-oilwell:server:add_employee', function(oilrig_hash, state_id) + state_id = tonumber(state_id) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then return end + local _, is_owner = oil_well.is_employee(Player.PlayerData.citizenid) + if not is_owner then + TriggerClientEvent('QBCore:Notify', src, "Du skal være ejer af denne oliebrønd!", 'error') + return + end + local new_employee = QBCore.Functions.GetPlayer(state_id) + if not new_employee then + TriggerClientEvent('QBCore:Notify', src, "Forkert stats ID!", 'error') + return + end + + if new_employee.PlayerData.citizenid == oil_well.citizenid then + TriggerClientEvent('QBCore:Notify', src, "Du kan ikke tilføje ejeren som medarbejder", 'error') + return + end + + local sqlQuery = 'INSERT INTO oilcompany_employees (citizenid, oilrig_hash) VALUES (:citizenid, :oilrig_hash)' + local QueryData = { + ['citizenid'] = new_employee.PlayerData.citizenid, + ['oilrig_hash'] = oilrig_hash, + } + MySQL.Async.execute(sqlQuery, QueryData, function() + local e_sql = 'SELECT * FROM oilcompany_employees WHERE oilrig_hash = ?' + oil_well.employees = MySQL.Sync.fetchAll(e_sql, { oilrig_hash }) + local id = #oil_well.employees + 1 + oil_well.employees[id] = { + id = id, + oilrig_hash = oil_well.oilrig_hash, + citizenid = oil_well.citizenid + } + TriggerClientEvent('QBCore:Notify', src, "Ny medarbejder tilføjet til listen", 'success') + end) +end) + +RegisterNetEvent('keep-oilwell:server:remove_employee', function(oilrig_hash, citizenid) + if type(oilrig_hash) ~= 'string' or type(citizenid) ~= 'string' then + -- print('wrong type') + return + end + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then return end + if not citizenid then return end + local _, is_owner = oil_well.is_employee(Player.PlayerData.citizenid) + if not is_owner then + TriggerClientEvent('QBCore:Notify', src, "Du skal være ejer af denne oliebrønd!", 'error') + return + end + + if citizenid == oil_well.citizenid then + TriggerClientEvent('QBCore:Notify', src, "Du kan ikke fyre dig selv", 'error') + return + end + + local sqlQuery = 'DELETE FROM oilcompany_employees WHERE citizenid = ?' + local QueryData = { + citizenid + } + MySQL.Async.execute(sqlQuery, QueryData, function() + local e_sql = 'SELECT * FROM oilcompany_employees WHERE oilrig_hash = ?' + oil_well.employees = MySQL.Sync.fetchAll(e_sql, { oilrig_hash }) + local id = #oil_well.employees + 1 + oil_well.employees[id] = { + id = id, + oilrig_hash = oil_well.oilrig_hash, + citizenid = oil_well.citizenid + } + TriggerClientEvent('QBCore:Notify', src, "Medarbejder fyret!", 'success') + end) +end) + +QBCore.Functions.CreateCallback('keep-oilwell:server:oilwell_metadata', function(source, cb, oilrig_hash) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then cb(false) return end + cb(oil_well.metadata) +end) + +RegisterNetEvent('keep-oilwell:server:remove_oilwell', function(oilrig_hash) + -- flag a oilwell as deleted + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local oil_well = GlobalScirptData:getByHash(oilrig_hash) + if not oil_well then + return --print('oilwell not found', src, oilrig_hash) + end + if not Player.PlayerData.job.isboss then + -- DropPlayer(src, 'you are not CEO') + return + end + + local sqlQuery = 'UPDATE oilrig_position SET deleted = ? WHERE oilrig_hash = ?' + MySQL.Async.execute(sqlQuery, { 1, oil_well.oilrig_hash }, function() + TriggerClientEvent('QBCore:Notify', src, + "Destruktions-anmodning modtaget! Oliebrønden vil forsvinde efter næste tsunami!", + 'success' + ) + end) +end) +-- =========================== +-- Commands +-- =========================== + +QBCore.Commands.Add('create', 'Lav oliebrønd', {}, false, function(source, args) + if args[1] == 'oilwell' then + TriggerClientEvent('keep-oilrig:client:spawn', source, args[1]) + end +end, 'admin') + +QBCore.Commands.Add('togglejob', 'togglejob', {}, false, function(source, args) + local PlayerJob = QBCore.Functions.GetPlayer(source).PlayerData.job + TriggerClientEvent('keep-oilrig:client:goOnDuty', source, PlayerJob) +end, 'admin') diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/shared/shared_main.lua b/resources/[qb]/[qb_jobs]/keep-oilwell/shared/shared_main.lua new file mode 100644 index 0000000..06f986e --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/shared/shared_main.lua @@ -0,0 +1,120 @@ +function RandomHash(length) + local res = "" + for i = 1, length do + res = res .. string.char(math.random(97, 122)) + end + return res +end + +---print tables : debug +---@param node table +function print_table(node) + local cache, stack, output = {}, {}, {} + local depth = 1 + local output_str = "{\n" + + while true do + local size = 0 + for k, v in pairs(node) do + size = size + 1 + end + + local cur_index = 1 + for k, v in pairs(node) do + if (cache[node] == nil) or (cur_index >= cache[node]) then + + if (string.find(output_str, "}", output_str:len())) then + output_str = output_str .. ",\n" + elseif not (string.find(output_str, "\n", output_str:len())) then + output_str = output_str .. "\n" + end + + -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings + table.insert(output, output_str) + output_str = "" + + local key + if (type(k) == "number" or type(k) == "boolean") then + key = "[" .. tostring(k) .. "]" + else + key = "['" .. tostring(k) .. "']" + end + + if (type(v) == "number" or type(v) == "boolean") then + output_str = output_str .. string.rep('\t', depth) .. key .. " = " .. tostring(v) + elseif (type(v) == "table") then + output_str = output_str .. string.rep('\t', depth) .. key .. " = {\n" + table.insert(stack, node) + table.insert(stack, v) + cache[node] = cur_index + 1 + break + else + output_str = output_str .. string.rep('\t', depth) .. key .. " = '" .. tostring(v) .. "'" + end + + if (cur_index == size) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + else + output_str = output_str .. "," + end + else + -- close the table + if (cur_index == size) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + end + end + + cur_index = cur_index + 1 + end + + if (size == 0) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + end + + if (#stack > 0) then + node = stack[#stack] + stack[#stack] = nil + depth = cache[node] == nil and depth + 1 or depth - 1 + else + break + end + end + + -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings + table.insert(output, output_str) + output_str = table.concat(output) + + -- print(output_str) +end + +function Round(num, dp) + --[[ + round a number to so-many decimal of places, which can be negative, + e.g. -1 places rounds to 10's, + + examples + 173.2562 rounded to 0 dps is 173.0 + 173.2562 rounded to 2 dps is 173.26 + 173.2562 rounded to -1 dps is 170.0 + ]] -- + local mult = 10 ^ (dp or 0) + return math.floor(num * mult + 0.5) / mult +end + +function Tablelength(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end + +Colors = { + red = "\027[31m", + green = "\027[32m", + orange = "\027[33m", + cyan = "\027[36m", + gray = "\027[90m", + grey = "\027[90m", + light_green = "\027[92m", + yellow = "\027[93m", + blue = "\027[94m", +} diff --git a/resources/[qb]/[qb_jobs]/keep-oilwell/sql.sql b/resources/[qb]/[qb_jobs]/keep-oilwell/sql.sql new file mode 100644 index 0000000..9779d31 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/keep-oilwell/sql.sql @@ -0,0 +1,49 @@ +CREATE TABLE IF NOT EXISTS `oilrig_position` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `name` varchar(50) DEFAULT NULL, + `oilrig_hash` varchar(50) DEFAULT NULL, + `position` TEXT NOT NULL DEFAULT '0', + `metadata` TEXT NOT NULL DEFAULT '0', + `state` BOOLEAN NOT NULL DEFAULT FALSE, + `deleted` BOOLEAN NOT NULL DEFAULT FALSE, + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `oilrig_storage` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `name` varchar(50) DEFAULT NULL, + `metadata` TEXT NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `oilrig_cdu` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `metadata` TEXT NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `oilrig_blender` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `metadata` TEXT NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +-- Patch 1.1.0 new part +CREATE TABLE IF NOT EXISTS `oilcompany_employees` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `oilrig_hash` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +-- for pre exsting users to update their database don't use it on a fresh install +-- ALTER TABLE `oilrig_position` ADD `deleted` BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/.gitattributes b/resources/[qb]/[qb_jobs]/kloud-farmjob/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/LICENSE b/resources/[qb]/[qb_jobs]/kloud-farmjob/LICENSE new file mode 100644 index 0000000..e62ec04 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/README.md b/resources/[qb]/[qb_jobs]/kloud-farmjob/README.md new file mode 100644 index 0000000..8309b65 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/README.md @@ -0,0 +1,209 @@ +# kloud-farmjob + +Dive into the world of a simple farmer, gather crops and sell it for money! + +# Features + +* Highly Configurable +* Easily Add Locations +* Highly Optimized (0.00ms Idle & 0.00 ~ 0.09 ms Active) +* Usage of Targeting Script for more immersive experience +* Smooth Animations + +# Preview + +https://youtu.be/xaWnb6a1-Uc + +# Dependencies + +**Required** + +* [ox_lib](https://github.com/overextended/ox_lib) + +**Framework** + +- [qb-core](https://github.com/qbcore-framework/qb-core) +- [qbx-core](https://github.com/Qbox-project/qbx-core) +- [es_extended](https://github.com/esx-framework/esx_core) + +**Target** + +- [qb-target](https://github.com/qbcore-framework/qb-target) +- [ox_target](https://github.com/overextended/ox_target) + +**Inventory** + +- [qb-inventory](https://github.com/qbcore-framework/qb-inventory) +- [lj-inventory](https://github.com/loljoshie/lj-inventory) +- [ps-inventoy](https://github.com/Project-Sloth/ps-inventory) +- [ox_inventory](https://overextended.dev/ox_inventory) + +# Installation + +Join my [Discord Server](https://discord.gg/DbqC2SWzJk) for updates + +## Configuration + +### Language + +Add this to your server.cfg +```cfg +setr ox:locale en +``` + +## server.cfg + +```cfg +ensure FRAMEWORK # es_extended / qb-core +ensure ox_lib +ensure TARGET # ox_target / qb-target +ensure INVENTORY # ox_inventory / qb-inventory / lj-inventory +ensure kloud-farm +``` + +## For qb-core + +### qb-core\shared\items.lua + +```lua + ['potato'] = {['name'] = 'potato', ['label'] = 'Potato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'potato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Po-ta-to'}, + ['dirty_potato'] = {['name'] = 'dirty_potato', ['label'] = 'Dirty Potato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_potato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Po-ta-to'}, + ['tomato'] = {['name'] = 'tomato', ['label'] = 'Tomato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'tomato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To-ma-to'}, + ['dirty_tomato'] = {['name'] = 'dirty_tomato', ['label'] = 'Dirty Tomato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_tomato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To-ma-to'}, + ['coffee_beans'] = {['name'] = 'coffee_beans', ['label'] = 'Coffee Beans', ['weight'] = 350, ['type'] = 'item', ['image'] = 'coffee_beans.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Wakey wakey!'}, + ['dirty_coffee_beans'] = {['name'] = 'dirty_coffee_beans', ['label'] = 'Dirty Coffee Beans', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_coffee_beans.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Wakey wakey!'}, + ['cabbage'] = {['name'] = 'cabbage', ['label'] = 'Cabbage', ['weight'] = 350, ['type'] = 'item', ['image'] = 'cabbage.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Let-tuce? No!'}, + ['dirty_cabbage'] = {['name'] = 'dirty_cabbage', ['label'] = 'Dirty Cabbage', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_cabbage.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Let-tuce? No!'}, + ['orange'] = {['name'] = 'orange', ['label'] = 'Orange', ['weight'] = 350, ['type'] = 'item', ['image'] = 'orange.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The talking orange!'}, + ['dirty_orange'] = {['name'] = 'dirty_orange', ['label'] = 'Dirty Orange', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_orange.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The talking orange!'}, + ['trowel'] = {['name'] = 'trowel', ['label'] = 'Trowel', ['weight'] = 350, ['type'] = 'item', ['image'] = 'trowel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mini-shovel yes'}, + ['shovel'] = {['name'] = 'shovel', ['label'] = 'Shovel', ['weight'] = 350, ['type'] = 'item', ['image'] = 'shovel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Legit shovel yes'}, +``` + +## For ox_inventory + +### ox_inventory\data\items.lua + +```lua + ['trowel'] = { + label = 'Trowel', + weight = 500, + decay = true, + stack = false, + close = false, + description = 'Diggy Diggy Diggy?', + }, + + ['shovel'] = { + label = 'Shovel', + weight = 1000, + decay = true, + stack = false, + close = false, + description = 'Diggy Diggy Diggy?', + }, + + ['dirty_potato'] = { + label = 'Dirty Potato', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Potato potato but dirty dirty?', + }, + + ['potato'] = { + label = 'Potato', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Potato potato?', + }, + + ['dirty_cabbage'] = { + label = 'Dirty Cabbage', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Cabby cabby but dirty dirty?', + }, + + ['cabbage'] = { + label = 'Cabbage', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Cabby cabby?', + }, + + ['dirty_tomato'] = { + label = 'Dirty Tomato', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'To-ma-to but dirty', + }, + + ['tomato'] = { + label = 'Tomato', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'To-ma-to', + }, + + ['dirty_orange'] = { + label = 'Dirty Orange', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'It talks!!!!', + }, + + ['orange'] = { + label = 'Orange', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'It talks!!!!', + }, + + ['dirty_coffee_beans'] = { + label = 'Dirty Coffee Beans', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Ohh wakey wakey but dirty', + }, + + ['coffee_beans'] = { + label = 'Coffee Beans', + weight = 250, + degrade = 7160, + decay = true, + stack = true, + close = false, + description = 'Ohh wakey wakey but dirty', + }, +``` + +# Support & Suggestions + +Contact me at my discord @ybarra. or join my Discord Server!
![Discord Server](https://discordapp.com/api/guilds/1131198002976014377/widget.png?style=shield) diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/esx.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/esx.lua new file mode 100644 index 0000000..faed9a1 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/esx.lua @@ -0,0 +1,37 @@ +if GetResourceState("es_extended") ~= "started" then return end + +ESX = exports["es_extended"]:getSharedObject() + +PlayerData = {} +PlayerJob = {} +PlayerLoaded = false + +RegisterNetEvent('esx:playerLoaded', function(xPlayer) + JobInfo = xPlayer.job + UpdateJobInfo(JobInfo) + + PlayerLoaded = true +end) + +RegisterNetEvent('esx:onPlayerLogout', function() + table.wipe(PlayerData) + table.wipe(PlayerJob) +end) + +RegisterNetEvent('esx:setJob', function(JobInfo) + UpdateJobInfo(JobInfo) +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() ~= resourceName then return end + + PlayerData = ESX.GetPlayerData() + UpdateJobInfo(PlayerData.job) + PlayerLoaded = ESX.PlayerLoaded +end) + +UpdateJobInfo = function(info) + PlayerJob.grade = {} + PlayerJob.name = info.name + PlayerJob.grade.level = info.grade +end diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/qb.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/qb.lua new file mode 100644 index 0000000..b796d64 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/client/qb.lua @@ -0,0 +1,52 @@ +if GetResourceState("qb-core") ~= "started" then return end + +QBCore = exports['qb-core']:GetCoreObject() + +PlayerData = {} +PlayerJob = {} +PlayerLoaded = false + +---@diagnostic disable-next-line: param-type-mismatch +AddStateBagChangeHandler('isLoggedIn', nil, function(_bagName, _key, value, _reserved, _replicated) + if value then + PlayerData = QBCore.Functions.GetPlayerData() + UpdateJobInfo(PlayerData.job) + else + table.wipe(PlayerData) + table.wipe(PlayerJob) + end + PlayerLoaded = value +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + JobInfo = QBCore.Functions.GetPlayerData().job + UpdateJobInfo(JobInfo) +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + table.wipe(PlayerData) + table.wipe(PlayerJob) +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + UpdateJobInfo(JobInfo) +end) + +RegisterNetEvent('QBCore:Player:SetPlayerData', function(newPlayerData) + local invokingResource = GetInvokingResource() + if invokingResource and invokingResource ~= 'qb-core' then return end + PlayerData = newPlayerData +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() ~= resourceName or not LocalPlayer.state.isLoggedIn then return end + PlayerData = QBCore.Functions.GetPlayerData() + UpdateJobInfo(PlayerData.job) + PlayerLoaded = true +end) + +UpdateJobInfo = function(info) + PlayerJob.grade = {} + PlayerJob.name = info.name + PlayerJob.grade.level = info.grade.level +end diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/esx.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/esx.lua new file mode 100644 index 0000000..f25ea07 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/esx.lua @@ -0,0 +1,47 @@ +if GetResourceState("es_extended") ~= "started" then return end + +CreateThread(function() + Wait(200) + -- print("^5ESX found! Loading ESX functions^0") + if GetResourceState("ox_inventory") ~= "started" then + -- print("^1Can't find ox_inventory, start it before this script^0") + end +end) + +ESX = exports['es_extended']:getSharedObject() + +GetPlayer = function(target) + local Player = ESX.GetPlayerFromId(target) + + return Player +end + +AddMoney = function(target, type, amount, reason) + local Player = GetPlayer(target) + + if type == "cash" then + type = "money" + end + + return Player.addAccountMoney(type, amount) +end + +RemoveMoney = function(target, type, amount, reason) + local Player = GetPlayer(target) + + if type == "cash" then + type = "money" + end + + return Player.removeAccountMoney(type, amount) +end + +GetMoney = function(target, type) + local Player = GetPlayer(target) + + if type == "cash" then + type = "money" + end + + return Player.getAccount(type).money +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/qb.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/qb.lua new file mode 100644 index 0000000..c42b7a9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/framework/server/qb.lua @@ -0,0 +1,26 @@ +if GetResourceState("qb-core") ~= "started" then return end +QBCore = exports['qb-core']:GetCoreObject() + +GetPlayer = function(target) + local Player = QBCore.Functions.GetPlayer(target) + + return Player +end + +AddMoney = function(target, type, amount, reason) + local Player = GetPlayer(target) + + return Player.Functions.AddMoney(type, amount, reason) +end + +RemoveMoney = function(target, type, amount, reason) + local Player = GetPlayer(target) + + return Player.Functions.RemoveMoney(type, amount, reason) +end + +GetMoney = function(target, type) + local Player = GetPlayer(target) + + return Player.PlayerData.money[type] +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/fxmanifest.lua new file mode 100644 index 0000000..2d24e57 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/fxmanifest.lua @@ -0,0 +1,37 @@ +fx_version 'cerulean' +game 'gta5' + +lua54 'yes' + +author 'kloud' +description 'Advanced Farming Job Made for QB/Qbox/ESX by Kloud' +version '1.0.0' + +shared_scripts { + '@ox_lib/init.lua', + 'shared/*.lua' +} + +client_scripts { + 'target/*.lua', + 'modules/**/*.lua', + 'inventory/client/*.lua', + 'framework/client/*.lua', + 'init.lua', +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'inventory/server/*.lua', + 'framework/server/*.lua', + 'server.lua', +} + +files { + 'locales/*.json' +} + +dependencies { + 'oxmysql', + 'ox_lib' +} diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/init.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/init.lua new file mode 100644 index 0000000..55e8e57 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/init.lua @@ -0,0 +1,221 @@ +_T = { + Zone = {}, + Props = {}, + Blip = {}, + PickedTrees = {}, + Peds = {}, +} + +_G = { + InZone = false, + IsBusy = false, + CurrentZone = nil, + Cooldown = false +} + +Start = function() + for zone, info in pairs(KloudDev.Locations) do + _T.Zone[zone] = lib.zones.sphere({ + coords = info.coords, + radius = info.zoneRadius, + debug = KloudDev.Debug, + onEnter = function() + if info.job and PlayerJob.name ~= info.job then return end + _G.InZone = true + _G.CurrentZone = zone + SpawnProps(zone) + end, + onExit = function() + _G.InZone = false + _G.CurrentZone = nil + ClearProps() + end + }) + end + for zone, info in pairs(KloudDev.Trees) do + if info.zoneType == "sphere" then + _T.Zone[zone] = lib.zones.sphere({ + coords = info.coords, + radius = info.zoneRadius, + debug = KloudDev.Debug, + onEnter = function() + if info.job and PlayerJob.name ~= info.job then return end + _G.InZone = true + _G.CurrentZone = zone + end, + onExit = function() + _G.InZone = false + _G.CurrentZone = nil + end + }) + elseif info.zoneType == "poly" then + lib.zones.poly({ + points = info.zonePoints, + thickness = 25, + debug = KloudDev.Debug, + onEnter = function() + if info.job and PlayerJob.name ~= info.job then return end + _G.InZone = true + _G.CurrentZone = zone + end, + onExit = function() + _G.InZone = false + _G.CurrentZone = nil + end + }) + end + end + CreateBlips() + CreateTargets() + CreatePeds() +end + +CreateBlips = function() + for zone, info in pairs(KloudDev.Locations) do + if info.blip.enabled then + _T.Blip[zone] = AddBlipForCoord(info.coords.x, info.coords.y, info.coords.z) + SetBlipSprite(_T.Blip[zone], info.blip.sprite) + SetBlipDisplay(_T.Blip[zone], 4) + SetBlipScale(_T.Blip[zone], info.blip.scale) + SetBlipColour(_T.Blip[zone], info.blip.colour) + SetBlipAsShortRange(_T.Blip[zone], true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(info.blip.label) + EndTextCommandSetBlipName(_T.Blip[zone]) + end + end + for zone, info in pairs(KloudDev.Trees) do + if info.blip.enabled then + _T.Blip[zone] = AddBlipForCoord(info.coords.x, info.coords.y, info.coords.z) + SetBlipSprite(_T.Blip[zone], info.blip.sprite) + SetBlipDisplay(_T.Blip[zone], 4) + SetBlipScale(_T.Blip[zone], info.blip.scale) + SetBlipColour(_T.Blip[zone], info.blip.colour) + SetBlipAsShortRange(_T.Blip[zone], true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(info.blip.label) + EndTextCommandSetBlipName(_T.Blip[zone]) + end + end + for zone, info in pairs(KloudDev.Shops) do + if info.blip.enabled then + for _, coords in pairs(info.coords) do + _T.Blip[zone] = AddBlipForCoord(coords.x, coords.y, coords.z) + SetBlipSprite(_T.Blip[zone], info.blip.sprite) + SetBlipDisplay(_T.Blip[zone], 4) + SetBlipScale(_T.Blip[zone], info.blip.scale) + SetBlipColour(_T.Blip[zone], info.blip.colour) + SetBlipAsShortRange(_T.Blip[zone], true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(info.blip.label) + EndTextCommandSetBlipName(_T.Blip[zone]) + end + end + end + if KloudDev.WashLocations.blip.enabled then + for k, coords in pairs(KloudDev.WashLocations.coords) do + _T.Blip["Wash"..k] = AddBlipForCoord(coords.x, coords.y, coords.z) + SetBlipSprite(_T.Blip["Wash"..k], KloudDev.WashLocations.blip.sprite) + SetBlipDisplay(_T.Blip["Wash"..k], 4) + SetBlipScale(_T.Blip["Wash"..k], KloudDev.WashLocations.blip.scale) + SetBlipColour(_T.Blip["Wash"..k], KloudDev.WashLocations.blip.colour) + SetBlipAsShortRange(_T.Blip["Wash"..k], true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(KloudDev.WashLocations.blip.label) + EndTextCommandSetBlipName(_T.Blip["Wash"..k]) + end + end +end + +CreateTargets = function() + for zone, info in pairs(KloudDev.Trees) do + if info.job and PlayerJob.name ~= info.job then return end + AddTargetModel(info.prop, { + { + event = 'kloud-farm:client:pickTree', + label = info.target.label, + name = "PickTrees", + icon = info.target.icon, + currentZone = zone, + canInteract = function(entity) + if not _G.IsBusy and _G.InZone and CanPick(entity) and _G.CurrentZone == zone then return true end + return false + end, + distance = 2, + } + }) + end + + for _, coords in pairs(KloudDev.WashLocations.coords) do + lib.zones.sphere({ + coords = coords, + radius = 4.5, + debug = KloudDev.Debug, + onEnter = function() + DrawText(locale("press_wash_crops", "[E]")) + end, + onExit = function() + HideText() + end, + inside = function () + if not _G.IsBusy and IsControlJustPressed(0, 38) then + TriggerEvent("kloud-farm:client:wash") + end + + if _G.IsBusy then + HideText() + end + end + }) + end +end + +CreatePeds = function() + while not PlayerLoaded do Wait(100) end + for k, v in pairs(KloudDev.Shops) do + for _, coords in pairs(v.coords) do + if k == "sell" then + local model = v.pedModels[math.random(1, #v.pedModels)] + lib.requestModel(model, 10000) + _T.Peds[k] = CreatePed(5, joaat(model), coords.x, coords.y, coords.z, coords.w, false, false) + FreezeEntityPosition(_T.Peds[k], true) + SetBlockingOfNonTemporaryEvents(_T.Peds[k], true) + SetEntityInvincible(_T.Peds[k], true) + + AddEntityTarget(_T.Peds[k], { + { + event = 'kloud-farm:client:openSell', + label = locale('open_sell'), + name = "kloud-farm:openSell", + icon = "fas fa-basket-shopping", + distance = 2.5, + }, + }) + SetModelAsNoLongerNeeded(model) + end + + + if k == "shop" then + local model = v.pedModels[math.random(1, #v.pedModels)] + lib.requestModel(model, 10000) + _T.Peds[k] = CreatePed(5, joaat(model), coords.x, coords.y, coords.z, coords.w, false, false) + FreezeEntityPosition(_T.Peds[k], true) + SetBlockingOfNonTemporaryEvents(_T.Peds[k], true) + SetEntityInvincible(_T.Peds[k], true) + + AddEntityTarget(_T.Peds[k], { + { + event = 'kloud-farm:client:openShop', + label = locale('open_shop'), + name = "kloud-farm:openShop", + icon = "fas fa-basket-shopping", + distance = 2.5, + }, + }) + SetModelAsNoLongerNeeded(model) + end + end + end +end + +CreateThread(Start) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/cabbage.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/cabbage.png new file mode 100644 index 0000000..8d1145e Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/cabbage.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/coffee_beans.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/coffee_beans.png new file mode 100644 index 0000000..20c1a64 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/coffee_beans.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_cabbage.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_cabbage.png new file mode 100644 index 0000000..5130982 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_cabbage.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_coffee_beans.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_coffee_beans.png new file mode 100644 index 0000000..8fde543 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_coffee_beans.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_potato.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_potato.png new file mode 100644 index 0000000..f706a8c Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_potato.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_tomato.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_tomato.png new file mode 100644 index 0000000..03e096d Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/dirty_tomato.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/orange.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/orange.png new file mode 100644 index 0000000..c18305e Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/orange.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/potato.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/potato.png new file mode 100644 index 0000000..d9ea2ab Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/potato.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/shovel.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/shovel.png new file mode 100644 index 0000000..1088157 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/shovel.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/tomato.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/tomato.png new file mode 100644 index 0000000..b8fd844 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/tomato.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/trowel.png b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/trowel.png new file mode 100644 index 0000000..c00864a Binary files /dev/null and b/resources/[qb]/[qb_jobs]/kloud-farmjob/install/images/trowel.png differ diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/ox_inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/ox_inventory.lua new file mode 100644 index 0000000..a9ebc55 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/ox_inventory.lua @@ -0,0 +1,7 @@ +if GetResourceState("ox_inventory") ~= "started" then return end + +Inventory = exports.ox_inventory + +GetItemCount = function(itemName, metadata, strict) + return Inventory:GetItemCount(itemName, metadata, strict) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qb-inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qb-inventory.lua new file mode 100644 index 0000000..0c97cb8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qb-inventory.lua @@ -0,0 +1,23 @@ +local qbVariations = {"qb-inventory", "ps-inventory", "lj-inventory"} +local Inventory = exports["qb-inventory"] +local foundInv = false + +for i = 1, #qbVariations do + if GetResourceState(qbVariations[i]) ~= "started" then + if i == #qbVariations then + if not foundInv then + return + end + end + else + foundInv = true + Inventory = exports[qbVariations[i]] + KloudDev.ImagePath = "https://cfx-nui-".. qbVariations[i] .. "/html/images/" + end +end + + +GetItemCount = function(itemName, metadata, strict) + local count = lib.callback.await("GetItemCount", false, itemName) + return count +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qs-inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qs-inventory.lua new file mode 100644 index 0000000..aa226fd --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/client/qs-inventory.lua @@ -0,0 +1,8 @@ +if GetResourceState("qs-inventory") ~= "started" then return end + +Inventory = exports["qs-inventory"] + +GetItemCount = function(itemName, metadata, strict) + local count = lib.callback.await("GetItemCount", false, itemName) + return count +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/ox_inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/ox_inventory.lua new file mode 100644 index 0000000..d943d66 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/ox_inventory.lua @@ -0,0 +1,28 @@ +if GetResourceState("ox_inventory") ~= "started" then return end + +Inventory = exports.ox_inventory + +AddItem = function(inv, item, amount, metadata) + return Inventory:AddItem(inv, item, amount, metadata) +end + +RemoveItem = function(inv, item, amount, metadata, slot) + return Inventory:RemoveItem(inv, item, amount, metadata, slot) +end + +CanCarryItem = function(inv, item, amount) + return Inventory:CanCarryItem(inv, item, amount) +end + +GetItemCount = function(inv, item) + if Inventory:GetItemCount(inv, item, nil, false) >= 1 then return true end + return false +end + +GetSlotWithItem = function(inv, item, metadata, strict) + return Inventory:GetSlotWithItem(inv, item, metadata, strict) +end + +SetDurability = function(inv, slot, durability) + return Inventory:SetDurability(inv, slot, durability) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qb-inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qb-inventory.lua new file mode 100644 index 0000000..de2dd4b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qb-inventory.lua @@ -0,0 +1,62 @@ +local qbVariations = {"qb-inventory", "ps-inventory", "lj-inventory"} +local Inventory = exports["qb-inventory"] +local foundInv = false + +for i = 1, #qbVariations do + if GetResourceState(qbVariations[i]) ~= "started" then + if i == #qbVariations then + if not foundInv then + return + end + end + else + foundInv = true + Inventory = exports[qbVariations[i]] + end +end + +AddItem = function(inv, item, amount, metadata) + if Inventory:AddItem(inv, item, amount, false, metadata) then + for i = 1, amount do + TriggerClientEvent('inventory:client:ItemBox', inv, QBCore.Shared.Items[item], 'add') + end + return true + end + return false +end + +RemoveItem = function(inv, item, amount, metadata, slot) + if Inventory:RemoveItem(inv, item, amount, slot) then + for i = 1, amount do + TriggerClientEvent('inventory:client:ItemBox', inv, QBCore.Shared.Items[item], 'remove') + end + return true + end + return false +end + +CanCarryItem = function(inv, item, amount) + return true +end + +GetItemCount = function(inv, item) + if #Inventory:GetItemsByName(inv, item) >= 1 then return true end + return false +end + +GetSlotWithItem = function(inv, item, metadata, strict) + local Player = GetPlayer(inv) + return Inventory:GetFirstSlotByItem(Player.PlayerData.items, item) +end + +SetDurability = function(inv, slot, durability) + return true +end + +lib.callback.register("GetItemCount", function(source, item) + local items = Inventory:GetItemsByName(source, item) + for k, v in pairs(items) do + return v.amount + end + return 0 +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qs-inventory.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qs-inventory.lua new file mode 100644 index 0000000..f8f1389 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/inventory/server/qs-inventory.lua @@ -0,0 +1,39 @@ +if GetResourceState("qs-inventory") ~= "started" then return end + +Inventory = exports["qs-inventory"] + +AddItem = function(inv, item, amount, metadata) + return Inventory:AddItem(inv, item, amount, false, metadata) +end + +RemoveItem = function(inv, item, amount, metadata, slot) + return Inventory:RemoveItem(inv, item, amount, slot, metadata) +end + +CanCarryItem = function(inv, item, amount) + return Inventory:CanCarryItem(inv, item, amount) +end + +GetItemCount = function(inv, item) + if Inventory:GetItemTotalAmount(inv, item) >= 1 then return true end + return false +end + +GetSlotWithItem = function(inv, item, metadata, strict) + local items = Inventory:GetInventory(inv) + for itemData, slotData in pairs(items) do + if slotData.name == item then + slotData.metadata = slotData.info + return slotData + end + end + return false +end + +SetDurability = function(inv, slot, durability) + return true +end + +lib.callback.register("GetItemCount", function(source, item) + return Inventory:GetItemTotalAmount(source, item) +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/da.json b/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/da.json new file mode 100644 index 0000000..eb906d8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/da.json @@ -0,0 +1,14 @@ +{ + "no_required_item":"Du har ikke en %s", + "cant_carry":"Du kan ikke bære mere %s", + "uprooting":"Høster %s", + "washing":"Vasker %s", + "item_broke":"%s gik i stykker", + "wash_crops":"Vasker afgrøder", + "no_crops_to_wash":"Du har ingen afgrøder der skal vaskes", + "press_wash_crops":"%s Vask afgrøder", + "open_shop":"Åben shop", + "open_sell":"Åben sælger", + "sell_crops":"Sælg afgrøder", + "farmer_shop":"Landbrugsbutik" +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/en.json b/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/en.json new file mode 100644 index 0000000..74aa823 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/locales/en.json @@ -0,0 +1,14 @@ +{ + "no_required_item":"You don't have a %s", + "cant_carry":"You can't carry more %s", + "uprooting":"Uprooting %s", + "washing":"Washing %s", + "item_broke":"%s Broke", + "wash_crops":"Wash Crops", + "no_crops_to_wash":"You don't have any crops that needs a wash", + "press_wash_crops":"%s Wash Crops", + "open_shop":"Open Shop", + "open_sell":"Open Sell", + "sell_crops":"Sell Crops", + "farmer_shop":"Agriculture Shop" +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/events.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/events.lua new file mode 100644 index 0000000..eaae528 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/events.lua @@ -0,0 +1,129 @@ +RegisterNetEvent("kloud-farm:client:pickProp", function(data) + local zoneData = KloudDev.Locations[data.currentZone] + local canStart, msg = lib.callback.await("kloud-farm:callback:canStart", false, zoneData) + if not canStart then Notify(msg, "error") return end + _G.IsBusy = true + if zoneData.anim.scenario then + TaskStartScenarioInPlace(cache.ped, zoneData.anim.scenario, 0, false) + else + PlayAnim(cache.ped, zoneData.anim.dict, zoneData.anim.clip, -1, zoneData.anim.upperBody) + end + if zoneData.action.type == "progress" then + + local progress = Progress(zoneData.action.progressDuration, locale("uprooting", FormatStr(zoneData.item.label))) + if not progress then + ClearPedTasksImmediately(cache.ped) + DeleteProp(data.entity) + _G.IsBusy = false + return + end + elseif zoneData.action.type == "skillCheck" then + if not SkillCheck(zoneData.action.skillCheckDifficulty, zoneData.action.skillCheckInputs) then + ClearPedTasksImmediately(cache.ped) + DeleteProp(data.entity) + _G.IsBusy = false + return + end + end + _G.IsBusy = false + ClearPedTasksImmediately(cache.ped) + DeleteProp(data.entity) + lib.callback("kloud-farm:callback:uprooted", 3000, nil, zoneData) +end) + +RegisterNetEvent("kloud-farm:client:pickTree", function(data) + local zoneData = KloudDev.Trees[data.currentZone] + local canStart, msg = lib.callback.await("kloud-farm:callback:canStart", false, zoneData) + if not canStart then Notify(msg, "error") return end + _G.IsBusy = true + if zoneData.anim.scenario then + TaskStartScenarioInPlace(cache.ped, zoneData.anim.scenario, 0, false) + else + PlayAnim(cache.ped, zoneData.anim.dict, zoneData.anim.clip, -1, zoneData.anim.upperBody) + end + if zoneData.action.type == "progress" then + local progress = Progress(zoneData.action.progressDuration, locale("uprooting", FormatStr(zoneData.item.label))) + if not progress then + ClearPedTasksImmediately(cache.ped) + _G.IsBusy = false + return + end + elseif zoneData.action.type == "skillCheck" then + if not SkillCheck(zoneData.action.skillCheckDifficulty, zoneData.action.skillCheckInputs) then + ClearPedTasksImmediately(cache.ped) + _G.IsBusy = false + return + end + end + ClearPedTasksImmediately(cache.ped) + _G.IsBusy = false + table.insert(_T.PickedTrees, {entity = data.entity, cooldown = zoneData.cooldown}) + TriggerEvent("kloud-farm:client:startTreesCooldown") + lib.callback("kloud-farm:callback:uprooted", 3000, nil, zoneData) +end) + +RegisterNetEvent("kloud-farm:client:startTreesCooldown", function() + if _G.Cooldown then return end + _G.Cooldown = true + while true do + for k, tree in pairs(_T.PickedTrees) do + for key, value in pairs(tree) do + if key == "cooldown" then + _T.PickedTrees[k].cooldown = value - 1 + -- print("Cooldown: " .. value) + if value <= 0 then + table.remove(_T.PickedTrees, k) + end + end + end + end + if next(_T.PickedTrees) == nil then + _G.Cooldown = false + return + end + Wait(1000) + end +end) + +RegisterNetEvent("kloud-farm:client:wash", function() + HideText() + local optionsTbl = {} + for _, v in pairs(KloudDev.WashLocations.items) do + if GetItemCount(v[1], nil, false) > 0 then + local values = {} + for i = 1, GetItemCount(v[1], nil, false) do + if i <= KloudDev.WashLocations.maxWash then + table.insert(values, i) + end + end + table.insert(optionsTbl, { + label = "x1 ".. FormatStr(v[1]).." : x1 "..FormatStr(v[2]), + icon = KloudDev.ImagePath .. v[2] .. ".png", + values = values, + args = { + itemRequired = v[1], + itemResult = v[2] + } + }) + end + end + if next(optionsTbl) == nil then + Notify(locale("no_crops_to_wash"), "error") + return + end + lib.registerMenu({ + id = "kloud-farm:wash", + title = locale("wash_crops"), + position = "top-right", + options = optionsTbl, + disableInput = true, + }, function(selected, scrollIndex, args) + WashCrops({itemRequired = args.itemRequired, itemResult = args.itemResult, amount = scrollIndex}) + end) + lib.showMenu("kloud-farm:wash") +end) + +AddEventHandler("onResourceStop", function(name) + if GetCurrentResourceName() ~= name then return end + ClearProps() +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/functions.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/functions.lua new file mode 100644 index 0000000..40b992a --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/field/functions.lua @@ -0,0 +1,148 @@ +local spawnedProps = 0 + +GetZCoord = function (x, y, groundHeights) + local groundCheckHeights = groundHeights + + for i, height in ipairs(groundCheckHeights) do + local foundGround, z = GetGroundZFor_3dCoord(x, y, height, true) + + if foundGround then + return z + end + end + + return 76 +end + +ValidateCoord = function(coord) + local validate = true + if spawnedProps > 0 then + for _, v in pairs(_T.Props) do + if #(coord - GetEntityCoords(v)) < 5 then + validate = false + end + end + end + return validate +end + +GetCoords = function (zone) + local loc = KloudDev.Locations[zone] + local groundHeight = {} + local value = loc.coords.z - 15 + local radius = math.floor(loc.zoneRadius / 2) + for i = 1, 30 do + value += 1 + table.insert(groundHeight, value) + end + while true do + Wait(1) + local propCoordX, propCoordY + + math.randomseed(GetGameTimer()) + local modX = math.random(radius * -1 , radius) + + Wait(100) + + math.randomseed(GetGameTimer()) + local modY = math.random(-35, 35) + + propCoordX = loc.coords.x + modX + propCoordY = loc.coords.y + modY + + local coordZ = GetZCoord(propCoordX, propCoordY, groundHeight) + local coord = vector3(propCoordX, propCoordY, coordZ) + + if ValidateCoord(coord) then + return coord + end + end +end + +SpawnProps = function(zone) + local loc = KloudDev.Locations[zone] + while spawnedProps < loc.max do + Wait(0) + lib.requestModel(loc.prop, 10000) + local propCoords = GetCoords(zone) + local obj = CreateObject(joaat(loc.prop), propCoords.x, propCoords.y, propCoords.z, false, true, false) + while not DoesEntityExist(obj) do Wait(100) end + AddEntityTarget(obj, { + { + event = 'kloud-farm:client:pickProp', + label = loc.target.label, + name = "PickProps", + icon = loc.target.icon, + currentZone = _G.CurrentZone, + canInteract = function() + if not _G.IsBusy and _G.CurrentZone == zone then return true end + return false + end, + distance = 2, + } + }) + SetEntityAsMissionEntity(obj, true, true) + PlaceObjectOnGroundProperly(obj) + FreezeEntityPosition(obj, true) + table.insert(_T.Props, obj) + spawnedProps = #_T.Props + end + SetModelAsNoLongerNeeded(joaat(loc.prop)) +end + +WashCrops = function(data) + local zoneData = KloudDev.WashLocations + local canCarry, msg = lib.callback.await("kloud-farm:callback:canCarry", false, data) + local duration = zoneData.duration * data.amount + if not canCarry then Notify(msg, "error") return end + _G.IsBusy = true + if zoneData.anim.scenario then + TaskStartScenarioInPlace(cache.ped, zoneData.anim.scenario, 0, false) + else + PlayAnim(cache.ped, zoneData.anim.dict, zoneData.anim.clip, -1, zoneData.anim.upperBody) + end + + if not Progress(duration, locale("washing", FormatStr(data.itemRequired))) then + ClearPedTasksImmediately(cache.ped) + _G.IsBusy = false + return + end + ClearPedTasksImmediately(cache.ped) + _G.IsBusy = false + lib.callback("kloud-farm:callback:washed", 3000, nil, data) +end + +ClearProps = function() + for k, v in pairs(_T.Props) do + if DoesEntityExist(v) then + if not DeleteObject(v) then DeleteObject(v) end + table.remove(_T.Props, k) + spawnedProps = #_T.Props + else + table.remove(_T.Props, k) + spawnedProps = #_T.Props + end + end +end + +DeleteProp = function(prop) + for k, v in pairs(_T.Props) do + if prop == v then + if not DoesEntityExist(v) then table.remove(_T.Props, k) end + + if not DeleteObject(v) then DeleteObject(v) end + table.remove(_T.Props, k) + spawnedProps = #_T.Props + SpawnProps(_G.CurrentZone) + end + end +end + +CanPick = function(entity) + for _, info in pairs(_T.PickedTrees) do + for k, v in pairs(info) do + if v == entity then return false end + end + end + return true +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/shops/events.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/shops/events.lua new file mode 100644 index 0000000..bbbace9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/modules/shops/events.lua @@ -0,0 +1,87 @@ +RegisterNetEvent("kloud-farm:client:openSell", function() + local optionsTbl = {} + for k, v in pairs(KloudDev.Shops) do + if k == "sell" then + for _, data in pairs(v.prices) do + if GetItemCount(data[1], nil, false) > 0 then + local values = {} + for i = 1, GetItemCount(data[1], nil, false) do + if i <= KloudDev.WashLocations.maxWash then + table.insert(values, i) + end + end + table.insert(optionsTbl, { + label = FormatStr(data[1]) .. " $".. data[2], + icon = KloudDev.ImagePath .. data[1] .. ".png", + values = values, + args = { + item = data[1], + price = data[2] + } + }) + else + table.insert(optionsTbl, { + label = FormatStr(data[1]), + icon = KloudDev.ImagePath .. data[1] .. ".png", + close = false + }) + end + end + end + end + lib.registerMenu({ + id = "kloud-farm:sell", + title = locale("sell_crops"), + position = "top-right", + options = optionsTbl, + disableInput = true, + }, function(selected, scrollIndex, args) + if scrollIndex then + local sold = lib.callback.await("kloud-farm:callback:sellItem", false, {item = args.item, price = args.price, amount = scrollIndex}) + if sold then + lib.hideMenu(false) + end + end + end) + + lib.showMenu("kloud-farm:sell") +end) + +RegisterNetEvent("kloud-farm:client:openShop", function() + local optionsTbl = {} + for k, v in pairs(KloudDev.Shops) do + if k == "shop" then + for _, data in pairs(v.prices) do + local values = {} + for i = 1, 10 do + table.insert(values, i) + end + table.insert(optionsTbl, { + label = "$" .. data[2] .." ".. FormatStr(data[1]), + icon = KloudDev.ImagePath .. data[1] .. ".png", + values = values, + args = { + item = data[1], + price = data[2] + } + }) + end + end + end + lib.registerMenu({ + id = "kloud-farm:shop", + title = locale("farmer_shop"), + position = "top-right", + options = optionsTbl, + disableInput = true, + }, function(selected, scrollIndex, args) + if scrollIndex then + local sold = lib.callback.await("kloud-farm:callback:buyItem", false, {item = args.item, price = args.price, amount = scrollIndex}) + if sold then + lib.hideMenu(false) + end + end + end) + + lib.showMenu("kloud-farm:shop") +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/server.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/server.lua new file mode 100644 index 0000000..37ca4f6 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/server.lua @@ -0,0 +1,77 @@ +lib.callback.register("kloud-farm:callback:canStart", function(source, zoneData) + local src = source + local requireItem = zoneData.item.require + if requireItem.enable then + return GetItemCount(src, requireItem.item), locale('no_required_item', requireItem.item) + end + + if CanCarryItem(src, zoneData.item.name, 1) then + return true + else + return false, locale('cant_carry', FormatStr(zoneData.item.name)) + end +end) + +lib.callback.register("kloud-farm:callback:canCarry", function(source, data) + local src = source + if CanCarryItem(src, data.itemResult, data.amount) then + return true + else + return false, locale('cant_carry', FormatStr(data.itemResult)) + end +end) + +lib.callback.register("kloud-farm:callback:uprooted", function(source, zoneData) + local src = source + local requireItem = zoneData.item.require + local randomAmount = math.random(zoneData.item.min, zoneData.item.max) + + AddItem(src, zoneData.item.name, randomAmount, nil) + + if requireItem.enable and requireItem.durability.subtract then + local itemData = GetSlotWithItem(src, requireItem.item, nil, false) + local currentDurability = 100 + local durabilityChance = math.random(1, 100) + + if itemData.metadata.durability then + currentDurability = itemData.metadata.durability + end + + if durabilityChance < requireItem.durability.chance then + SetDurability(src, itemData.slot, currentDurability - requireItem.durability.amount) + end + + if requireItem.randomBreak then + local randomChance = math.random(1, 100) + if randomChance < requireItem.breakChance then + RemoveItem(src, requireItem.item, 1, false, itemData.slot) + SVNotify(src, locale('item_broke', FormatStr(requireItem.item)), "error") + end + end + end +end) + +lib.callback.register("kloud-farm:callback:washed", function(source, data) + local src = source + + if RemoveItem(src, data.itemRequired, data.amount) then + AddItem(src, data.itemResult, data.amount, nil) + end +end) + +lib.callback.register("kloud-farm:callback:sellItem", function(source, data) + local src = source + + if not RemoveItem(src, data.item, data.amount) then return false end + + if not AddMoney(src, "cash", data.price * data.amount, "Sold Crop") then return false end + +end) + +lib.callback.register("kloud-farm:callback:buyItem", function(source, data) + local src = source + + if not RemoveMoney(src, "cash", data.price * data.amount, "Buy Farming Item") then return false end + + if not AddItem(src, data.item, data.amount) then return false end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/animations.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/animations.lua new file mode 100644 index 0000000..385aaef --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/animations.lua @@ -0,0 +1,24 @@ +_anim = {} + +_anim.props = { + clipboard = "p_amb_clipboard_01", + notepad = "prop_notepad_01" +} + +_anim.shrug = { dict = "gestures@f@standing@casual", clip = "gesture_shrug_hard" } +_anim.no = { dict = "mp_player_int_upper_nod", clip = "mp_player_int_nod_no" } +_anim.clipboard = { dict = "missfam4", clip = "base" } +_anim.notepad = { dict = "missheistdockssetup1clipboard@base", clip = "base" } +_anim.trolly = { dict = "missfinale_c2ig_11", clip = "pushcar_offcliff_f" } +_anim.give = { dict = "mp_common", clip = "givetake1_a"} +_anim.take = { dict = "mp_common", clip = "givetake1_b"} + +_anim.wait = { + {dict = "mp_cp_welcome_tutthink", clip = "b_think"}, + {dict = "misscarsteal4@aliens", clip = "rehearsal_base_idle_director"}, + {dict = "timetable@tracy@ig_8@base", clip = "base"}, + {dict = "missheist_jewelleadinout", clip = "jh_int_outro_loop_a"}, + {dict = "rcmjosh1", clip = "idle"}, + {dict = "missbigscore2aig_3", clip = "wait_for_van_c"}, + {dict = "timetable@amanda@ig_2", clip = "ig_2_base_amanda"} +} diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/checks.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/checks.lua new file mode 100644 index 0000000..70f5b05 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/checks.lua @@ -0,0 +1,13 @@ +CreateThread(function() + Wait(1000) + + if GetResourceState("ox_target") ~= "started" and GetResourceState("qb-target") ~= "started" then + -- print("^1No targeting resource found. Start the targeting resource before this script or you might be using an unsupported one.^0") + end + + if GetResourceState("es_extended") ~= "started" and GetResourceState("qb-core") ~= "started" and GetResourceState("qbx-core") ~= "started" then + -- print("^1No framework found.^0") + end + + collectgarbage("collect") +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/config.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/config.lua new file mode 100644 index 0000000..27a7bf4 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/config.lua @@ -0,0 +1,14 @@ +KloudDev = {} + +KloudDev.Debug = false + +KloudDev.ImagePath = "ps-inventory/html/images/" + +KloudDev.DrawSprite = true -- ox_target indicator +KloudDev.DrawText = "qb" -- "qb","ox" +KloudDev.Menu = "qb" -- "qb","ox" +KloudDev.Notify = "qb" -- "qb","esx","ox", "ps" +KloudDev.NotifyPos = "top-right" -- For ox_lib // 'top', 'top-right', 'top-left', 'bottom', 'bottom-right', 'bottom-left', 'center-right', 'center-left' // For QB change qb-core/config.lua +KloudDev.Progress = "ox-circle" -- "ox-bar","ox-circle" +KloudDev.ProgressCirclePos = "bottom" -- "middle", "bottom" +KloudDev.DrawTextAlignment = "top" -- "top","right","left" \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/location_config.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/location_config.lua new file mode 100644 index 0000000..f852d25 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/location_config.lua @@ -0,0 +1,414 @@ +KloudDev.Locations = { + ["potato"] = { + coords = vec4(2852.95, 4627.06, 50.69, 284.01), + zoneRadius = 65, + prop = "prop_plant_fern_02a", + job = false, -- false to disable, "jobname" to enable + action = { + type = "skillCheck", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + max = 25, + target = { + label = "Træk op", + icon = "fas fa-trowel" + }, + anim = { + scenario = "WORLD_HUMAN_GARDENER_PLANT", + dict = nil, + clip = nil, + upperBody = false + }, + item = { + require = { + enable = true, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "dirty_potato", + label = "Beskidt kartoffel", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Kartoffel-mark", + sprite = 285, + scale = 0.9, + colour = 21, + }, + }, + ["cabbage"] = { + coords = vec4(2541.34, 4812.27, 33.73, 65.37), + zoneRadius = 35, + prop = "prop_veg_crop_03_cab", + job = false, -- false to disable, "jobname" to enable + action = { + type = "progress", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + max = 25, + target = { + label = "Træk op", + icon = "fas fa-hands-holding" + }, + anim = { + scenario = nil, + dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", + clip = "machinic_loop_mechandplayer", + upperBody = false, + }, + item = { + require = { + enable = false, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "dirty_cabbage", + label = "Beskidt kål", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Kål-mark", + sprite = 285, + scale = 0.9, + colour = 2, + }, + }, + ["tomato"] = { + coords = vec4(2238.95, 5074.01, 47.25, 220.28), + zoneRadius = 45, + prop = "prop_veg_crop_02", + job = false, -- false to disable, "jobname" to enable + action = { + type = "skillCheck", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + max = 25, + target = { + label = "Træk op", + icon = "fas fa-hands-holding" + }, + anim = { + scenario = nil, + dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", + clip = "machinic_loop_mechandplayer", + upperBody = true, + }, + item = { + require = { + enable = false, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "dirty_tomato", + label = "Beskidt tomat", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Tomat-mark", + + sprite = 285, + scale = 0.9, + colour = 6, + }, + }, + ["coffee_beans"] = { + coords = vec4(2308.01, 5131.05, 50.5, 45.11), + zoneRadius = 35, + prop = "prop_veg_crop_04_leaf", + job = false, -- false to disable, "jobname" to enable + action = { + type = "skillCheck", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + max = 25, + target = { + label = "Træk op", + icon = "fas fa-hands-holding" + }, + anim = { + scenario = nil, + dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", + clip = "machinic_loop_mechandplayer", + upperBody = true, + }, + item = { + require = { + enable = false, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "dirty_coffee_beans", + label = "Beskidte kaffebønner", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Kaffebønne-mark", + + sprite = 285, + scale = 0.9, + colour = 44, + }, + }, +} + +KloudDev.Trees = { + ["orange"] = { + coords = vec4(2341.86, 5003.98, 42.53, 45.44), + zoneType = "sphere", + zoneRadius = 55, + zonePoints = { + vec3(2455.0, 4670.0, 35.0), + vec3(2367.0, 4761.0, 35.0), + vec3(2311.0, 4780.0, 35.0), + vec3(2299.0, 4743.0, 35.0), + vec3(2361.0, 4712.0, 35.0), + vec3(2428.0, 4646.0, 35.0), + }, + cooldown = 60, + prop = "prop_veg_crop_orange", + job = false, -- false to disable, "jobname" to enable + action = { + type = "skillCheck", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + target = { + label = "Pluk appelsin", + icon = "fas fa-cannabis" + }, + anim = { + scenario = nil, + dict = "missmechanic", + clip = "work_base", + upperBody = true + }, + item = { + require = { + enable = false, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "orange", + label = "Appelsin", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Appelsin-mark", + + sprite = 285, + scale = 0.9, + colour = 47, + }, + }, + ["orange2"] = { + coords = vec4(2360.21, 4729.47, 34.53, 260.21), + zoneType = "poly", + zoneRadius = 55, + zonePoints = { + vec3(2455.0, 4670.0, 35.0), + vec3(2367.0, 4761.0, 35.0), + vec3(2311.0, 4780.0, 35.0), + vec3(2299.0, 4743.0, 35.0), + vec3(2361.0, 4712.0, 35.0), + vec3(2428.0, 4646.0, 35.0), + }, + cooldown = 60, + prop = "prop_veg_crop_orange", + job = false, -- false to disable, "jobname" to enable + action = { + type = "skillCheck", -- "progress" / "skillCheck" + progressDuration = 5000, + skillCheckDifficulty = {"easy", "easy", "easy", "easy"}, -- "easy", "medium", "hard" + skillCheckInputs = {"1", "2", "3", "4"} + }, + target = { + label = "Pluk appelsin", + icon = "fas fa-cannabis" + }, + anim = { + scenario = nil, + dict = "missmechanic", + clip = "work_base", + upperBody = true + }, + item = { + require = { + enable = false, + item = "trowel", + durability = { + subtract = true, + amount = 1, + chance = 75 + }, + breaking = { + enabled = true, + chance = 15 + } + }, + name = "orange", + label = "Appelsin", + min = 1, + max = 4 + }, + blip = { + enabled = true, + label = "Appelsin-mark", + + sprite = 285, + scale = 0.9, + colour = 47, + }, + }, +} + +KloudDev.WashLocations = { + blip = { + enabled = true, + label = "Vask afgrøder", + sprite = 728, + scale = 0.9, + colour = 4, + }, + duration = 3000, -- per item count ex. x1 orange = 3secs, x10 orange = 30secs + maxWash = 20, + anim = { + scenario = "WORLD_HUMAN_BUM_WASH", -- nil to disable + dict = nil, + clip = nil, + upperBody = false + }, + items = { + {"dirty_potato", "potato"}, + {"dirty_cabbage", "cabbage"}, + {"dirty_tomato", "tomato"}, + {"dirty_coffee_beans", "coffee_beans"}, + --{requiredItem, resultItem} + }, + coords = { + vec4(2405.77, 4600.39, 30.31, 98.15), + vec4(2397.81, 4596.51, 30.31, 134.76), + vec4(2384.6, 4594.71, 30.38, 107.85), + vec4(2363.49, 4593.61, 30.52, 106.54), + vec4(2372.93, 4595.23, 30.54, 190.0), + } +} + +KloudDev.Shops = { + ["sell"] = { + blip = { + enabled = true, + label = "Farmer John", + sprite = 59, + scale = 0.9, + colour = 2, + }, + coords = { + vector4(2028.18, 4978.26, 40.12, 224.48), + vector4(2243.63, 5154.18, 56.89, 154.39) + }, + pedModels = { + "a_m_m_farmer_01", + "cs_russiandrunk", + "cs_old_man1a", + "cs_old_man2", + "cs_nervousron", + }, + prices = { + {"potato", 5}, + {"tomato", 3}, + {"orange", 4}, + {"cabbage", 6}, + {"coffee_beans", 8}, + -- {"itemName", price} + } + }, + ["shop"] = { + blip = { + enabled = true, + label = "Farmer John", + sprite = 59, + scale = 0.9, + colour = 2, + }, + coords = { + vector4(461.93, -696.86, 26.42, 70.94), + + }, + pedModels = { + "a_m_m_farmer_01", + "cs_russiandrunk", + "cs_old_man1a", + "cs_old_man2", + "cs_nervousron", + }, + prices = { + {"shovel", 100}, + {"trowel", 50}, + {"potato", 75}, + {"tomato", 75}, + {"orange", 75}, + {"cabbage", 75}, + {"coffee_beans", 75}, + -- {"itemName", price} + } + }, +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/utils.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/utils.lua new file mode 100644 index 0000000..4edca97 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/shared/utils.lua @@ -0,0 +1,225 @@ +lib.locale() + +FormatStr = function(str) + local strFormat = str + strFormat = strFormat:gsub("_", " ") + strFormat = string.gsub(" "..strFormat, "%W%l", string.upper):sub(2) + return strFormat +end + +DrawText = function (msg) + if KloudDev.DrawText == 'ox' then + local pos = KloudDev.DrawTextAlignment.."-center" + lib.showTextUI(msg, { + position = pos or "right-center" + }) + elseif KloudDev.DrawText == 'qb' then + exports['qb-core']:DrawText(msg, KloudDev.DrawTextAlignment) + end +end + +HideText = function () + if KloudDev.DrawText == 'ox' then + lib.hideTextUI() + elseif KloudDev.DrawText == 'qb' then + exports['qb-core']:HideText() + end +end + +Progress = function (duration, label, dict, clip) + if KloudDev.Progress == "ox-circle" then + local anim = nil + if dict and clip then + anim = { + dict = dict, + clip = clip + } + end + return lib.progressCircle({ + duration = duration, + label = label, + useWhileDead = false, + canCancel = false, + position = KloudDev.ProgressCirclePos or "bottom", + disable = { + move = true, + car = true, + combat = true, + mouse = false + }, + anim = anim, + }) + elseif KloudDev.Progress == "ox-bar" then + local anim = nil + if dict and clip then + anim = { + dict = dict, + clip = clip + } + end + return lib.progressBar({ + duration = duration, + label = label, + useWhileDead = false, + canCancel = false, + disable = { + move = true, + car = true, + combat = true, + mouse = false + }, + anim = anim + }) + end +end + +Notify = function (msg, type, duration) + local dur = duration or 3000 + if KloudDev.Notify == "ox" then + if GetResourceState("ox_lib") ~= "started" then print("You need ox_lib running for the notifications to work") return end + if type == "error" then + lib.notify({ + description = msg, + icon = 'ban', + duration = dur, + iconColor = '#C53030', + position = KloudDev.NotifyPos or "top-right" + }) + elseif type == "success" then + lib.notify({ + description = msg, + icon = 'check', + duration = dur, + iconColor = '#30c56a', + position = KloudDev.NotifyPos or "top-right" + }) + end + elseif KloudDev.Notify == "qb" then + TriggerEvent('QBCore:Notify', msg, type, dur) + elseif KloudDev.Notify == "esx" then + TriggerEvent('esx:showNotification', msg, type, dur) + elseif KloudDev.Notify == "ps" then + exports['ps-ui']:Notify(msg, type, dur) + end +end + +SVNotify = function (source, msg, type, duration) + local dur = duration or 3000 + if KloudDev.Notify == "ox" then + local randomID = math.random(1, 500) + if type == "error" then + TriggerClientEvent('ox_lib:notify', source, { + description = msg, + duration = dur, + icon = 'ban', + iconColor = '#C53030', + position = KloudDev.NotifyPos or "top-right" + }) + elseif type == "success" then + TriggerClientEvent('ox_lib:notify', source, { + description = msg, + duration = dur, + icon = 'check', + iconColor = '#30c56a', + position = KloudDev.NotifyPos or "top-right" + }) + end + elseif KloudDev.Notify == "qb" then + TriggerClientEvent('QBCore:Notify', source, msg, type, dur) + elseif KloudDev.Notify == "esx" then + TriggerClientEvent('esx:showNotification', source, msg, type, dur) + elseif KloudDev.Notify == "ps" then + TriggerClientEvent('ps-ui:Notify', source, msg, type, dur) + end +end + +FaceEntity = function (entity1, entity2) + local x, y, z = table.unpack(GetEntityCoords(entity1, true)) + local x1, y1, z1 = table.unpack(GetEntityCoords(entity2, true)) + + local dx = x1 - x + local dy = y1 - y + + local heading = GetHeadingFromVector_2d(dx, dy) + SetPedDesiredHeading(entity1, heading) + return tonumber(heading) +end + +PlayAnim = function (ped, dict, clip, duration, upperbody) + lib.requestAnimDict(dict) + ClearPedTasks(ped) + TaskPlayAnim(ped, dict, clip, 5.0, 5.0, duration or -1, upperbody and 51 or 0, 0, false, false, false) +end + +ShrugAnim = function (ped) + lib.requestAnimDict(_anim.shrug.dict) + ClearPedTasks(ped) + TaskPlayAnim(ped, _anim.shrug.dict, _anim.shrug.clip, 5.0, 5.0, 1000, 51, 0, false, false, false) + Wait(800) +end + +NoAnim = function (ped) + lib.requestAnimDict(_anim.no.dict) + ClearPedTasks(ped) + TaskPlayAnim(ped, _anim.no.dict, _anim.no.clip, 5.0, 5.0, 1000, 51, 0, false, false, false) +end + +RandomWaitAnim = function (ped, duration) + local randomAnim = math.random(1, #_anim.wait) + lib.requestAnimDict(_anim.wait[randomAnim].dict) + ClearPedTasks(ped) + TaskPlayAnim(ped, _anim.wait[randomAnim].dict, _anim.wait[randomAnim].clip, 5.0, 5.0, duration, 51, 0, false, false, false) +end + +DeleteProp = function (prop) + DeleteObject(prop) +end + +ClipboardAnim = function (ped, duration) + lib.requestModel(_anim.props.clipboard, 10000) + local ped = ped + local x, y, z = table.unpack(GetEntityCoords(ped)) + local prop = CreateObject(joaat(_anim.props.clipboard), x, y, z, true, false, false) + + PlayAnim(ped, _anim.clipboard.dict, _anim.clipboard.clip, duration) + AttachEntityToEntity(prop, ped, GetPedBoneIndex(ped, 36029), 0.16, 0.08, 0.1, -130.0, -50.0, 0.0, true, true, false, true, 1, true) + SetModelAsNoLongerNeeded(_anim.props.clipboard) + return prop +end + +NotepadAnim = function (ped, duration) + lib.requestModel(_anim.props.notepad, 10000) + local x, y, z = table.unpack(GetEntityCoords(ped)) + local prop = CreateObject(joaat(_anim.props.notepad), x, y, z, true, false, false) + + PlayAnim(ped, _anim.notepad.dict, _anim.notepad.clip, duration) + AttachEntityToEntity(prop, ped, GetPedBoneIndex(ped, 36029), 0.1, 0.02, 0.05, 10.0, 0.0, 0.0, true, true, false, true, 1, true) + SetModelAsNoLongerNeeded(_anim.props.notepad) + return prop +end + +TrollyAnim = function (model, coords, created) + lib.requestAnimDict(_anim.trolly.dict) + + ClearPedTasks(cache.ped) + TaskPlayAnim(cache.ped, _anim.trolly.dict, _anim.trolly.clip, 5.0, 5.0, 1.0 , 62, 0, false, false, false) + Wait(200) + if not created then + local trolly = CreateObject(joaat(model), coords.x, coords.y, coords.z, true, false, false) + AttachEntityToEntity(trolly, cache.ped, GetPedBoneIndex(cache.ped, 60309), -0.4, -1.6, -0.85, 0.0, 0.0, 180.0, true, true, false, true, 1, true) + return trolly + end + + AttachEntityToEntity(created, cache.ped, GetPedBoneIndex(cache.ped, 60309), -0.4, -1.6, -0.85, 0.0, 0.0, 180.0, true, true, false, true, 1, true) + return created +end + +TrollyReAnim = function() + lib.requestAnimDict(_anim.trolly.dict) + + TaskPlayAnim(cache.ped, _anim.trolly.dict, _anim.trolly.clip, 5.0, 5.0, 1.0 , 62, 0, false, false, false) +end + +SkillCheck = function(difficulty, inputs) + return lib.skillCheck(difficulty, inputs) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/target/ox_target.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/target/ox_target.lua new file mode 100644 index 0000000..bfc3787 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/target/ox_target.lua @@ -0,0 +1,32 @@ +if GetResourceState("ox_target") ~= "started" then return end + +AddTarget = function (coords, radius, options) + exports.ox_target:addSphereZone({ + coords = coords, + radius = 2.25, + debug = KloudDev.Debug, + drawSprite = KloudDev.DrawSprite, + options = options + }) +end +AddEntityTarget = function (entity, options) + if NetworkGetEntityIsNetworked(entity) then + local netId = NetworkGetNetworkIdFromEntity(entity) + exports.ox_target:addEntity(netId, options) + else + exports.ox_target:addLocalEntity(entity, options) + end +end + +RemoveEntityTarget = function(entity, optionNames) + if NetworkGetEntityIsNetworked(entity) then + local netId = NetworkGetNetworkIdFromEntity(entity) + exports.ox_target:removeEntity(netId, optionNames) + else + exports.ox_target:removeLocalEntity(entity, optionNames) + end +end + +AddTargetModel = function(model, options) + exports.ox_target:addModel(model, options) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/kloud-farmjob/target/qb-target.lua b/resources/[qb]/[qb_jobs]/kloud-farmjob/target/qb-target.lua new file mode 100644 index 0000000..719130a --- /dev/null +++ b/resources/[qb]/[qb_jobs]/kloud-farmjob/target/qb-target.lua @@ -0,0 +1,74 @@ +if GetResourceState("qb-target") ~= "started" or GetResourceState("ox_target") == "started" then return end + +AddTarget = function (coords, radius, options) + local optionsTbl = {} + local distance = 2.0 + for _, v in pairs(options) do + table.insert(optionsTbl, { + label = v.label, + name = v.name, + event = v.event or nil, + icon = v.icon, + canInteract = v.canInteract or nil, + action = v.onSelect or nil, + currentZone = v.currentZone + }) + distance = v.distance + end + exports['qb-target']:AddCircleZone(options[1].name, coords, radius, { + name = options[1].name, + debugPoly = KloudDev.Debug + }, { + options = optionsTbl, + distance = distance + }) +end + +AddEntityTarget = function (entity, options) + local optionsTbl = {} + local distance = 2.0 + for _, v in pairs(options) do + table.insert(optionsTbl, { + type = "client", + event = v.event or nil, + icon = v.icon, + label = v.label, + action = v.onSelect or nil, + canInteract = v.canInteract or nil, + currentZone = v.currentZone + }) + end + if NetworkGetEntityIsNetworked(entity) then + local netId = NetworkGetNetworkIdFromEntity(entity) + exports["qb-target"]:AddTargetEntity(netId, {options = optionsTbl, distance = distance}) + else + exports["qb-target"]:AddTargetEntity(entity, {options = optionsTbl, distance = distance}) + end +end + +AddTargetModel = function(model, options) + local optionsTbl = {} + local distance = 2.0 + for _, v in pairs(options) do + distance = v.distance or 2.0 + table.insert(optionsTbl, { + type = "client", + event = v.event or nil, + icon = v.icon, + label = v.label, + action = v.onSelect or nil, + canInteract = v.canInteract or nil, + currentZone = v.currentZone + }) + end + exports["qb-target"]:AddTargetModel(model, {options = optionsTbl, distance = distance}) +end + +RemoveEntityTarget = function(entity, optionNames, labels) + if NetworkGetEntityIsNetworked(entity) then + local netId = NetworkGetNetworkIdFromEntity(entity) + exports["qb-target"]:RemoveTargetEntity(netId, labels) + else + exports["qb-target"]:RemoveTargetEntity(entity, labels) + end +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/README.md b/resources/[qb]/[qb_jobs]/pickle_taxijob/README.md new file mode 100644 index 0000000..fc8b942 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/README.md @@ -0,0 +1,51 @@ +
+ + +## Preview + +https://www.youtube.com/watch?v=SHyzr0GcOx8 + +## What is this? + +

This is a multi-framework taxi job.

+ +

It's a great fit for any type of roleplaying server, whether it's Serious RP or not.

+ +With this resource, you will be able to do the following: + +- Create multiple taxi businesses. +- Allow multiple groups to access and manage a business. +- Earn money through NPC missions. +- Spawn Vehicles at the depot. +- Go on/off duty. +- Manage the business. + +## Supported Frameworks + +- ESX 1.1+ & Legacy +- QBCore +- Other (Code your own bridge) + +## What do I need? + +Use a supported framework or make it work with yours via the bridge folder. + +Ox Lib (Required). + +## Installation + +

Start ox_lib before pickle_taxijob.

+

Add your businesses in the config.lua.

+

Add the groups via the SQL files (use included examples in the "_INSTALL" folder).

+

Restart the server.

+ +## Need Support? + +Click here! + +## Licensing + +

Do not at any point redistribute this without my permission and credit.

+

I've already had to issue reports on people selling my Television Script (which is free).

+

That is not fair to anyone, especially to the people who get scammed out of their money.

+

So please, respect the rules and have fun!

diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/client.lua new file mode 100644 index 0000000..887fe53 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/client.lua @@ -0,0 +1,48 @@ +if GetResourceState('es_extended') ~= 'started' then return end + +ESX = exports.es_extended:getSharedObject() + +function ShowNotification(text) + ESX.ShowNotification(text) +end + +function ShowHelpNotification(text) + ESX.ShowHelpNotification(text) +end + +function ServerCallback(name, cb, ...) + ESX.TriggerServerCallback(name, cb, ...) +end + +function GetPlayersInArea(coords, maxDistance) + return ESX.Game.GetPlayersInArea(coords, maxDistance) +end + +function CanAccessGroup(data) + if not data then return true end + local pdata = ESX.GetPlayerData() + for k,v in pairs(data) do + if (pdata.job.name == k and pdata.job.grade >= v) then return true end + end + return false +end + +function AccessBossMenu(businessID) + local cfg = Config.Businesses[businessID] + if not CanAccessGroup(cfg.bossgroups) then + return ShowNotification(_L("no_access")) + end + TriggerEvent('esx_society:openBossMenu', cfg.info.society, function(data, menu) + menu.close() + end, { + withdraw = false, + deposit = false, + wash = true, + employees = true, + grades = false + }) +end + +RegisterNetEvent(GetCurrentResourceName()..":showNotification", function(text) + ShowNotification(text) +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/server.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/server.lua new file mode 100644 index 0000000..0f5ac41 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/esx/server.lua @@ -0,0 +1,75 @@ +if GetResourceState('es_extended') ~= 'started' then return end + +ESX = exports.es_extended:getSharedObject() + +function RegisterCallback(name, cb) + ESX.RegisterServerCallback(name, cb) +end + +function RegisterUsableItem(...) + ESX.RegisterUsableItem(...) +end + +function ShowNotification(target, text) + TriggerClientEvent(GetCurrentResourceName()..":showNotification", target, text) +end + +function Search(source, name) + local xPlayer = ESX.GetPlayerFromId(source) + if (name == "money") then + return xPlayer.getMoney() + elseif (name == "bank") then + return xPlayer.getAccount('bank').money + else + local item = xPlayer.getInventoryItem(name) + if item ~= nil then + return item.count + else + return 0 + end + end +end + +function AddItem(source, name, amount, metadata) + local xPlayer = ESX.GetPlayerFromId(source) + if (name == "money") then + return xPlayer.addMoney(amount) + elseif (name == "bank") then + return xPlayer.addAccountMoney('bank', amount) + else + return exports.ox_inventory:AddItem(source, name, amount, metadata) + end +end + +function RemoveItem(source, name, amount) + local xPlayer = ESX.GetPlayerFromId(source) + if (name == "money") then + return xPlayer.removeMoney(amount) + elseif (name == "bank") then + return xPlayer.removeAccountMoney('bank', amount) + else + return xPlayer.removeInventoryItem(name, amount) + end +end + +function CanAccessGroup(source, data) + if not data then return true end + local pdata = ESX.GetPlayerFromId(source) + for k,v in pairs(data) do + if (pdata.job.name == k and pdata.job.grade >= v) then return true end + end + return false +end + +function GetIdentifier(source) + local xPlayer = ESX.GetPlayerFromId(source) + return xPlayer.identifier +end + +-- REMOVE BELOW IF NOT USING ESX SOCIETY + +for i=1, #Config.Businesses do + local cfg = Config.Businesses[i] + local society = cfg.info.society + TriggerEvent('esx_society:registerSociety', society, society, 'society_'..society, 'society_'..society, 'society_'..society, {type = 'public'}) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/client.lua new file mode 100644 index 0000000..bb62209 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/client.lua @@ -0,0 +1,42 @@ +if GetResourceState('qb-core') ~= 'started' then return end + +QBCore = exports['qb-core']:GetCoreObject() + +function ServerCallback(name, cb, ...) + QBCore.Functions.TriggerCallback(name, cb, ...) +end + +function ShowNotification(text) + QBCore.Functions.Notify(text) +end + +function ShowHelpNotification(text) + AddTextEntry('qbHelpNotification', text) + BeginTextCommandDisplayHelp('qbHelpNotification') + EndTextCommandDisplayHelp(0, false, false, -1) +end + +function GetPlayersInArea(coords, maxDistance) + return QBCore.Functions.GetPlayersFromCoords(coords, maxDistance) +end + +function CanAccessGroup(data) + if not data then return true end + local pdata = QBCore.Functions.GetPlayerData() + for k,v in pairs(data) do + if (pdata.job.name == k and pdata.job.grade.level >= v) then return true end + end + return false +end + +function AccessBossMenu(businessID) + local cfg = Config.Businesses[businessID] + if not CanAccessGroup(cfg.bossgroups) then + return ShowNotification(_L("no_access")) + end + TriggerEvent('qb-bossmenu:client:OpenMenu') +end + +RegisterNetEvent(GetCurrentResourceName()..":showNotification", function(text) + ShowNotification(text) +end) diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/server.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/server.lua new file mode 100644 index 0000000..696fa32 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/qb/server.lua @@ -0,0 +1,67 @@ +if GetResourceState('qb-core') ~= 'started' then return end + +QBCore = exports['qb-core']:GetCoreObject() + +function RegisterCallback(name, cb) + QBCore.Functions.CreateCallback(name, cb) +end + +function RegisterUsableItem(...) + QBCore.Functions.CreateUseableItem(...) +end + +function ShowNotification(target, text) + TriggerClientEvent(GetCurrentResourceName()..":showNotification", target, text) +end + +function Search(source, name) + local xPlayer = QBCore.Functions.GetPlayer(source) + if (name == "money") then + return xPlayer.PlayerData.money['cash'] + elseif (name == "bank") then + return xPlayer.PlayerData.money['cash'] -- If anyone knows how to get bank balance for QBCore, let me know. + else + local item = xPlayer.Functions.GetItemByName(name) + if item ~= nil then + return item.amount + else + return 0 + end + end +end + +function AddItem(source, name, amount, metadata) + local xPlayer = QBCore.Functions.GetPlayer(source) + if (name == "money") then + return xPlayer.Functions.AddMoney("cash", amount) + elseif (name == "bank") then + return xPlayer.Functions.AddMoney("cash", amount) -- If anyone knows how to add to bank balance for QBCore, let me know. + else + return xPlayer.Functions.AddItem(name, amount, nil, metadata) + end +end + +function RemoveItem(source, name, amount) + local xPlayer = QBCore.Functions.GetPlayer(source) + if (name == "money") then + return xPlayer.Functions.RemoveMoney("cash", amount) + elseif (name == "bank") then + return xPlayer.Functions.RemoveMoney("cash", amount) -- If anyone knows how to remove from bank balance for QBCore, let me know. + else + return xPlayer.Functions.RemoveItem(name, amount) + end +end + +function CanAccessGroup(source, data) + if not data then return true end + local pdata = QBCore.Functions.GetPlayer(source).PlayerData + for k,v in pairs(data) do + if (pdata.job.name == k and pdata.job.grade.level >= v) then return true end + end + return false +end + +function GetIdentifier(source) + local xPlayer = QBCore.Functions.GetPlayer(source).PlayerData + return xPlayer.citizenid +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/client.lua new file mode 100644 index 0000000..89c1cd1 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/client.lua @@ -0,0 +1,4 @@ +if GetResourceState('es_extended') == 'started' then return end +if GetResourceState('qb-core') == 'started' then return end + +print("You are not using a supported framework, it will be required to make edits to the bridge files.") \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/server.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/server.lua new file mode 100644 index 0000000..89c1cd1 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/bridge/standalone/server.lua @@ -0,0 +1,4 @@ +if GetResourceState('es_extended') == 'started' then return end +if GetResourceState('qb-core') == 'started' then return end + +print("You are not using a supported framework, it will be required to make edits to the bridge files.") \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/config.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/config.lua new file mode 100644 index 0000000..3540631 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/config.lua @@ -0,0 +1,74 @@ +Config = {} + +Config.Debug = false + +Config.Language = "da" + +Config.Businesses = { + { + info = { + id = "pickle_taxi", + society = "taxi", + label = "HP Taxa Selskab", + }, + blip = { + Label = "HP Taxa Selskab", + Location = vector3(912.0522, -174.0470, 74.2908), + ID = 198, + Display = 4, + Scale = 0.75, + Color = 5 + }, + groups = { + ["taxi"] = 0, + }, + bossgroups = { + ["taxi"] = 4, + }, + vehicles = { + { + label = "Taxi", + model = `taxi`, + groups = { + ["taxi"] = 0, + } + }, + { + label = "Limosine", + model = `stretch`, + groups = { + ["taxi"] = 0, + } + }, + }, + locations = { + vehicle = vector4(916.0678, -163.4347, 74.6782, 152.6545), + boss = vector3(895.5319, -179.3002, 74.7003), + duty = vector3(900.5847, -171.5111, 74.0756) + } + } +} + +Config.Missions = { + loop = false, -- Keep doing missions until /taxijob is used. + reward = {name = "money", min = 10, max = 50, miles = 2.0}, -- multiples reward by miles traveled. + models = { + `s_m_m_cntrybar_01`, + `u_f_y_comjane`, + `a_f_y_hipster_04`, + `s_m_m_highsec_02`, + `a_m_y_hipster_03`, + }, + locations = { + vector4(946.3250, -171.7351, 74.5242, 56.1620), + vector4(397.9923, -870.3594, 29.2102, 322.1986), + vector4(59.2745, -1483.8176, 29.2773, 270.6085), + vector4(1246.3237, -1453.9513, 34.9354, 344.2509), + vector4(-289.3166, -1847.9614, 26.2498, 4.3302), + vector4(-45.8459, -1029.7800, 28.6224, 71.5370), + vector4(181.9603, -322.1017, 43.9382, 211.4422), + vector4(-514.8563, -260.6308, 35.5337, 211.8925), + vector4(-1284.6191, 297.2318, 64.9439, 154.2817), + vector4(-1440.0933, -773.8246, 23.4396, 343.2090), + } +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/core/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/core/client.lua new file mode 100644 index 0000000..9d7ae3b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/core/client.lua @@ -0,0 +1,62 @@ +function CreateVeh(modelHash, ...) + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do Wait(0) end + local veh = CreateVehicle(modelHash, ...) + SetModelAsNoLongerNeeded(modelHash) + return veh +end + +function CreateNPC(modelHash, ...) + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do Wait(0) end + local ped = CreatePed(26, modelHash, ...) + SetModelAsNoLongerNeeded(modelHash) + return ped +end + +function CreateProp(modelHash, ...) + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do Wait(0) end + local obj = CreateObject(modelHash, ...) + SetModelAsNoLongerNeeded(modelHash) + return obj +end + +function PlayAnim(ped, dict, ...) + RequestAnimDict(dict) + while not HasAnimDictLoaded(dict) do Wait(0) end + TaskPlayAnim(ped, dict, ...) +end + +function PlayEffect(dict, particleName, entity, off, rot, time, cb) + CreateThread(function() + RequestNamedPtfxAsset(dict) + while not HasNamedPtfxAssetLoaded(dict) do + Wait(0) + end + UseParticleFxAssetNextCall(dict) + Wait(10) + local particleHandle = StartParticleFxLoopedOnEntity(particleName, entity, off.x, off.y, off.z, rot.x, rot.y, rot.z, 1.0) + SetParticleFxLoopedColour(particleHandle, 0, 255, 0 , 0) + Wait(time) + StopParticleFxLooped(particleHandle, false) + cb() + end) +end + +function CreateBlip(data) + local x,y,z = table.unpack(data.Location) + local blip = AddBlipForCoord(x, y, z) + SetBlipSprite(blip, data.ID) + SetBlipDisplay(blip, data.Display) + SetBlipScale(blip, data.Scale) + SetBlipColour(blip, data.Color) + if (data.Rotation) then + SetBlipRotation(blip, math.ceil(data.Rotation)) + end + SetBlipAsShortRange(blip, true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(data.Label) + EndTextCommandSetBlipName(blip) + return blip +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/core/shared.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/core/shared.lua new file mode 100644 index 0000000..30e73a8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/core/shared.lua @@ -0,0 +1,10 @@ +function v3(coords) return vec3(coords.x, coords.y, coords.z), coords.w end + +function GetRandomInt(min, max, exclude) + for i=1, 1000 do + local int = math.random(min, max) + if exclude == nil or exclude ~= int then + return int + end + end +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/fxmanifest.lua new file mode 100644 index 0000000..3256f13 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/fxmanifest.lua @@ -0,0 +1,24 @@ +fx_version 'cerulean' +game "gta5" +version "v1.0.0" + +shared_scripts { + "@ox_lib/init.lua", + "config.lua", + "locales/locale.lua", + "locales/translations/da.lua", + "core/shared.lua" +} + +client_scripts { + "bridge/**/client.lua", + "modules/**/client.lua", + "core/client.lua" +} + +server_scripts { + "bridge/**/server.lua", + "modules/**/server.lua", +} + +lua54 'yes' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/locale.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/locale.lua new file mode 100644 index 0000000..0cab5e5 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/locale.lua @@ -0,0 +1,14 @@ +Language = {} + +function _L(name, ...) + if name then + local str = Language[Config.Language][name] + if str then + return string.format(str, ...) + else + return "ERR_TRANSLATE_"..(name).."_404" + end + else + return "ERR_TRANSLATE_404" + end +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/translations/da.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/translations/da.lua new file mode 100644 index 0000000..9b0b48b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/locales/translations/da.lua @@ -0,0 +1,26 @@ +Language["da"] = { + marker_interact_vehicle = "Tryk ~INPUT_CONTEXT~ for at åbne køretøjsmenuen.", + marker_remove_vehicle = "Tryk ~INPUT_CONTEXT~ for at parkere køretøjet.", + marker_interact_boss = "Tryk ~INPUT_CONTEXT~ for at åbne ledermenuen.", + marker_interact_duty = "Tryk ~INPUT_CONTEXT~ for at gå %s-duty.", + + vehicle_menu = "Køretøjsvalg", + vehicle_none = "Du har ingen køretøjer at vælge imellem.", + vehicle_stored = "Dit køretøj er blevet parkeret.", + vehicle_spawned = "Du er spawnet i arbejdskøretøjet.", + + no_access = "Du kan ikke gøre dette.", + duty_toggle = "Du er gået %s-duty hos %s.", + duty_forceoff = "Du gik hjem fra arbejde", + not_duty = "Du er ikke på arbejde.", + + taxi_occupied = "Der er en person i bilen, kør dem til deres destination før du starter et nyt job.", + taxi_pickup = "Hent personen der er markeret på din GPS.", + taxi_dropoff = "Aflever personen på den lokation der er markeret på din GPS.", + not_driver = "Du kører ikke en taxa.", + mission_fail = "Du har fejlet dit job.", + mission_success = "Du har fuldført ruten, og modtaget %s,-", + cancelled_mission = "Annullerede det nuværende job.", + taxi_pickup_blip = "Hent Kunde", + taxi_dropoff_blip = "Aflever Kunde", +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/client.lua new file mode 100644 index 0000000..945a11f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/client.lua @@ -0,0 +1,109 @@ +STATUS = { + BUSINESS = nil, + DUTY = false +} + +function GetStatus() + return STATUS +end + +function SetDutyStatus(businessID, bool) + TriggerServerEvent("pickle_taxijob:setDutyStatus", businessID, bool) +end + +function OpenVehicleMenu(businessID) + local cfg = Config.Businesses[businessID] + if not CanAccessGroup(cfg.groups) then + return ShowNotification(_L("no_access")) + end + if not STATUS.DUTY then + return ShowNotification(_L("not_duty")) + end + local options = {} + for i=1, #cfg.vehicles do + if CanAccessGroup(cfg.vehicles[i].groups) then + table.insert(options, {label = cfg.vehicles[i].label, value = i}) + end + end + if #options < 1 then return ShowNotification(_L("vehicle_none")) end + lib.registerMenu({ + id = 'pickle_taxijob_vehicle', + title = _L("vehicle_menu"), + position = 'top-right', + options = options + }, function(selected, scrollIndex, args) + local ped = PlayerPedId() + local vehicleData = cfg.vehicles[options[selected].value] + local coords, heading = v3(cfg.locations.vehicle) + local vehicle = CreateVeh(vehicleData.model, coords.x, coords.y, coords.z, heading, true, true) + TaskWarpPedIntoVehicle(ped, vehicle, -1) + ShowNotification(_L("vehicle_spawned")) + end) + + lib.showMenu('pickle_taxijob_vehicle') +end + +function InteractLocation(businessID, locationID) + if locationID == "vehicle" then + local vehicle = GetVehiclePedIsIn(PlayerPedId()) + if vehicle ~= 0 then + TaskLeaveAnyVehicle(PlayerPedId()) + Wait(1500) + DeleteEntity(vehicle) + ShowNotification(_L("vehicle_stored")) + else + OpenVehicleMenu(businessID) + end + elseif locationID == "boss" then + AccessBossMenu(businessID) + elseif locationID == "duty" then + SetDutyStatus(businessID, not STATUS.DUTY) + end +end + +function DisplayHelp(businessID, locationID) + if locationID == "vehicle" then + if GetVehiclePedIsIn(PlayerPedId()) ~= 0 then + ShowHelpNotification(_L("marker_remove_vehicle")) + else + ShowHelpNotification(_L("marker_interact_vehicle")) + end + elseif locationID == "boss" then + ShowHelpNotification(_L("marker_interact_boss")) + elseif locationID == "duty" then + ShowHelpNotification(_L("marker_interact_duty", STATUS.DUTY and "hjem fra arbejde" or "på arbejde")) + end +end + +RegisterNetEvent("pickle_taxijob:onDutyUpdate", function(businessID, bool) + STATUS.BUSINESS = businessID + STATUS.DUTY = bool +end) + +CreateThread(function() + for i=1, #Config.Businesses do + if Config.Businesses[i].blip then + CreateBlip(Config.Businesses[i].blip) + end + end + while true do + local wait = 1000 + for i=1, #Config.Businesses do + local cfg = Config.Businesses[i] + local ped = PlayerPedId() + local pcoords = GetEntityCoords(ped) + for k,v in pairs(cfg.locations) do + local coords = v3(v) + local dist = #(coords - pcoords) + if (dist < 20) then + wait = 0 + DrawMarker(2, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.25, 0.25, 255, 255, 255, 127, false, true) + if (dist < 1.25 and not DisplayHelp(i, k) and IsControlJustPressed(1, 51)) then + InteractLocation(i, k) + end + end + end + end + Wait(wait) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/server.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/server.lua new file mode 100644 index 0000000..5acbc1f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/business/server.lua @@ -0,0 +1,32 @@ +Players = {} + +function GetPlayer(source, createIfEmpty) + if Players[source] then + return Players[source] + elseif createIfEmpty then + Players[source] = {} + return Players[source] + end +end + +function SetDutyStatus(source, businessID, bool) + local player = GetPlayer(source, true) + Players[source].BUSINESS = businessID + Players[source].DUTY = bool + TriggerClientEvent("pickle_taxijob:onDutyUpdate", source, businessID, bool) +end + +RegisterNetEvent("pickle_taxijob:setDutyStatus", function(businessID, bool) + if type(businessID) ~= "boolean" then + local cfg = Config.Businesses[businessID] + if CanAccessGroup(cfg.groups) then + SetDutyStatus(source, businessID, bool) + ShowNotification(source, _L("duty_toggle", bool and "på arbejde" or "hjem fra arbejde", cfg.info.label)) + else + ShowNotification(source, _L("no_access")) + end + else + SetDutyStatus(source, nil, false) + ShowNotification(source, _L("duty_forceoff")) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/client.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/client.lua new file mode 100644 index 0000000..2ed42e9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/client.lua @@ -0,0 +1,174 @@ +local blip +local mission + +function Destination(text, coords) + if blip then + RemoveBlip(blip) + end + if not text then + return + end + blip = CreateBlip({ + Location = coords, + Label = text, + ID = 1, + Display = 4, + Color = 5, + Scale = 0.75 + }) + SetBlipRoute(blip, true) + SetBlipRouteColour(blip, 5) + return blip +end + +function IsVehicleTaxi(vehicle, list) + local model = GetEntityModel(vehicle) + for i=1, #list do + if model == list[i].model then + return true + end + end +end + +function StartMission(lastIndex) + if not STATUS.DUTY then + return ShowNotification(_L("not_duty")) + end + local business = Config.Businesses[STATUS.BUSINESS] + local cfg = Config.Missions + mission = {} + mission.from = GetRandomInt(1, #cfg.locations, lastIndex) + mission.to = GetRandomInt(1, #cfg.locations, mission.from) + mission.model = cfg.models[GetRandomInt(1, #cfg.models)] + mission.ped = nil + mission.taxi = GetVehiclePedIsIn(PlayerPedId()) + mission.status = "pickup" + + if GetPedInVehicleSeat(mission.taxi, 2) ~= 0 then + return ShowNotification(_L("taxi_occupied")) + end + + if GetPedInVehicleSeat(mission.taxi, -1) ~= PlayerPedId() or not IsVehicleTaxi(mission.taxi, business.vehicles) then + return ShowNotification(_L("not_driver")) + end + + if (mission and mission.status == "pickup") then + local coords, heading = v3(cfg.locations[mission.from]) + local enteringVehicle = false + + ShowNotification(_L("taxi_pickup")) + Destination(_L("taxi_pickup_blip"), coords) + + while mission and mission.status == "pickup" do + local wait = 1000 + local ped = PlayerPedId() + local pedCoords = GetEntityCoords(ped) + local dist = #(coords - pedCoords) + if (not DoesEntityExist(mission.taxi) or GetEntityHealth(mission.taxi) == 0) then + mission.status = "fail" + end + if (dist < 60.0) then + if not mission.ped then + enteringVehicle = false + mission.ped = CreateNPC(mission.model, coords.x, coords.y, coords.z, heading, true, true) + else + if IsEntityDead(mission.ped) then + mission.status = "fail" + end + if (dist < 10.0 and not enteringVehicle) then + enteringVehicle = true + TaskEnterVehicle(mission.ped, mission.taxi, -1, 2, 2.0, 1, 0) + elseif GetVehiclePedIsIn(mission.ped) == mission.taxi then + mission.status = "dropoff" + end + end + elseif mission.ped then + DeleteEntity(mission.ped) + mission.ped = nil + end + Wait(wait) + end + end + + if (mission and mission.status == "dropoff") then + local coords, heading = v3(cfg.locations[mission.to]) + local exitingVehicle = false + + ShowNotification(_L("taxi_dropoff")) + Destination(_L("taxi_dropoff_blip"), coords) + + while mission and mission.status == "dropoff" do + local wait = 1000 + local ped = PlayerPedId() + local pedCoords = GetEntityCoords(ped) + local dist = #(coords - pedCoords) + + if (not DoesEntityExist(mission.taxi) or GetEntityHealth(mission.taxi) == 0) then + mission.status = "fail" + end + if (not exitingVehicle and GetVehiclePedIsIn(mission.ped) ~= mission.taxi) or (not DoesEntityExist(mission.ped) or IsEntityDead(mission.ped)) then + mission.status = "fail" + end + if (dist < 5.0 and not exitingVehicle) then + exitingVehicle = true + TaskLeaveAnyVehicle(mission.ped, 1, 1) + elseif exitingVehicle and GetVehiclePedIsIn(mission.ped) ~= mission.taxi then + mission.status = "success" + end + Wait(wait) + end + end + + Destination() + + if (mission and mission.status == "success") then + for i=-1, 4 do + SetVehicleDoorShut(mission.taxi, i, false) + end + + ServerCallback("pickle_taxijob:npcMissionComplete", function(result) + if result then + local ped = mission.ped + TaskWanderStandard(ped, 1, 1) + SetTimeout(5000, function() + DeleteEntity(ped) + end) + else + ShowNotification(_L("mission_fail")) + end + if cfg.loop then + StartMission(mission.to) + else + mission = nil + end + end, mission.from, mission.to) + elseif (mission) then + for i=-1, 4 do + SetVehicleDoorShut(mission.taxi, i, false) + end + ShowNotification(_L("mission_fail")) + if cfg.loop then + StartMission(mission.to) + else + mission = nil + end + end +end + +function StopMission() + local _mission = mission + mission = nil + if _mission.ped then + DeleteEntity(_mission.ped) + end + Destination() + ShowNotification(_L("cancelled_mission")) +end + +RegisterCommand("taxijob", function() + if mission then + StopMission() + else + StartMission() + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/server.lua b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/server.lua new file mode 100644 index 0000000..535bad2 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/pickle_taxijob/modules/mission/server.lua @@ -0,0 +1,19 @@ +RegisterCallback("pickle_taxijob:npcMissionComplete", function(source, cb, from, to) + local player = GetPlayer(source, true) + local cfg = Config.Missions + local coords = { + from = v3(cfg.locations[from]), + to = v3(cfg.locations[to]), + } + local dist = #(coords.from - coords.to) + if (player.DUTY) then + local amount = math.random(cfg.reward.min, cfg.reward.max) + local multi = cfg.reward.miles * (dist / 1000) + amount = math.ceil(amount * multi) + AddItem(source, cfg.reward.name, amount) + ShowNotification(source, _L("mission_success", amount)) + cb(true) + else + cb(false) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/LICENSE b/resources/[qb]/[qb_jobs]/qb-ambulancejob/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/README.md b/resources/[qb]/[qb_jobs]/qb-ambulancejob/README.md new file mode 100644 index 0000000..8e5e0d6 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/README.md @@ -0,0 +1,35 @@ +# qb-ambulancejob +EMS Job and Death/Wound Logic for QB-Core Framework :ambulance: + +## Dependencies +- [qb-core](https://github.com/qbcore-framework/qb-core) (Required) +- [qb-phone](https://github.com/qbcore-framework/qb-phone) (Required) +- [qb-target](https://github.com/BerkieBb/qb-target) (Optional) +- [PolyZone](https://github.com/mkafrin/PolyZone) (Required) + +## Showcase +- [walk trough](https://www.youtube.com/watch?v=LWKerWlh3g4) + +## Features +- [More Config Option](https://youtu.be/9Qn4qRrGi7A) +- Ped Integratios +- [Ranjit's emsbag](https://github.com/Ranjit-Develops/Ranjit-EMS-bag) integration + + +# License + + QBCore Framework + Copyright (C) 2021 Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/dead.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/dead.lua new file mode 100644 index 0000000..e2d3c96 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/dead.lua @@ -0,0 +1,223 @@ +local deadAnimDict = "dead" +local deadAnim = "dead_a" +local hold = 5 +deathTime = 0 + +-- Functions + +local function loadAnimDict(dict) + while (not HasAnimDictLoaded(dict)) do + RequestAnimDict(dict) + Wait(5) + end +end + +function OnDeath() + if not isDead then + isDead = true + TriggerServerEvent("hospital:server:SetDeathStatus", true) + TriggerServerEvent("InteractSound_SV:PlayOnSource", "demo", 0.1) + local player = PlayerPedId() + + while GetEntitySpeed(player) > 0.5 or IsPedRagdoll(player) do + Wait(10) + end + + if isDead then + local pos = GetEntityCoords(player) + local heading = GetEntityHeading(player) + + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped) then + local veh = GetVehiclePedIsIn(ped) + local vehseats = GetVehicleModelNumberOfSeats(GetHashKey(GetEntityModel(veh))) + for i = -1, vehseats do + local occupant = GetPedInVehicleSeat(veh, i) + if occupant == ped then + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z + 0.5, heading, true, false) + SetPedIntoVehicle(ped, veh, i) + end + end + else + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z + 0.5, heading, true, false) + end + + SetEntityInvincible(player, true) + SetEntityHealth(player, GetEntityMaxHealth(player)) + if IsPedInAnyVehicle(player, false) then + loadAnimDict("veh@low@front_ps@idle_duck") + TaskPlayAnim(player, "veh@low@front_ps@idle_duck", "sit", 1.0, 1.0, -1, 1, 0, 0, 0, 0) + else + loadAnimDict(deadAnimDict) + TaskPlayAnim(player, deadAnimDict, deadAnim, 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + TriggerServerEvent('hospital:server:ambulanceAlert', Lang:t('info.civ_died')) + end + end +end + +function DeathTimer() + hold = 5 + while isDead do + Wait(1000) + deathTime = deathTime - 1 + if deathTime <= 0 then + if IsControlPressed(0, 38) and hold <= 0 and not isInHospitalBed then + TriggerEvent("hospital:client:RespawnAtHospital") + hold = 5 + end + if IsControlPressed(0, 38) then + if hold - 1 >= 0 then + hold = hold - 1 + else + hold = 0 + end + end + if IsControlReleased(0, 38) then + hold = 5 + end + end + end +end + +local function DrawTxt(x, y, width, height, scale, text, r, g, b, a, _) + SetTextFont(4) + SetTextProportional(0) + SetTextScale(scale, scale) + SetTextColour(r, g, b, a) + SetTextDropShadow(0, 0, 0, 0,255) + SetTextEdge(2, 0, 0, 0, 255) + SetTextDropShadow() + SetTextOutline() + SetTextEntry("STRING") + AddTextComponentString(text) + DrawText(x - width/2, y - height/2 + 0.005) +end + +-- Damage Handler + +AddEventHandler('gameEventTriggered', function(event, data) + if event == "CEventNetworkEntityDamage" then + local victim, attacker, victimDied, weapon = data[1], data[2], data[4], data[7] + if not IsEntityAPed(victim) then return end + if victimDied and NetworkGetPlayerIndexFromPed(victim) == PlayerId() and IsEntityDead(PlayerPedId()) then + if not InLaststand then + SetLaststand(true) + elseif InLaststand and not isDead then + SetLaststand(false) + local playerid = NetworkGetPlayerIndexFromPed(victim) + local playerName = GetPlayerName(playerid) .. " " .. "("..GetPlayerServerId(playerid)..")" or Lang:t('info.self_death') + local killerId = NetworkGetPlayerIndexFromPed(attacker) + local killerName = GetPlayerName(killerId) .. " " .. "("..GetPlayerServerId(killerId)..")" or Lang:t('info.self_death') + local weaponLabel = QBCore.Shared.Weapons[weapon].label or 'Ukendt' + local weaponName = QBCore.Shared.Weapons[weapon].name or 'Ukendt' + TriggerServerEvent("qb-log:server:CreateLog", "death", Lang:t('logs.death_log_title', {playername = playerName, playerid = GetPlayerServerId(playerid)}), "red", Lang:t('logs.death_log_message', {killername = killerName, playername = playerName, weaponlabel = weaponLabel, weaponname = weaponName})) + deathTime = Config.DeathTime + OnDeath() + DeathTimer() + end + end + end +end) + +-- Threads + +emsNotified = false + +CreateThread(function() + while true do + local sleep = 1000 + if isDead or InLaststand then + sleep = 5 + local ped = PlayerPedId() + DisableAllControlActions(0) + EnableControlAction(0, 1, true) + EnableControlAction(0, 2, true) + EnableControlAction(0, 245, true) + EnableControlAction(0, 38, true) + EnableControlAction(0, 0, true) + EnableControlAction(0, 322, true) + EnableControlAction(0, 288, true) + EnableControlAction(0, 213, true) + EnableControlAction(0, 249, true) + EnableControlAction(0, 46, true) + EnableControlAction(0, 47, true) + + if isDead then + if not isInHospitalBed then + if deathTime > 0 then + DrawTxt(0.93, 1.44, 1.0,1.0,0.6, Lang:t('info.respawn_txt', {deathtime = math.ceil(deathTime)}), 255, 255, 255, 255) + else + DrawTxt(0.865, 1.44, 1.0, 1.0, 0.6, Lang:t('info.respawn_revive', {holdtime = hold, cost = Config.BillCost}), 255, 255, 255, 255) + end + end + + if IsPedInAnyVehicle(ped, false) then + loadAnimDict("veh@low@front_ps@idle_duck") + if not IsEntityPlayingAnim(ped, "veh@low@front_ps@idle_duck", "sit", 3) then + TaskPlayAnim(ped, "veh@low@front_ps@idle_duck", "sit", 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + else + if isInHospitalBed then + if not IsEntityPlayingAnim(ped, inBedDict, inBedAnim, 3) then + loadAnimDict(inBedDict) + TaskPlayAnim(ped, inBedDict, inBedAnim, 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + else + if not IsEntityPlayingAnim(ped, deadAnimDict, deadAnim, 3) then + loadAnimDict(deadAnimDict) + TaskPlayAnim(ped, deadAnimDict, deadAnim, 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + end + end + + SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true) + elseif InLaststand then + sleep = 5 + + if LaststandTime > Config.MinimumRevive then + DrawTxt(0.94, 1.44, 1.0, 1.0, 0.6, Lang:t('info.bleed_out', {time = math.ceil(LaststandTime)}), 255, 255, 255, 255) + else + DrawTxt(0.845, 1.44, 1.0, 1.0, 0.6, Lang:t('info.bleed_out_help', {time = math.ceil(LaststandTime)}), 255, 255, 255, 255) + if not emsNotified then + DrawTxt(0.91, 1.40, 1.0, 1.0, 0.6, Lang:t('info.request_help'), 255, 255, 255, 255) + else + DrawTxt(0.90, 1.40, 1.0, 1.0, 0.6, Lang:t('info.help_requested'), 255, 255, 255, 255) + end + + if IsControlJustPressed(0, 47) and not emsNotified then + TriggerServerEvent('hospital:server:ambulanceAlert', Lang:t('info.civ_down')) + emsNotified = true + end + end + + if not isEscorted then + if IsPedInAnyVehicle(ped, false) then + loadAnimDict("veh@low@front_ps@idle_duck") + if not IsEntityPlayingAnim(ped, "veh@low@front_ps@idle_duck", "sit", 3) then + TaskPlayAnim(ped, "veh@low@front_ps@idle_duck", "sit", 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + else + loadAnimDict(lastStandDict) + if not IsEntityPlayingAnim(ped, lastStandDict, lastStandAnim, 3) then + TaskPlayAnim(ped, lastStandDict, lastStandAnim, 1.0, 1.0, -1, 1, 0, 0, 0, 0) + end + end + else + if IsPedInAnyVehicle(ped, false) then + loadAnimDict("veh@low@front_ps@idle_duck") + if IsEntityPlayingAnim(ped, "veh@low@front_ps@idle_duck", "sit", 3) then + StopAnimTask(ped, "veh@low@front_ps@idle_duck", "sit", 3) + end + else + loadAnimDict(lastStandDict) + if IsEntityPlayingAnim(ped, lastStandDict, lastStandAnim, 3) then + StopAnimTask(ped, lastStandDict, lastStandAnim, 3) + end + end + end + end + end + Wait(sleep) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/emsbag_cl.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/emsbag_cl.lua new file mode 100644 index 0000000..ce440a4 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/emsbag_cl.lua @@ -0,0 +1,74 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local emsbag1 = nil +local function dropemsbag() + DetachEntity(emsbag1) + PlaceObjectOnGroundProperly(emsbag1) +end +local function spawnemsbag() + local hasBag = true + CreateThread(function() + while hasBag do + Wait(0) + if IsControlJustReleased(0, 38) then -- If E is pressed it drop the bag + hasBag = false + dropemsbag() + Wait(1000) + end + end + end) +end + +local ObjectList = {} + +RegisterNetEvent('Ranjit-EmsBag:Client:SpawnAmbulanceBag', function() + local hash = GetHashKey('prop_cs_shopping_bag') + local ped = PlayerPedId() + local x, y, z = table.unpack(GetOffsetFromEntityInWorldCoords(ped, 0.0, 3.0, 0.5)) + QBCore.Functions.LoadModel(hash) + emsbag1 = CreateObjectNoOffset(hash, x, y, z, true, false) + SetModelAsNoLongerNeeded(hash) + AttachEntityToEntity(emsbag1, ped, GetPedBoneIndex(ped, 57005), 0.42, 0, -0.05, 0.10, 270.0, 60.0, true, true, false, + true, 1, true) + spawnemsbag() + TriggerServerEvent("Ranjit-EmsBag:Server:RemoveItem","emsbag",1) +end) + +RegisterNetEvent('Ranjit-EmsBag:Client:spawnLight', function() + + TriggerServerEvent("Ranjit-EmsBag:Server:SpawnAmbulanceBag", "emsbag") +end) + +RegisterNetEvent('Ranjit-EmsBag:Client:GuardarAmbulanceBag') +AddEventHandler("Ranjit-EmsBag:Client:GuardarAmbulanceBag", function() + local x, y, z = table.unpack(GetEntityCoords(PlayerPedId(), true)) + local playerPedPos = GetEntityCoords(PlayerPedId(), true) + local AmbulanceBag = GetClosestObjectOfType(playerPedPos, 10.0, GetHashKey("prop_cs_shopping_bag"), false, false, false) + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager EMS taske...") + Wait(2500) + Notify("EMS taske taget.") + SetEntityAsMissionEntity(AmbulanceBag, 1, 1) + DeleteObject(AmbulanceBag) + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem","emsbag",1) +end) + +local citizenid = nil +AddEventHandler("Ranjit-EmsBag:Client:StorageAmbulanceBag", function() + local charinfo = QBCore.Functions.GetPlayerData().charinfo + citizenid = QBCore.Functions.GetPlayerData().citizenid + TriggerEvent("inventory:client:SetCurrentStash", "Ambulance Taske",citizenid) + TriggerServerEvent("inventory:server:OpenInventory", "stash", "Ambulance Taske",citizenid, { + maxweight = Config.Stash.MaxWeighStash, + slots = Config.Stash.MaxSlotsStash, + }) +end) + +local AmbulanceBags = { + `prop_cs_shopping_bag`, +} + + +exports['qb-target']:AddTargetModel(AmbulanceBags, { + options = {{event = "Ranjit-EmsBag:Client:MenuAmbulanceBag",icon = "fa-solid fa-suitcase-medical",label = "Ems taske" , job = Config.Bag.Job }, + {event = "Ranjit-EmsBag:Client:GuardarAmbulanceBag",icon = "fa-solid fa-suitcase-medical",label = "Tag EMS taske" , job = Config.Bag.Job },},distance = 2.0 }) diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/job.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/job.lua new file mode 100644 index 0000000..af9f594 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/job.lua @@ -0,0 +1,1025 @@ +local PlayerJob = {} +local onDuty = false +local currentGarage = 0 +local currentHospital + + +-- Functions + +local function IsArmoryWhitelist() -- being removed + local retval = false + + if QBCore.Functions.GetPlayerData().job.type == 'leo' then + retval = true + end + return retval +end + +local function SetCarItemsInfo() + local items = {} + for _, item in pairs(Config.CarItems) do + local itemInfo = QBCore.Shared.Items[item.name:lower()] + items[item.slot] = { + name = itemInfo["name"], + amount = tonumber(item.amount), + info = item.info, + label = itemInfo["label"], + description = itemInfo["description"] and itemInfo["description"] or "", + weight = itemInfo["weight"], + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = item.slot, + } + end + Config.CarItems = items +end + + +local function GetClosestPlayer() + local closestPlayers = QBCore.Functions.GetPlayersFromCoords() + local closestDistance = -1 + local closestPlayer = -1 + local coords = GetEntityCoords(PlayerPedId()) + + for i = 1, #closestPlayers, 1 do + if closestPlayers[i] ~= PlayerId() then + local pos = GetEntityCoords(GetPlayerPed(closestPlayers[i])) + local distance = #(pos - coords) + + if closestDistance == -1 or closestDistance > distance then + closestPlayer = closestPlayers[i] + closestDistance = distance + end + end + end + return closestPlayer, closestDistance +end + +function TakeOutVehicle(vehicleInfo) + local coords = Config.Locations["vehicle"][currentGarage] + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleNumberPlateText(veh, Lang:t('info.amb_plate') .. tostring(math.random(1000, 9999))) + SetEntityHeading(veh, coords.w) + exports[Config.FuelScript]:SetFuel(veh, 100.0) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + if Config.VehicleSettings[vehicleInfo] ~= nil then + QBCore.Shared.SetDefaultVehicleExtras(veh, Config.VehicleSettings[vehicleInfo].extras) + end + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + SetVehicleEngineOn(veh, true, true) + end, vehicleInfo, coords, true) +end + +--[[function MenuGarage(currentSelection) + --print(json.encode(currentSelection)) + local vehicleMenu = { + { + header = Lang:t('menu.garage_title'), + isMenuHeader = true, + icon = "fas fa-warehouse", + } + } + + local authorizedVehicles = Config.AuthorizedVehicles[QBCore.Functions.GetPlayerData().job.grade.level] + for veh, label in pairs(authorizedVehicles) do + vehicleMenu[#vehicleMenu+1] = { + header = label, + icon = "fa-solid fa-car", + txt = "", + params = { + event = "ambulance:client:TakeOutVehicle", + args = { + vehicle = veh, + currentSelection = currentSelection + } + } + } + end + + if IsArmoryWhitelist() then + for veh, label in pairs(Config.WhitelistedVehicles) do + vehicleMenu[#vehicleMenu+1] = { + header = label, + txt = "", + params = { + event = "ambulance:client:TakeOutVehicle", + args = { + vehicle = veh, + currentSelection = currentSelection + } + } + } + end + end + + vehicleMenu[#vehicleMenu+1] = { + header = Lang:t('menu.close'), + txt = "", + params = { + event = "qb-menu:client:closeMenu" + } + + } + exports['qb-menu']:openMenu(vehicleMenu) +end]] + +-- Events + + + +--RegisterNetEvent('ambulance:client:TakeOutVehicle', function(data) + -- local vehicle = data.vehicle + --TakeOutVehicle(vehicle) +--end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + PlayerJob = JobInfo + if PlayerJob.name == 'ambulance' then + onDuty = PlayerJob.onduty + if PlayerJob.onduty then + TriggerServerEvent("hospital:server:AddDoctor", PlayerJob.name) + else + TriggerServerEvent("hospital:server:RemoveDoctor", PlayerJob.name) + end + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + exports.spawnmanager:setAutoSpawn(false) + local ped = PlayerPedId() + local player = PlayerId() + CreateThread(function() + Wait(5000) + SetEntityMaxHealth(ped, 200) + SetEntityHealth(ped, 200) + SetPlayerHealthRechargeMultiplier(player, 0.0) + SetPlayerHealthRechargeLimit(player, 0.0) + end) + CreateThread(function() + Wait(1000) + QBCore.Functions.GetPlayerData(function(PlayerData) + PlayerJob = PlayerData.job + onDuty = PlayerData.job.onduty + SetPedArmour(PlayerPedId(), PlayerData.metadata["armor"]) + if (not PlayerData.metadata["inlaststand"] and PlayerData.metadata["isdead"]) then + deathTime = Laststand.ReviveInterval + OnDeath() + DeathTimer() + elseif (PlayerData.metadata["inlaststand"] and not PlayerData.metadata["isdead"]) then + SetLaststand(true) + else + TriggerServerEvent("hospital:server:SetDeathStatus", false) + TriggerServerEvent("hospital:server:SetLaststandStatus", false) + end + if PlayerJob.name == 'ambulance' and onDuty then + TriggerServerEvent("hospital:server:AddDoctor", PlayerJob.name) + end + end) + end) +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + if PlayerJob.name == 'ambulance' and onDuty then + TriggerServerEvent("hospital:server:RemoveDoctor", PlayerJob.name) + end +end) + +RegisterNetEvent('QBCore:Client:SetDuty', function(duty) + if PlayerJob.name == 'ambulance' and duty ~= onDuty then + if duty then + TriggerServerEvent("hospital:server:AddDoctor", PlayerJob.name) + else + TriggerServerEvent("hospital:server:RemoveDoctor", PlayerJob.name) + end + end + + onDuty = duty +end) + +function Status() + if isStatusChecking then + local statusMenu = { + { + header = Lang:t('menu.status'), + isMenuHeader = true + } + } + for _, v in pairs(statusChecks) do + statusMenu[#statusMenu + 1] = { + header = v.label, + txt = "", + params = { + event = "hospital:client:TreatWounds", + } + } + end + statusMenu[#statusMenu + 1] = { + header = Lang:t('menu.close'), + txt = "", + params = { + event = "qb-menu:client:closeMenu" + } + } + exports['qb-menu']:openMenu(statusMenu) + end +end + +RegisterNetEvent('hospital:client:CheckStatus', function() + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 5.0 then + local playerId = GetPlayerServerId(player) + QBCore.Functions.TriggerCallback('hospital:GetPlayerStatus', function(result) + if result then + for k, v in pairs(result) do + if k ~= "BLEED" and k ~= "WEAPONWOUNDS" then + statusChecks[#statusChecks + 1] = { bone = Config.BoneIndexes[k], + label = v.label .. " (" .. Config.WoundStates[v.severity] .. ")" } + elseif result["WEAPONWOUNDS"] then + for _, v2 in pairs(result["WEAPONWOUNDS"]) do + TriggerEvent('chat:addMessage', { + color = { 255, 0, 0 }, + multiline = false, + args = { Lang:t('info.status'), QBCore.Shared.Weapons[v2].damagereason } + }) + end + elseif result["BLEED"] > 0 then + TriggerEvent('chat:addMessage', { + color = { 255, 0, 0 }, + multiline = false, + args = { Lang:t('info.status'), + Lang:t('info.is_status', { status = Config.BleedingStates[v].label }) } + }) + else + QBCore.Functions.Notify(Lang:t('success.healthy_player'), 'success') + end + end + isStatusChecking = true + Status() + end + end, playerId) + else + QBCore.Functions.Notify(Lang:t('error.no_player'), 'error') + end +end) + +RegisterNetEvent('hospital:client:RevivePlayer', function() + local hasItem = QBCore.Functions.HasItem('firstaid') + if hasItem then + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 5.0 then + local playerId = GetPlayerServerId(player) + QBCore.Functions.Progressbar("hospital_revive", Lang:t('progress.revive'), 5000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = healAnimDict, + anim = healAnim, + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), healAnimDict, "exit", 1.0) + QBCore.Functions.Notify(Lang:t('success.revived'), 'success') + TriggerServerEvent("hospital:server:RevivePlayer", playerId) + end, function() -- Cancel + StopAnimTask(PlayerPedId(), healAnimDict, "exit", 1.0) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) + else + QBCore.Functions.Notify(Lang:t('error.no_player'), "error") + end + else + QBCore.Functions.Notify(Lang:t('error.no_firstaid'), "error") + end +end) + +RegisterNetEvent('hospital:client:TreatWounds', function() + local hasItem = QBCore.Functions.HasItem('bandage') + if hasItem then + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 5.0 then + local playerId = GetPlayerServerId(player) + QBCore.Functions.Progressbar("hospital_healwounds", Lang:t('progress.healing'), 5000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = healAnimDict, + anim = healAnim, + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), healAnimDict, "exit", 1.0) + QBCore.Functions.Notify(Lang:t('success.helped_player'), 'success') + TriggerServerEvent("hospital:server:TreatWounds", playerId) + end, function() -- Cancel + StopAnimTask(PlayerPedId(), healAnimDict, "exit", 1.0) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) + else + QBCore.Functions.Notify(Lang:t('error.no_player'), "error") + end + else + QBCore.Functions.Notify(Lang:t('error.no_bandage'), "error") + end +end) + +local check = false +local function EMSControls(variable) + CreateThread(function() + check = true + while check do + if IsControlJustPressed(0, 38) then + exports['qb-core']:KeyPressed(38) + if variable == "sign" then + TriggerEvent('EMSToggle:Duty') + elseif variable == "stash" then + TriggerEvent('qb-ambulancejob:stash') + elseif variable == "armory" then + TriggerEvent('qb-ambulancejob:armory') + elseif variable == "storeheli" then + TriggerEvent('qb-ambulancejob:storeheli') + elseif variable == "takeheli" then + TriggerEvent('qb-ambulancejob:pullheli') + elseif variable == "roof" then + TriggerEvent('qb-ambulancejob:elevator_main') + elseif variable == "main" then + TriggerEvent('qb-ambulancejob:elevator_roof') + elseif variable == "basement" then + TriggerEvent('qb-ambulancejob:elevator_basement') + end + end + end + end) +end + +RegisterNetEvent('qb-ambulancejob:stash', function() + if onDuty then + TriggerServerEvent("inventory:server:OpenInventory", "stash", + "ambulancestash_" .. QBCore.Functions.GetPlayerData().citizenid) + TriggerEvent("inventory:client:SetCurrentStash", "ambulancestash_" .. QBCore.Functions.GetPlayerData().citizenid) + end +end) + +RegisterNetEvent('qb-ambulancejob:armory', function() + if onDuty then + TriggerServerEvent("inventory:server:OpenInventory", "shop", "hospital", Config.Items) + end +end) + +local CheckVehicle = false +local function EMSVehicle(k) + CheckVehicle = true + CreateThread(function() + while CheckVehicle do + exports['qb-core']:KeyPressed(38) + CheckVehicle = false + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped, false) then + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(ped)) + else + local currentVehicle = k + --MenuGarage(currentVehicle) + currentGarage = currentVehicle + end + Wait(1) + end + end) +end + +RegisterNetEvent("ambulance:client:VehicleMenuHeader", function(data) + local Menu = { + { + header = Lang:t('menu.garage_title'), + isMenuHeader = true, + icon = "fas fa-warehouse", + } + } + for k,v in pairs(Config.VehicleTable) do + Menu[#Menu+1] = { + header = k:upper(), + txt = "Select a Heli to fly with", + icon = "fa-solid fa-shield", + params = { + event = "ambulance:client:veh-category-selected", + args = { + category = k, + location = data.spawn, + } + } + } + end + exports['qb-menu']:openMenu(Menu) +end) + +RegisterNetEvent("ambulance:client:VehicleMenuHeader", function(data) + local Menu = { + { + header = Lang:t('menu.garage_title'), + isMenuHeader = true, + icon = "fas fa-warehouse", + } + } + for k,v in pairs(Config.VehicleTable) do + Menu[#Menu+1] = { + header = k:upper(), + txt = "Select a Heli to fly with", + icon = "fa-solid fa-shield", + params = { + event = "ambulance:client:veh-category-selected", + args = { + category = k, + location = data.spawn, + } + } + } + end + exports['qb-menu']:openMenu(Menu) +end) + +RegisterNetEvent("ambulance:client:TakeOutVehicle", function(data) + local VehicleSpawnCoord = Config.Locations["vehicle"][data.currentSelection]["vehspawn"] + local plate = "EMS".."-".. math.random(000, 999) + + QBCore.Functions.SpawnVehicle(data.model, function(veh) + --print("callback") + SetVehicleNumberPlateText(veh, plate) + SetEntityHeading(veh, VehicleSpawnCoord.w) + SetEntityAsMissionEntity(veh, true, true) + SetCarItemsInfo() + exports[Config.FuelScript]:SetFuel(veh, 100.0) + TriggerEvent('vehiclekeys:client:SetOwner', QBCore.Functions.GetPlate(veh)) + TriggerServerEvent("hospital:server:addTrunkItems", QBCore.Functions.GetPlate(veh), Config.CarItems) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + end, vector3(VehicleSpawnCoord.x,VehicleSpawnCoord.y,VehicleSpawnCoord.z), true) +end) + + + +local CheckHeli = false +local function EMSHelicopter(k) + CheckHeli = true + CreateThread(function() + while CheckHeli do + if IsControlJustPressed(0, 38) then + exports['qb-core']:KeyPressed(38) + CheckHeli = false + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped, false) then + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(ped)) + else + local currentHelictoper = k + local coords = Config.Locations["helicopter"][currentHelictoper] + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleNumberPlateText(veh, Lang:t('info.heli_plate') .. tostring(math.random(1000, 9999))) + SetEntityHeading(veh, coords.w) + SetVehicleLivery(veh, 1) -- Ambulance Livery + exports[Config.FuelScript]:SetFuel(veh, 100.0) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + SetVehicleEngineOn(veh, true, true) + end, Config.Helicopter, coords, true) + end + end + Wait(1) + end + end) +end + + + +RegisterNetEvent("ambulance:client:TakeOutCopter", function(data) + local VehicleSpawnCoord = Config.Locations["helicopter"][data.currentSelection]["vehspawn"] + local plate = "EMS".."-".."ZULU" + + QBCore.Functions.SpawnVehicle(data.model, function(veh) + --print("callback") + SetVehicleNumberPlateText(veh, plate) + SetEntityHeading(veh, VehicleSpawnCoord.w) + SetEntityAsMissionEntity(veh, true, true) + -- SetCarItemsInfo() + exports[Config.FuelScript]:SetFuel(veh, 100.0) + SetVehicleLivery(veh, 1) -- Ambulance Livery + TriggerEvent('vehiclekeys:client:SetOwner', QBCore.Functions.GetPlate(veh)) + TriggerServerEvent("hospital:server:addTrunkItems", QBCore.Functions.GetPlate(veh), Config.CarItems) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + end, vector3(VehicleSpawnCoord.x,VehicleSpawnCoord.y,VehicleSpawnCoord.z), true) +end) + + +RegisterNetEvent('qb-ambulancejob:elevator_basement', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["main"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["basement"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('qb-ambulancejob:elevator_roof', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["roof"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["main"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('ambulance:client:veh-category-selected', function(data) + local newtable = data.category + local result = Config.VehicleTable[newtable] + if not result then return end + local Menu = { + { + header = Lang:t('menu.garage_title'), + isMenuHeader = true, + icon = "fas fa-warehouse", + } + } + for k,v in pairs(result) do + Menu[#Menu+1] = { + header = v:upper(), + txt = "", + icon = "fa-solid fa-shield", + params = { + event = "ambulance:client:TakeOutVehicle", + args = { + currentSelection = data.location, + model = v, + } + } + } + end + exports['qb-menu']:openMenu(Menu) +end) + +RegisterNetEvent("ambulance:client:CopterMenu", function(data) + local heli = Config.Helicopters + local copterlist = {} + copterlist[#copterlist + 1] = { -- create non-clickable header button + isMenuHeader = true, + header = 'Helikopter Garage', + icon = 'fa-solid fa-shield' + } + for k,v in pairs(heli) do -- loop through our table + copterlist[#copterlist + 1] = { -- insert data from our loop into the menu + header = k, + txt = 'De er bestemt '..v, + icon = 'fa-solid fa-helicopter', + params = { + event = 'ambulance:client:TakeOutCopter', -- event name + args = { + currentSelection = data.spawn, + model = v, + } + } + } + end + exports['qb-menu']:openMenu(copterlist) -- open our menu +end) + +RegisterNetEvent('qb-ambulancejob:elevator_main', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["main"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["roof"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('qb-ambulancejob:elevator_basement-main', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["basement"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["main"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('EMSToggle:Duty', function() + onDuty = not onDuty + TriggerServerEvent("QBCore:ToggleDuty") + --TriggerServerEvent("police:server:UpdateBlips") +end) + + +CreateThread(function() + + for k, v in pairs(Config.Locations["vehicle"]) do + + QBCore.Functions.LoadModel(Config.GaragePed) + while not HasModelLoaded(Config.GaragePed) do + Wait(100) + end + GaragePed = CreatePed(0, Config.GaragePed, v.pedspawn.x, v.pedspawn.y, v.pedspawn.z-1.0, v.w, false, true) + TaskStartScenarioInPlace(GaragePed, true) + FreezeEntityPosition(GaragePed, true) + SetEntityInvincible(GaragePed, true) + SetBlockingOfNonTemporaryEvents(GaragePed, true) + TaskStartScenarioInPlace(GaragePed, Config.GaragePedScenario, 0, true) + + exports['qb-target']:AddBoxZone("name", vector3(v.pedspawn.x, v.pedspawn.y, v.pedspawn.z-1), 1.0, 1.0, { -- The name has ambulance:client:TakeOutVehicle to be unique, the coords a vector3 as shown, the 1.5 is the length of the boxzone and the 1.6 is the width of the boxzone, the length and width have to be float values + name = "vehicle" .. k, + debugPoly = Config.Debug, + heading = v.pedspawn.w, + minZ = v.pedspawn.z - 1.0, + maxZ = v.pedspawn.z + 1.0, + }, { + options = { + { + icon = 'fa-solid fa-warehouse', + label = 'Åben garage', + type = "client", + event = "ambulance:client:VehicleMenuHeader", + job = "ambulance", + spawn = k + + }, + { + icon = 'fa-solid fa-car', + label = 'Parker køretøj', + type = "client", + event = "police:client:returnveh", + job = "ambulance", + } + }, + distance = 4.0 + }) + end + + for k, v in pairs(Config.Locations["helicopter"]) do + QBCore.Functions.LoadModel(Config.HeliPed) + while not HasModelLoaded(Config.HeliPed) do + Wait(100) + end + heliped = CreatePed(0, Config.HeliPed, v.pedspawn.x, v.pedspawn.y, v.pedspawn.z-1.0, v.pedspawn.w, false, true) + TaskStartScenarioInPlace(heliped, true) + FreezeEntityPosition(heliped, true) + SetEntityInvincible(heliped, true) + SetBlockingOfNonTemporaryEvents(heliped, true) + TaskStartScenarioInPlace(heliped, Config.HeliPedScenario, 0, true) + + exports['qb-target']:AddBoxZone("heli" .. k, vector3(v.pedspawn.x, v.pedspawn.y, v.pedspawn.z-1), 1.0, 1.0, { + name = "heli" .. k, + debugPoly = Config.Debug, + heading = v.pedspawn.w, + minZ = v.pedspawn.z - 1.0, + maxZ = v.pedspawn.z + 1.0, + }, { + options = { + { + icon = 'fa-solid fa-helicopter', + label = 'Åben helikopter hangar', + type = "client", + event = "ambulance:client:CopterMenu", + job = "ambulance", + spawn = k + + }, + { + icon = 'fa-solid fa-car', + label = 'Parker køretøj', + type = "client", + event = "police:client:returnveh", + job = "ambulance", + } + }, + distance = 4.0 + }) + + end +end) + +-- Convar turns into a boolean +if Config.UseTarget then + CreateThread(function() + for k, v in pairs(Config.Locations["duty"]) do + QBCore.Functions.LoadModel(Config.DutyPed) + while not HasModelLoaded(Config.DutyPed) do + Wait(100) + end + dutyPed = CreatePed(0, Config.DutyPed, v.x, v.y, v.z-1.5, v.w, false, true) + TaskStartScenarioInPlace(dutyPed, true) + FreezeEntityPosition(dutyPed, true) + SetEntityInvincible(dutyPed, true) + SetBlockingOfNonTemporaryEvents(dutyPed, true) + TaskStartScenarioInPlace(dutyPed, Config.DutyPedScenario, 0, true) + + + exports['qb-target']:AddBoxZone("emsDuty".. k, vector3(v.x, v.y, v.z-1.0), 1.0, 1.0, { -- The name has to be unique, the coords a vector3 as shown, the 1.5 is the length of the boxzone and the 1.6 is the width of the boxzone, the length and width have to be float values + name = "emsDuty".. k, -- This is the name of the zone recognized by PolyZone, this has to be unique so it doesn't mess up with other zones + heading = v.w, -- The heading of the boxzone, this has to be a float value + debugPoly = Config.Debug, -- This is for enabling/disabling the drawing of the box, it accepts only a boolean value (true or false), when true it will draw the polyzone in green + minZ = v.z -1.0, -- This is the bottom of the boxzone, this can be different from the Z value in the coords, this has to be a float value + maxZ = v.z +1.0, -- This is the top of the boxzone, this can be different from the Z value in the coords, this has to be a float value + }, { + options = { + { + type = "client", + event = "EMSToggle:Duty", + icon = "fa fa-clipboard", + label = "Gå hjem/på arbejde", + job = "ambulance" + } + }, + distance = 1.2, + }) + + end + for k, v in pairs(Config.Locations["stash"]) do + exports['qb-target']:AddBoxZone("stash" .. k, vector3(v.x, v.y, v.z-1), 1, 1, { + name = "stash" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:stash", + icon = "fa fa-hand", + label = "Åben inventar", + job = "ambulance", + } + }, + distance = 2.0 + }) + end + for k, v in pairs(Config.Locations["armory"]) do + QBCore.Functions.LoadModel(Config.ArmoryPed) + while not HasModelLoaded(Config.ArmoryPed) do + Wait(100) + end + ArmoryPed = CreatePed(0, Config.ArmoryPed, v.x, v.y, v.z-1.0, v.w, false, true) + TaskStartScenarioInPlace(ArmoryPed, true) + FreezeEntityPosition(ArmoryPed, true) + SetEntityInvincible(ArmoryPed, true) + SetBlockingOfNonTemporaryEvents(ArmoryPed, true) + TaskStartScenarioInPlace(ArmoryPed, Config.ArmoryPedScenario, 0, true) + + exports['qb-target']:AddBoxZone("armory" .. k, vector3(v.x, v.y, v.z-1), 1, 1, { + name = "armory" .. k, + debugPoly = Config.Debug, + heading = v.w, + minZ = v.z - 1.0, + maxZ = v.z + 1.0, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:armory", + icon = "fa fa-hand", + label = "Åben skab", + job = "ambulance" + } + }, + distance = 1.5 + }) + end + for k, v in pairs(Config.Locations["roof"]) do + exports['qb-target']:AddBoxZone("roof" .. k, vector3(v.x, v.y, v.z), 2, 2, { + name = "roof" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:elevator_roof", + icon = "fas fa-hand-point-up", + label = "Tag elevator", + job = "ambulance" + }, + }, + distance = 8 + }) + end + for k, v in pairs(Config.Locations["main"]) do + exports['qb-target']:AddBoxZone("main" .. k, vector3(v.x, v.y, v.z), 1.5, 1.5, { + name = "main" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:elevator_main", + icon = "fas fa-hand-point-up", + label = "Tag elevator op", + job = "ambulance" + }, + { + type = "client", + event = "qb-ambulancejob:elevator_basement", + icon = "fas fa-hand-point-down", + label = "Tag elevator ned", + job = "ambulance" + } + }, + distance = 8 + }) + end + for k, v in pairs(Config.Locations["basement"]) do + exports['qb-target']:AddBoxZone("basement" .. k, vector3(v.x, v.y, v.z), 1.5, 1.5, { + name = "basement" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:elevator_basement-main", + icon = "fas fa-hand-point-up", + label = "Tag elevator op", + job = "ambulance" + }, + }, + distance = 8 + }) + end + end) +else + CreateThread(function() + local signPoly = {} + for k, v in pairs(Config.Locations["duty"]) do + signPoly[#signPoly + 1] = BoxZone:Create(vector3(vector3(v.x, v.y, v.z)), 1.5, 1, { + name = "sign" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + end + + local signCombo = ComboZone:Create(signPoly, { name = "signcombo", debugPoly = false }) + signCombo:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerJob.name == "ambulance" then + if not onDuty then + exports['qb-core']:DrawText(Lang:t('text.onduty_button'), 'top') + EMSControls("sign") + else + exports['qb-core']:DrawText(Lang:t('text.offduty_button'), 'top') + EMSControls("sign") + end + else + check = false + exports['qb-core']:HideText() + end + end) + + local stashPoly = {} + for k, v in pairs(Config.Locations["stash"]) do + stashPoly[#stashPoly + 1] = BoxZone:Create(vector3(vector3(v.x, v.y, v.z)), 1, 1, { + name = "stash" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + end + + local stashCombo = ComboZone:Create(stashPoly, { name = "stashCombo", debugPoly = false }) + stashCombo:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerJob.name == "ambulance" then + if onDuty then + exports['qb-core']:DrawText(Lang:t('text.pstash_button'), 'top') + EMSControls("stash") + end + else + check = false + exports['qb-core']:HideText() + end + end) + + local armoryPoly = {} + for k, v in pairs(Config.Locations["armory"]) do + armoryPoly[#armoryPoly + 1] = BoxZone:Create(vector3(vector3(v.x, v.y, v.z)), 1, 1, { + name = "armory" .. k, + debugPoly = Config.Debug, + heading = 70, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + end + + local armoryCombo = ComboZone:Create(armoryPoly, { name = "armoryCombo", debugPoly = false }) + armoryCombo:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerJob.name == "ambulance" then + if onDuty then + exports['qb-core']:DrawText(Lang:t('text.armory_button'), 'top') + EMSControls("armory") + end + else + check = false + exports['qb-core']:HideText() + end + end) + + local roofPoly = {} + for k, v in pairs(Config.Locations["roof"]) do + roofPoly[#roofPoly + 1] = BoxZone:Create(vector3(vector3(v.x, v.y, v.z)), 2, 2, { + name = "roof" .. k, + debugPoly = Config.Debug, + heading = 70, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + end + + local roofCombo = ComboZone:Create(roofPoly, { name = "roofCombo", debugPoly = false }) + roofCombo:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerJob.name == "ambulance" then + if onDuty then + exports['qb-core']:DrawText(Lang:t('text.elevator_main'), 'top') + EMSControls("main") + else + exports['qb-core']:DrawText(Lang:t('error.not_ems'), 'top') + end + else + check = false + exports['qb-core']:HideText() + end + end) + + local mainPoly = {} + for k, v in pairs(Config.Locations["main"]) do + mainPoly[#mainPoly + 1] = BoxZone:Create(vector3(vector3(v.x, v.y, v.z)), 1.5, 1.5, { + name = "main" .. k, + debugPoly = Config.Debug, + heading = 70, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + end + + local mainCombo = ComboZone:Create(mainPoly, { name = "mainPoly", debugPoly = false }) + mainCombo:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerJob.name == "ambulance" then + if onDuty then + exports['qb-core']:DrawText(Lang:t('text.elevator_roof'), 'top') + EMSControls("roof") + else + exports['qb-core']:DrawText(Lang:t('error.not_ems'), 'top') + end + else + check = false + exports['qb-core']:HideText() + end + end) + end) +end diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/laststand.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/laststand.lua new file mode 100644 index 0000000..2f95120 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/laststand.lua @@ -0,0 +1,181 @@ +Laststand = Laststand or {} +Laststand.ReviveInterval = 360 +Laststand.MinimumRevive = 300 +InLaststand = false +LaststandTime = 0 +lastStandDict = "combat@damage@rb_writhe" +lastStandAnim = "rb_writhe_loop" +isEscorted = false +local isEscorting = false + +-- Functions + +local function GetClosestPlayer() + local closestPlayers = QBCore.Functions.GetPlayersFromCoords() + local closestDistance = -1 + local closestPlayer = -1 + local coords = GetEntityCoords(PlayerPedId()) + + for i=1, #closestPlayers, 1 do + if closestPlayers[i] ~= PlayerId() then + local pos = GetEntityCoords(GetPlayerPed(closestPlayers[i])) + local distance = #(pos - coords) + + if closestDistance == -1 or closestDistance > distance then + closestPlayer = closestPlayers[i] + closestDistance = distance + end + end + end + + return closestPlayer, closestDistance +end + +local function LoadAnimation(dict) + while not HasAnimDictLoaded(dict) do + RequestAnimDict(dict) + Wait(100) + end +end + +function SetLaststand(bool, spawn) + local ped = PlayerPedId() + if bool then + Wait(1000) + local pos = GetEntityCoords(ped) + local heading = GetEntityHeading(ped) + + while GetEntitySpeed(ped) > 0.5 or IsPedRagdoll(ped) do + Wait(10) + end + TriggerServerEvent("InteractSound_SV:PlayOnSource", "heart", 0.2) + LaststandTime = Laststand.ReviveInterval + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped) then + local veh = GetVehiclePedIsIn(ped) + local vehseats = GetVehicleModelNumberOfSeats(GetHashKey(GetEntityModel(veh))) + for i = -1, vehseats do + local occupant = GetPedInVehicleSeat(veh, i) + if occupant == ped then + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z + 0.5, heading, true, false) + SetPedIntoVehicle(ped, veh, i) + end + end + else + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z + 0.5, heading, true, false) + end + SetEntityHealth(ped, 150) + if IsPedInAnyVehicle(ped, false) then + LoadAnimation("veh@low@front_ps@idle_duck") + TaskPlayAnim(ped, "veh@low@front_ps@idle_duck", "sit", 1.0, 8.0, -1, 1, -1, false, false, false) + else + LoadAnimation(lastStandDict) + TaskPlayAnim(ped, lastStandDict, lastStandAnim, 1.0, 8.0, -1, 1, -1, false, false, false) + end + + InLaststand = true + + TriggerServerEvent('hospital:server:ambulanceAlert', Lang:t('info.civ_down')) + + CreateThread(function() + while InLaststand do + ped = PlayerPedId() + player = PlayerId() + if LaststandTime - 1 > Laststand.MinimumRevive then + LaststandTime = LaststandTime - 1 + Config.DeathTime = LaststandTime + elseif LaststandTime - 1 <= Laststand.MinimumRevive and LaststandTime - 1 ~= 0 then + LaststandTime = LaststandTime - 1 + Config.DeathTime = LaststandTime + elseif LaststandTime - 1 <= 0 then + QBCore.Functions.Notify(Lang:t('error.bled_out'), "error") + SetLaststand(false) + local killer_2, killerWeapon = NetworkGetEntityKillerOfPlayer(player) + local killer = GetPedSourceOfDeath(ped) + + if killer_2 ~= 0 and killer_2 ~= -1 then + killer = killer_2 + end + + local killerId = NetworkGetPlayerIndexFromPed(killer) + local killerName = killerId ~= -1 and GetPlayerName(killerId) .. " " .. "("..GetPlayerServerId(killerId)..")" or Lang:t('info.self_death') + local weaponLabel = Lang:t('info.wep_unknown') + local weaponName = Lang:t('info.wep_unknown') + local weaponItem = QBCore.Shared.Weapons[killerWeapon] + if weaponItem then + weaponLabel = weaponItem.label + weaponName = weaponItem.name + end + TriggerServerEvent("qb-log:server:CreateLog", "death", Lang:t('logs.death_log_title', {playername = GetPlayerName(-1), playerid = GetPlayerServerId(player)}), "red", Lang:t('logs.death_log_message', {killername = killerName, playername = GetPlayerName(player), weaponlabel = weaponLabel, weaponname = weaponName})) + deathTime = 0 + OnDeath() + DeathTimer() + end + Wait(1000) + end + end) + else + TaskPlayAnim(ped, lastStandDict, "exit", 1.0, 8.0, -1, 1, -1, false, false, false) + InLaststand = false + LaststandTime = 0 + end + TriggerServerEvent("hospital:server:SetLaststandStatus", bool) +end + +-- Events + +RegisterNetEvent('hospital:client:SetEscortingState', function(bool) + isEscorting = bool +end) + +RegisterNetEvent('hospital:client:isEscorted', function(bool) + isEscorted = bool +end) + +RegisterNetEvent('hospital:client:UseFirstAid', function() + if not isEscorting then + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 1.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent('hospital:server:UseFirstAid', playerId) + end + else + QBCore.Functions.Notify(Lang:t('error.impossible'), 'error') + end +end) + +RegisterNetEvent('hospital:client:CanHelp', function(helperId) + if InLaststand then + if LaststandTime <= 300 then + TriggerServerEvent('hospital:server:CanHelp', helperId, true) + else + TriggerServerEvent('hospital:server:CanHelp', helperId, false) + end + else + TriggerServerEvent('hospital:server:CanHelp', helperId, false) + end +end) + +RegisterNetEvent('hospital:client:HelpPerson', function(targetId) + local ped = PlayerPedId() + isHealingPerson = true + QBCore.Functions.Progressbar("hospital_revive", Lang:t('progress.revive'), math.random(30000, 60000), false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = healAnimDict, + anim = healAnim, + flags = 1, + }, {}, {}, function() -- Done + isHealingPerson = false + ClearPedTasks(ped) + QBCore.Functions.Notify(Lang:t('success.revived'), 'success') + TriggerServerEvent("hospital:server:RevivePlayer", targetId) + end, function() -- Cancel + isHealingPerson = false + ClearPedTasks(ped) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/main.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/main.lua new file mode 100644 index 0000000..3d873c9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/main.lua @@ -0,0 +1,1067 @@ +QBCore = exports['qb-core']:GetCoreObject() + +local getOutDict = 'switch@franklin@bed' +local getOutAnim = 'sleep_getup_rubeyes' +local canLeaveBed = true +local bedOccupying = nil +local bedObject = nil +local bedOccupyingData = nil +local closestBed = nil +local doctorCount = 0 +local CurrentDamageList = {} +local cam = nil +local playerArmor = nil +inBedDict = "anim@gangops@morgue@table@" +inBedAnim = "body_search" +isInHospitalBed = false +isBleeding = 0 +bleedTickTimer, advanceBleedTimer = 0, 0 +fadeOutTimer, blackoutTimer = 0, 0 +legCount = 0 +armcount = 0 +headCount = 0 +playerHealth = nil +isDead = false +isStatusChecking = false +statusChecks = {} +statusCheckTime = 0 +healAnimDict = "mini@cpr@char_a@cpr_str" +healAnim = "cpr_pumpchest" +injured = {} + + +BodyParts = { + ['HEAD'] = { label = Lang:t('body.head'), causeLimp = false, isDamaged = false, severity = 0 }, + ['NECK'] = { label = Lang:t('body.neck'), causeLimp = false, isDamaged = false, severity = 0 }, + ['SPINE'] = { label = Lang:t('body.spine'), causeLimp = true, isDamaged = false, severity = 0 }, + ['UPPER_BODY'] = { label = Lang:t('body.upper_body'), causeLimp = false, isDamaged = false, severity = 0 }, + ['LOWER_BODY'] = { label = Lang:t('body.lower_body'), causeLimp = true, isDamaged = false, severity = 0 }, + ['LARM'] = { label = Lang:t('body.left_arm'), causeLimp = false, isDamaged = false, severity = 0 }, + ['LHAND'] = { label = Lang:t('body.left_hand'), causeLimp = false, isDamaged = false, severity = 0 }, + ['LFINGER'] = { label = Lang:t('body.left_fingers'), causeLimp = false, isDamaged = false, severity = 0 }, + ['LLEG'] = { label = Lang:t('body.left_leg'), causeLimp = true, isDamaged = false, severity = 0 }, + ['LFOOT'] = { label = Lang:t('body.left_foot'), causeLimp = true, isDamaged = false, severity = 0 }, + ['RARM'] = { label = Lang:t('body.right_arm'), causeLimp = false, isDamaged = false, severity = 0 }, + ['RHAND'] = { label = Lang:t('body.right_hand'), causeLimp = false, isDamaged = false, severity = 0 }, + ['RFINGER'] = { label = Lang:t('body.right_fingers'), causeLimp = false, isDamaged = false, severity = 0 }, + ['RLEG'] = { label = Lang:t('body.right_leg'), causeLimp = true, isDamaged = false, severity = 0 }, + ['RFOOT'] = { label = Lang:t('body.right_foot'), causeLimp = true, isDamaged = false, severity = 0 }, +} + +-- Functions + +local function GetAvailableBed(bedId) + local pos = GetEntityCoords(PlayerPedId()) + local retval = nil + if bedId == nil then + for k, _ in pairs(Config.Locations["beds"]) do + if not Config.Locations["beds"][k].taken then + if #(pos - vector3(Config.Locations["beds"][k].coords.x, Config.Locations["beds"][k].coords.y, Config.Locations["beds"][k].coords.z)) < 500 then + retval = k + end + end + end + else + if not Config.Locations["beds"][bedId].taken then + if #(pos - vector3(Config.Locations["beds"][bedId].coords.x, Config.Locations["beds"][bedId].coords.y, Config.Locations["beds"][bedId].coords.z)) < 500 then + retval = bedId + end + end + end + return retval +end + +local function GetDamagingWeapon(ped) + for k, v in pairs(Config.Weapons) do + if HasPedBeenDamagedByWeapon(ped, k, 0) then + return v + end + end + + return nil +end + +local function IsDamagingEvent(damageDone, weapon) + local luck = math.random(100) + local multi = damageDone / Config.HealthDamage + + return luck < (Config.HealthDamage * multi) or (damageDone >= Config.ForceInjury or multi > Config.MaxInjuryChanceMulti or Config.ForceInjuryWeapons[weapon]) +end + +local function DoLimbAlert() + if not isDead and not InLaststand then + if #injured > 0 then + local limbDamageMsg = '' + if #injured <= Config.AlertShowInfo then + for k, v in pairs(injured) do + limbDamageMsg = limbDamageMsg..Lang:t('info.pain_message', {limb = v.label, severity = Config.WoundStates[v.severity]}) + if k < #injured then + limbDamageMsg = limbDamageMsg .. " | " + end + end + else + limbDamageMsg = Lang:t('info.many_places') + end + QBCore.Functions.Notify(limbDamageMsg, "primary") + end + end +end + +local function DoBleedAlert() + if not isDead and tonumber(isBleeding) > 0 then + QBCore.Functions.Notify(Lang:t('info.bleed_alert', {bleedstate = Config.BleedingStates[tonumber(isBleeding)].label}), "error") + end +end + +local function ApplyBleed(level) + if isBleeding ~= 4 then + if isBleeding + level > 4 then + isBleeding = 4 + else + isBleeding = isBleeding + level + end + DoBleedAlert() + end +end + +local function SetClosestBed() + local pos = GetEntityCoords(PlayerPedId(), true) + local current = nil + local dist = nil + for k, _ in pairs(Config.Locations["beds"]) do + local dist2 = #(pos - vector3(Config.Locations["beds"][k].coords.x, Config.Locations["beds"][k].coords.y, Config.Locations["beds"][k].coords.z)) + if current then + if dist2 < dist then + current = k + dist = dist2 + end + else + dist = dist2 + current = k + end + end + if current ~= closestBed and not isInHospitalBed then + closestBed = current + end +end + +local function IsInjuryCausingLimp() + for _, v in pairs(BodyParts) do + if v.causeLimp and v.isDamaged then + return true + end + end + return false +end + +local function ProcessRunStuff(ped) + if IsInjuryCausingLimp() then + RequestAnimSet("move_m@injured") + while not HasAnimSetLoaded("move_m@injured") do + Wait(0) + end + SetPedMovementClipset(ped, "move_m@injured", 1 ) + SetPlayerSprint(PlayerId(), false) + end +end + +function ResetPartial() + for _, v in pairs(BodyParts) do + if v.isDamaged and v.severity <= 2 then + v.isDamaged = false + v.severity = 0 + end + end + + for k, v in pairs(injured) do + if v.severity <= 2 then + v.severity = 0 + table.remove(injured, k) + end + end + + if isBleeding <= 2 then + isBleeding = 0 + bleedTickTimer = 0 + advanceBleedTimer = 0 + fadeOutTimer = 0 + blackoutTimer = 0 + end + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) + + ProcessRunStuff(PlayerPedId()) + DoLimbAlert() + DoBleedAlert() + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) +end + +function ResetAll() + isBleeding = 0 + bleedTickTimer = 0 + advanceBleedTimer = 0 + fadeOutTimer = 0 + blackoutTimer = 0 + onDrugs = 0 + wasOnDrugs = false + onPainKiller = 0 + wasOnPainKillers = false + injured = {} + + for _, v in pairs(BodyParts) do + v.isDamaged = false + v.severity = 0 + end + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) + + CurrentDamageList = {} + TriggerServerEvent('hospital:server:SetWeaponDamage', CurrentDamageList) + + ProcessRunStuff(PlayerPedId()) + DoLimbAlert() + DoBleedAlert() + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) + TriggerServerEvent("hospital:server:resetHungerThirst") +end exports('ResetAll', ResetAll) + +local function loadAnimDict(dict) + while(not HasAnimDictLoaded(dict)) do + RequestAnimDict(dict) + Wait(1) + end +end + +local function SetBedCam() + isInHospitalBed = true + canLeaveBed = false + local player = PlayerPedId() + + DoScreenFadeOut(1000) + + while not IsScreenFadedOut() do + Wait(100) + end + + if IsPedDeadOrDying(player) then + local pos = GetEntityCoords(player, true) + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z, GetEntityHeading(player), true, false) + end + + bedObject = GetClosestObjectOfType(bedOccupyingData.coords.x, bedOccupyingData.coords.y, bedOccupyingData.coords.z, 1.0, bedOccupyingData.model, false, false, false) + FreezeEntityPosition(bedObject, true) + + SetEntityCoords(player, bedOccupyingData.coords.x, bedOccupyingData.coords.y, bedOccupyingData.coords.z + 0.02) + --SetEntityInvincible(PlayerPedId(), true) + Wait(500) + FreezeEntityPosition(player, true) + + loadAnimDict(inBedDict) + + TaskPlayAnim(player, inBedDict , inBedAnim, 8.0, 1.0, -1, 1, 0, 0, 0, 0 ) + SetEntityHeading(player, bedOccupyingData.coords.w) + + cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", 1) + SetCamActive(cam, true) + RenderScriptCams(true, false, 1, true, true) + AttachCamToPedBone(cam, player, 31085, 0, 1.0, 1.0 , true) + SetCamFov(cam, 90.0) + local heading = GetEntityHeading(player) + heading = (heading > 180) and heading - 180 or heading + 180 + SetCamRot(cam, -45.0, 0.0, heading, 2) + + DoScreenFadeIn(1000) + + Wait(1000) + FreezeEntityPosition(player, true) +end + +local function LeaveBed() + local player = PlayerPedId() + + RequestAnimDict(getOutDict) + while not HasAnimDictLoaded(getOutDict) do + Wait(0) + end + + FreezeEntityPosition(player, false) + SetEntityInvincible(player, false) + SetEntityHeading(player, bedOccupyingData.coords.w + 90) + TaskPlayAnim(player, getOutDict , getOutAnim, 100.0, 1.0, -1, 8, -1, 0, 0, 0) + Wait(4000) + ClearPedTasks(player) + TriggerServerEvent('hospital:server:LeaveBed', bedOccupying) + FreezeEntityPosition(bedObject, true) + RenderScriptCams(0, true, 200, true, true) + DestroyCam(cam, false) + + bedOccupying = nil + bedObject = nil + bedOccupyingData = nil + isInHospitalBed = false + + QBCore.Functions.GetPlayerData(function(PlayerData) + if PlayerData.metadata["injail"] > 0 then + TriggerEvent("prison:client:Enter", PlayerData.metadata["injail"]) + end + end) +end + +local function IsInDamageList(damage) + local retval = false + if CurrentDamageList then + for k, _ in pairs(CurrentDamageList) do + if CurrentDamageList[k] == damage then + retval = true + end + end + end + return retval +end + +local function CheckWeaponDamage(ped) + local detected = false + for k, v in pairs(QBCore.Shared.Weapons) do + if HasPedBeenDamagedByWeapon(ped, k, 0) then + detected = true + if not IsInDamageList(k) then + -- TriggerEvent('chat:addMessage', { + -- color = { 255, 0, 0}, + -- multiline = false, + --args = {Lang:t('info.status'), v.damagereason} + --}) + CurrentDamageList[#CurrentDamageList+1] = k + end + end + end + if detected then + TriggerServerEvent("hospital:server:SetWeaponDamage", CurrentDamageList) + end + ClearEntityLastDamageEntity(ped) +end + +local function ApplyImmediateEffects(ped, bone, weapon, damageDone) + local armor = GetPedArmour(ped) + if Config.MinorInjurWeapons[weapon] and damageDone < Config.DamageMinorToMajor then + if Config.CriticalAreas[Config.Bones[bone]] then + if armor <= 0 then + ApplyBleed(1) + end + end + + if Config.StaggerAreas[Config.Bones[bone]] and (Config.StaggerAreas[Config.Bones[bone]].armored or armor <= 0) then + if math.random(100) <= math.ceil(Config.StaggerAreas[Config.Bones[bone]].minor) then + SetPedToRagdoll(ped, 1500, 2000, 3, true, true, false) + end + end + elseif Config.MajorInjurWeapons[weapon] or (Config.MinorInjurWeapons[weapon] and damageDone >= Config.DamageMinorToMajor) then + if Config.CriticalAreas[Config.Bones[bone]] then + if armor > 0 and Config.CriticalAreas[Config.Bones[bone]].armored then + if math.random(100) <= math.ceil(Config.MajorArmoredBleedChance) then + ApplyBleed(1) + end + else + ApplyBleed(1) + end + else + if armor > 0 then + if math.random(100) < (Config.MajorArmoredBleedChance) then + ApplyBleed(1) + end + else + if math.random(100) < (Config.MajorArmoredBleedChance * 2) then + ApplyBleed(1) + end + end + end + + if Config.StaggerAreas[Config.Bones[bone]] and (Config.StaggerAreas[Config.Bones[bone]].armored or armor <= 0) then + if math.random(100) <= math.ceil(Config.StaggerAreas[Config.Bones[bone]].major) then + SetPedToRagdoll(ped, 1500, 2000, 3, true, true, false) + end + end + end +end + +local function CheckDamage(ped, bone, weapon, damageDone) + if weapon == nil then return end + + if Config.Bones[bone] and not isDead and not InLaststand then + ApplyImmediateEffects(ped, bone, weapon, damageDone) + + if not BodyParts[Config.Bones[bone]].isDamaged then + BodyParts[Config.Bones[bone]].isDamaged = true + BodyParts[Config.Bones[bone]].severity = math.random(1, 3) + injured[#injured+1] = { + part = Config.Bones[bone], + label = BodyParts[Config.Bones[bone]].label, + severity = BodyParts[Config.Bones[bone]].severity + } + else + if BodyParts[Config.Bones[bone]].severity < 4 then + BodyParts[Config.Bones[bone]].severity = BodyParts[Config.Bones[bone]].severity + 1 + + for _, v in pairs(injured) do + if v.part == Config.Bones[bone] then + v.severity = BodyParts[Config.Bones[bone]].severity + end + end + end + end + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) + + ProcessRunStuff(ped) + end +end + +local function ProcessDamage(ped) + if not isDead and not InLaststand and not onPainKillers then + for _, v in pairs(injured) do + if (v.part == 'LLEG' and v.severity > 1) or (v.part == 'RLEG' and v.severity > 1) or (v.part == 'LFOOT' and v.severity > 2) or (v.part == 'RFOOT' and v.severity > 2) then + if legCount >= Config.LegInjuryTimer then + if not IsPedRagdoll(ped) and IsPedOnFoot(ped) then + local chance = math.random(100) + if (IsPedRunning(ped) or IsPedSprinting(ped)) then + if chance <= Config.LegInjuryChance.Running then + ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', 0.08) -- change this float to increase/decrease camera shake + SetPedToRagdollWithFall(ped, 1500, 2000, 1, GetEntityForwardVector(ped), 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + end + else + if chance <= Config.LegInjuryChance.Walking then + ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', 0.08) -- change this float to increase/decrease camera shake + SetPedToRagdollWithFall(ped, 1500, 2000, 1, GetEntityForwardVector(ped), 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + end + end + end + legCount = 0 + else + legCount = legCount + 1 + end + elseif (v.part == 'LARM' and v.severity > 1) or (v.part == 'LHAND' and v.severity > 1) or (v.part == 'LFINGER' and v.severity > 2) or (v.part == 'RARM' and v.severity > 1) or (v.part == 'RHAND' and v.severity > 1) or (v.part == 'RFINGER' and v.severity > 2) then + if armcount >= Config.ArmInjuryTimer then + if (v.part == 'LARM' and v.severity > 1) or (v.part == 'LHAND' and v.severity > 1) or (v.part == 'LFINGER' and v.severity > 2) then + local isDisabled = 15 + CreateThread(function() + while isDisabled > 0 do + if IsPedInAnyVehicle(ped, true) then + DisableControlAction(0, 63, true) -- veh turn left + end + + if IsPlayerFreeAiming(PlayerId()) then + DisablePlayerFiring(PlayerId(), true) -- Disable weapon firing + end + + isDisabled = isDisabled - 1 + Wait(1) + end + end) + else + local isDisabled = 15 + CreateThread(function() + while isDisabled > 0 do + if IsPedInAnyVehicle(ped, true) then + DisableControlAction(0, 63, true) -- veh turn left + end + + if IsPlayerFreeAiming(PlayerId()) then + DisableControlAction(0, 25, true) -- Disable weapon firing + end + + isDisabled = isDisabled - 1 + Wait(1) + end + end) + end + + armcount = 0 + else + armcount = armcount + 1 + end + elseif (v.part == 'HEAD' and v.severity > 2) then + if headCount >= Config.HeadInjuryTimer then + local chance = math.random(100) + + if chance <= Config.HeadInjuryChance then + SetFlash(0, 0, 100, 10000, 100) + + DoScreenFadeOut(100) + while not IsScreenFadedOut() do + Wait(0) + end + + if not IsPedRagdoll(ped) and IsPedOnFoot(ped) and not IsPedSwimming(ped) then + ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', 0.08) -- change this float to increase/decrease camera shake + SetPedToRagdoll(ped, 5000, 1, 2) + end + + Wait(5000) + DoScreenFadeIn(250) + end + headCount = 0 + else + headCount = headCount + 1 + end + end + end + end +end + +--Ranjit's emsbag functions + +-- Notifys +function Notify(msg) + QBCore.Functions.Notify(msg) +end + +-- Progressbars +function progressBar(msg) + QBCore.Functions.Progressbar("ems bag", msg, 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function()end) +end + +-- Events + +RegisterNetEvent('hospital:client:ambulanceAlert', function(coords, text) + local street1, street2 = GetStreetNameAtCoord(coords.x, coords.y, coords.z) + local street1name = GetStreetNameFromHashKey(street1) + local street2name = GetStreetNameFromHashKey(street2) + QBCore.Functions.Notify({text = text, caption = street1name.. ' ' ..street2name}, 'ambulance') + PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1) + local transG = 250 + local blip = AddBlipForCoord(coords.x, coords.y, coords.z) + local blip2 = AddBlipForCoord(coords.x, coords.y, coords.z) + local blipText = Lang:t('info.ems_alert', {text = text}) + SetBlipSprite(blip, 153) + SetBlipSprite(blip2, 161) + SetBlipColour(blip, 1) + SetBlipColour(blip2, 1) + SetBlipDisplay(blip, 4) + SetBlipDisplay(blip2, 8) + SetBlipAlpha(blip, transG) + SetBlipAlpha(blip2, transG) + SetBlipScale(blip, 0.8) + SetBlipScale(blip2, 2.0) + SetBlipAsShortRange(blip, false) + SetBlipAsShortRange(blip2, false) + PulseBlip(blip2) + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(blipText) + EndTextCommandSetBlipName(blip) + while transG ~= 0 do + Wait(180 * 4) + transG = transG - 1 + SetBlipAlpha(blip, transG) + SetBlipAlpha(blip2, transG) + if transG == 0 then + RemoveBlip(blip) + return + end + end +end) + +RegisterNetEvent('hospital:client:Revive', function() + local player = PlayerPedId() + + if isDead or InLaststand then + local pos = GetEntityCoords(player, true) + NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z, GetEntityHeading(player), true, false) + isDead = false + SetEntityInvincible(player, false) + SetLaststand(false) + end + + if isInHospitalBed then + loadAnimDict(inBedDict) + TaskPlayAnim(player, inBedDict , inBedAnim, 8.0, 1.0, -1, 1, 0, 0, 0, 0 ) + SetEntityInvincible(player, true) + canLeaveBed = true + end + + TriggerServerEvent("hospital:server:RestoreWeaponDamage") + SetEntityMaxHealth(player, 200) + SetEntityHealth(player, 200) + ClearPedBloodDamage(player) + SetPlayerSprint(PlayerId(), true) + ResetAll() + ResetPedMovementClipset(player, 0.0) + TriggerServerEvent('hud:server:RelieveStress', 100) + TriggerServerEvent("hospital:server:SetDeathStatus", false) + TriggerServerEvent("hospital:server:SetLaststandStatus", false) + emsNotified = false + QBCore.Functions.Notify(Lang:t('info.healthy')) +end) + +RegisterNetEvent('hospital:client:SetPain', function() + ApplyBleed(math.random(1,4)) + if not BodyParts[Config.Bones[24816]].isDamaged then + BodyParts[Config.Bones[24816]].isDamaged = true + BodyParts[Config.Bones[24816]].severity = math.random(1, 4) + injured[#injured+1] = { + part = Config.Bones[24816], + label = BodyParts[Config.Bones[24816]].label, + severity = BodyParts[Config.Bones[24816]].severity + } + end + + if not BodyParts[Config.Bones[40269]].isDamaged then + BodyParts[Config.Bones[40269]].isDamaged = true + BodyParts[Config.Bones[40269]].severity = math.random(1, 4) + injured[#injured+1] = { + part = Config.Bones[40269], + label = BodyParts[Config.Bones[40269]].label, + severity = BodyParts[Config.Bones[40269]].severity + } + end + + TriggerServerEvent('hospital:server:SyncInjuries', { + limbs = BodyParts, + isBleeding = tonumber(isBleeding) + }) +end) + +RegisterNetEvent('hospital:client:KillPlayer', function() + SetEntityHealth(PlayerPedId(), 0) +end) + +RegisterNetEvent('hospital:client:HealInjuries', function(type) + if type == "full" then + ResetAll() + else + ResetPartial() + end + TriggerServerEvent("hospital:server:RestoreWeaponDamage") + QBCore.Functions.Notify(Lang:t('success.wounds_healed'), 'success') +end) + +RegisterNetEvent('hospital:client:SendToBed', function(id, data, isRevive) + bedOccupying = id + bedOccupyingData = data + SetBedCam() + CreateThread(function () + Wait(5) + if isRevive then + QBCore.Functions.Notify(Lang:t('success.being_helped'), 'success') + Wait(Config.AIHealTimer * 1000) + TriggerEvent("hospital:client:Revive") + else + canLeaveBed = true + end + end) +end) + +RegisterNetEvent('hospital:client:SetBed', function(id, isTaken) + Config.Locations["beds"][id].taken = isTaken +end) + +RegisterNetEvent('hospital:client:SetBed2', function(id, isTaken) + Config.Locations["jailbeds"][id].taken = isTaken +end) + +RegisterNetEvent('hospital:client:RespawnAtHospital', function() + TriggerServerEvent("hospital:server:RespawnAtHospital") + if exports["qb-policejob"]:IsHandcuffed() then + TriggerEvent("police:client:GetCuffed", -1) + end + TriggerEvent("police:client:DeEscort") +end) + +RegisterNetEvent('hospital:client:SendBillEmail', function(amount) + SetTimeout(math.random(2500, 4000), function() + local gender = Lang:t('info.mr') + if QBCore.Functions.GetPlayerData().charinfo.gender == 1 then + gender = Lang:t('info.mrs') + end + local charinfo = QBCore.Functions.GetPlayerData().charinfo + TriggerServerEvent('qb-phone:server:sendNewMail', { + sender = Lang:t('mail.sender'), + subject = Lang:t('mail.subject'), + message = Lang:t('mail.message', {gender = gender, lastname = charinfo.lastname, costs = amount}), + button = {} + }) + end) +end) + +RegisterNetEvent('hospital:client:SetDoctorCount', function(amount) + doctorCount = amount +end) + +RegisterNetEvent('hospital:client:adminHeal', function() + local ped = PlayerPedId() + SetEntityHealth(ped, 200) + TriggerServerEvent("hospital:server:resetHungerThirst") +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + local ped = PlayerPedId() + TriggerServerEvent("hospital:server:SetDeathStatus", false) + TriggerServerEvent('hospital:server:SetLaststandStatus', false) + TriggerServerEvent("hospital:server:SetArmor", GetPedArmour(ped)) + if bedOccupying then + TriggerServerEvent("hospital:server:LeaveBed", bedOccupying) + end + isDead = false + deathTime = 0 + SetEntityInvincible(ped, false) + SetPedArmour(ped, 0) + ResetAll() +end) + +--Ranjit's emsbag events +-- Simple Event's , you can create yours and put on qb-menu :) + +RegisterNetEvent('Ranjit-EmsBag:Client:GiveRadio') +AddEventHandler("Ranjit-EmsBag:Client:GiveRadio", function() + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager radio...") + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem", "radio", 1) + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["radio"], "add", 1) +end) + +RegisterNetEvent('Ranjit-EmsBag:Client:Givebandage') +AddEventHandler("Ranjit-EmsBag:Client:Givebandage", function() + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager Bandage...") + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem", "bandage", 1) + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["bandage"], "add", 1) +end) +RegisterNetEvent('Ranjit-EmsBag:Client:Givepainkillers') +AddEventHandler("Ranjit-EmsBag:Client:Givepainkillers", function() + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager smertestillende...") + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem", "painkillers", 1) + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["painkillers"], "add", 1) +end) +RegisterNetEvent('Ranjit-EmsBag:Client:Givefirstaid') +AddEventHandler("Ranjit-EmsBag:Client:Givefirstaid", function() + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager førstehjælpskasse...") + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem", "firstaid", 1) + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["firstaid"], "add", 1) +end) +RegisterNetEvent('Ranjit-EmsBag:Client:Giveweapon_flashlight') +AddEventHandler("Ranjit-EmsBag:Client:Giveweapon_flashlight", function() + local playerPed = PlayerPedId() + TaskStartScenarioInPlace(playerPed, "CODE_HUMAN_MEDIC_TEND_TO_DEAD") + progressBar("Tager lommelygte...") + TriggerServerEvent("Ranjit-EmsBag:Server:AddItem", "weapon_flashlight", 1) + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["weapon_flashlight"], "add", 1) +end) + + +RegisterNetEvent('Ranjit-EmsBag:Client:MenuAmbulanceBag', function() + local playerPed = PlayerPedId() + if IsEntityDead(playerPed) then return Notify("Du kan ikke åbne tasken når du er død", "error") end + if IsPedSwimming(playerPed) then return Notify("Du kan ikke åbne tasken i vand.", "error") end + if IsPedSittingInAnyVehicle(playerPed) then return Notify("Du kan ikke åbne tasken i et køretøj", "error") end + exports['qb-menu']:openMenu({ + { header = "[🚑] Ambulance Kasse", txt = "", isMenuHeader = true }, + { header = "[👜] Åben Ambulance taske", params = { event = "Ranjit-EmsBag:Client:StorageAmbulanceBag" } }, + { header = "[🩹] Tag Bandage ", params = { event = "Ranjit-EmsBag:Client:Givebandage" } }, + { header = "[💊] Tag Smertestillende ", params = { event = "Ranjit-EmsBag:Client:Givepainkillers" } }, + { header = "[💉] Tag Førstehjælpskasse ", params = { event = "Ranjit-EmsBag:Client:Givefirstaid" } }, + { header = "[🔦] Tag Lommelygte ", params = { event = "Ranjit-EmsBag:Client:Giveweapon_flashlight" } }, + { header = "[📻] Tag Radio", params = { event = "Ranjit-EmsBag:Client:GiveRadio" } }, + -- You can add more menus with your's personal events... + { header = "", txt = "❌ Luk", params = { event = "qb-menu:closeMenu" } }, + }) +end) + +-- Threads + +CreateThread(function() + for _, station in pairs(Config.Locations["stations"]) do + local blip = AddBlipForCoord(station.coords.x, station.coords.y, station.coords.z) + SetBlipSprite(blip, 61) + SetBlipAsShortRange(blip, true) + SetBlipScale(blip, 0.8) + SetBlipColour(blip, 25) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(station.label) + EndTextCommandSetBlipName(blip) + end +end) + +CreateThread(function() + while true do + local sleep = 1000 + if isInHospitalBed and canLeaveBed then + sleep = 0 + exports['qb-core']:DrawText(Lang:t('text.bed_out'), 'top') + if IsControlJustReleased(0, 38) then + exports['qb-core']:KeyPressed(38) + LeaveBed() + exports['qb-core']:HideText() + end + end + Wait(sleep) + end +end) + +CreateThread(function() + while true do + Wait((1000 * Config.MessageTimer)) + DoLimbAlert() + end +end) + +CreateThread(function() + while true do + Wait(1000) + SetClosestBed() + if isStatusChecking then + statusCheckTime = statusCheckTime - 1 + if statusCheckTime <= 0 then + statusChecks = {} + isStatusChecking = false + end + end + end +end) + +CreateThread(function() + while true do + local ped = PlayerPedId() + local health = GetEntityHealth(ped) + local armor = GetPedArmour(ped) + + if not playerHealth then + playerHealth = health + end + + if not playerArmor then + playerArmor = armor + end + + local armorDamaged = (playerArmor ~= armor and armor < (playerArmor - Config.ArmorDamage) and armor > 0) -- Players armor was damaged + local healthDamaged = (playerHealth ~= health) -- Players health was damaged + + local damageDone = (playerHealth - health) + + if armorDamaged or healthDamaged then + local hit, bone = GetPedLastDamageBone(ped) + local bodypart = Config.Bones[bone] + local weapon = GetDamagingWeapon(ped) + + if hit and bodypart ~= 'NONE' then + local checkDamage = true + if damageDone >= Config.HealthDamage then + if weapon then + if armorDamaged and (bodypart == 'SPINE' or bodypart == 'UPPER_BODY') or weapon == Config.WeaponClasses['NOTHING'] then + checkDamage = false -- Don't check damage if the it was a body shot and the weapon class isn't that strong + if armorDamaged then + TriggerServerEvent("hospital:server:SetArmor", GetPedArmour(ped)) + end + end + + if checkDamage then + if IsDamagingEvent(damageDone, weapon) then + CheckDamage(ped, bone, weapon, damageDone) + end + end + end + elseif Config.AlwaysBleedChanceWeapons[weapon] then + if armorDamaged and (bodypart == 'SPINE' or bodypart == 'UPPER_BODY') or weapon == Config.WeaponClasses['NOTHING'] then + checkDamage = false -- Don't check damage if the it was a body shot and the weapon class isn't that strong + end + if math.random(100) < Config.AlwaysBleedChance and checkDamage then + ApplyBleed(1) + end + end + end + + CheckWeaponDamage(ped) + end + + playerHealth = health + playerArmor = armor + + if not isInHospitalBed then + ProcessDamage(ped) + end + Wait(100) + end +end) + +local listen = false + local function CheckInControls(variable) + CreateThread(function() + listen = true + while listen do + if IsControlJustPressed(0, 38) then + exports['qb-core']:KeyPressed(38) + if variable == "checkin" then + TriggerEvent('qb-ambulancejob:checkin') + listen = false + elseif variable == "beds" then + TriggerEvent('qb-ambulancejob:beds') + listen = false + end + end + Wait(1) + end + end) +end + +RegisterNetEvent('qb-ambulancejob:checkin', function() + if doctorCount >= Config.MinimalDoctors then + TriggerServerEvent("hospital:server:SendDoctorAlert") + else + TriggerEvent('animations:client:EmoteCommandStart', {"notepad"}) + QBCore.Functions.Progressbar("hospital_checkin", Lang:t('progress.checking_in'), 2000, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerEvent('animations:client:EmoteCommandStart', {"c"}) + local bedId = GetAvailableBed() + if bedId then + TriggerServerEvent("hospital:server:SendToBed", bedId, true) + else + QBCore.Functions.Notify(Lang:t('error.beds_taken'), "error") + end + end, function() -- Cancel + TriggerEvent('animations:client:EmoteCommandStart', {"c"}) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) + end +end) + +RegisterNetEvent('qb-ambulancejob:beds', function() + if GetAvailableBed(closestBed) then + TriggerServerEvent("hospital:server:SendToBed", closestBed, false) + else + QBCore.Functions.Notify(Lang:t('error.beds_taken'), "error") + end +end) + +-- Convar turns into a boolean +if Config.UseTarget then + CreateThread(function() + for k, v in pairs(Config.Locations["checking"]) do + + QBCore.Functions.LoadModel(Config.CheckingPed) + while not HasModelLoaded(Config.CheckingPed) do + Wait(100) + end + CheckingPed = CreatePed(0, Config.CheckingPed, v.x, v.y, v.z-1.0, v.w, false, true) + TaskStartScenarioInPlace(CheckingPed, true) + FreezeEntityPosition(CheckingPed, true) + SetEntityInvincible(CheckingPed, true) + SetBlockingOfNonTemporaryEvents(CheckingPed, true) + TaskStartScenarioInPlace(CheckingPed, Config.CheckingPedScenario, 0, true) + + exports['qb-target']:AddBoxZone("checking"..k, vector3(v.x, v.y, v.z), 3.5, 2, { + name = "checking"..k, + heading = -72, + debugPoly = false, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + icon = "fa fa-clipboard", + event = "qb-ambulancejob:checkin", + label = "Check ind", + } + }, + distance = 1.5 + }) + end + + for k, v in pairs(Config.Locations["beds"]) do + exports['qb-target']:AddBoxZone("beds"..k, v.coords, 2.5, 2.3, { + name = "beds"..k, + heading = -20, + debugPoly = false, + minZ = v.coords.z - 1, + maxZ = v.coords.z + 1, + }, { + options = { + { + type = "client", + event = "qb-ambulancejob:beds", + icon = "fas fa-bed", + label = "Læg i seng", + } + }, + distance = 1.5 + }) + end + end) +else + CreateThread(function() + local checkingPoly = {} + for k, v in pairs(Config.Locations["checking"]) do + checkingPoly[#checkingPoly+1] = BoxZone:Create(vector3(v.x, v.y, v.z), 3.5, 2, { + heading = -72, + name="checkin"..k, + debugPoly = false, + minZ = v.z - 2, + maxZ = v.z + 2, + }) + local checkingCombo = ComboZone:Create(checkingPoly, {name = "checkingCombo", debugPoly = false}) + checkingCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + if doctorCount >= Config.MinimalDoctors then + exports['qb-core']:DrawText(Lang:t('text.call_doc'), 'top') + CheckInControls("checkin") + else + exports['qb-core']:DrawText(Lang:t('text.check_in'), 'top') + CheckInControls("checkin") + end + else + listen = false + exports['qb-core']:HideText() + end + end) + end + local bedPoly = {} + for k, v in pairs(Config.Locations["beds"]) do + bedPoly[#bedPoly+1] = BoxZone:Create(v.coords, 2.5, 2.3, { + name="beds"..k, + heading = -20, + debugPoly = false, + minZ = v.coords.z - 1, + maxZ = v.coords.z + 1, + }) + local bedCombo = ComboZone:Create(bedPoly, {name = "bedCombo", debugPoly = false}) + bedCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + exports['qb-core']:DrawText(Lang:t('text.lie_bed'), 'top') + CheckInControls("beds") + else + listen = false + exports['qb-core']:HideText() + end + end) + end + end) +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/wounding.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/wounding.lua new file mode 100644 index 0000000..092027a --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/client/wounding.lua @@ -0,0 +1,238 @@ +local prevPos = nil +onPainKillers = false +local painkillerAmount = 0 + +-- Functions + +local function DoBleedAlert() + if not isDead and tonumber(isBleeding) > 0 then + QBCore.Functions.Notify(Lang:t('info.bleed_alert', {bleedstate = Config.BleedingStates[tonumber(isBleeding)].label}), "error", 5000) + end +end + +local function RemoveBleed(level) + if isBleeding ~= 0 then + if isBleeding - level < 0 then + isBleeding = 0 + else + isBleeding = isBleeding - level + end + DoBleedAlert() + end +end + +local function ApplyBleed(level) + if isBleeding ~= 4 then + if isBleeding + level > 4 then + isBleeding = 4 + else + isBleeding = isBleeding + level + end + DoBleedAlert() + end +end + +-- Events + +RegisterNetEvent('hospital:client:UseIfaks', function() + local ped = PlayerPedId() + QBCore.Functions.Progressbar("use_bandage", Lang:t('progress.ifaks'), 3000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = "mp_suicide", + anim = "pill", + flags = 49, + }, {}, {}, function() -- Done + StopAnimTask(ped, "mp_suicide", "pill", 1.0) + TriggerServerEvent("hospital:server:removeIfaks") + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["ifaks"], "remove") + TriggerServerEvent('hud:server:RelieveStress', math.random(12, 24)) + SetEntityHealth(ped, GetEntityHealth(ped) + 10) + if painkillerAmount < 3 then + painkillerAmount = painkillerAmount + 1 + end + PainKillerLoop() + if math.random(1, 100) < 50 then + RemoveBleed(1) + end + end, function() -- Cancel + StopAnimTask(ped, "mp_suicide", "pill", 1.0) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) +end) + +RegisterNetEvent('hospital:client:UseBandage', function() + local ped = PlayerPedId() + QBCore.Functions.Progressbar("use_bandage", Lang:t('progress.bandage'), 4000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@amb@business@weed@weed_inspecting_high_dry@", + anim = "weed_inspecting_high_base_inspector", + flags = 49, + }, {}, {}, function() -- Done + StopAnimTask(ped, "anim@amb@business@weed@weed_inspecting_high_dry@", "weed_inspecting_high_base_inspector", 1.0) + TriggerServerEvent("hospital:server:removeBandage") + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["bandage"], "remove") + SetEntityHealth(ped, GetEntityHealth(ped) + 10) + if math.random(1, 100) < 50 then + RemoveBleed(1) + end + if math.random(1, 100) < 7 then + ResetPartial() + end + end, function() -- Cancel + StopAnimTask(ped, "anim@amb@business@weed@weed_inspecting_high_dry@", "weed_inspecting_high_base_inspector", 1.0) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) +end) + +RegisterNetEvent('hospital:client:UsePainkillers', function() + local ped = PlayerPedId() + QBCore.Functions.Progressbar("use_bandage", Lang:t('progress.painkillers'), 3000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, { + animDict = "mp_suicide", + anim = "pill", + flags = 49, + }, {}, {}, function() -- Done + StopAnimTask(ped, "mp_suicide", "pill", 1.0) + TriggerServerEvent("hospital:server:removePainkillers") + TriggerEvent("inventory:client:ItemBox", QBCore.Shared.Items["painkillers"], "remove") + if painkillerAmount < 3 then + painkillerAmount = painkillerAmount + 1 + end + PainKillerLoop() + end, function() -- Cancel + StopAnimTask(ped, "mp_suicide", "pill", 1.0) + QBCore.Functions.Notify(Lang:t('error.canceled'), "error") + end) +end) + +-- Threads + +function PainKillerLoop(pkAmount) + if not onPainKillers then + if pkAmount then + painkillerAmount = pkAmount + end + onPainKillers = true + while onPainKillers do + Wait(1) + painkillerAmount = painkillerAmount - 1 + Wait(Config.PainkillerInterval * 1000) + if painkillerAmount <= 0 then + painkillerAmount = 0 + onPainKillers = false + end + end + end +end +exports('PainKillerLoop', PainKillerLoop) + +CreateThread(function() + while true do + if #injured > 0 then + local level = 0 + for _, v in pairs(injured) do + if v.severity > level then + level = v.severity + end + end + SetPedMoveRateOverride(PlayerPedId(), Config.MovementRate[level]) + Wait(5) + else + Wait(1000) + end + end +end) + +CreateThread(function() + Wait(2500) + prevPos = GetEntityCoords(PlayerPedId(), true) + while true do + Wait(1000) + if isBleeding > 0 and not onPainKillers then + local player = PlayerPedId() + if bleedTickTimer >= Config.BleedTickRate and not isInHospitalBed then + if not isDead and not InLaststand then + if isBleeding > 0 then + if fadeOutTimer + 1 == Config.FadeOutTimer then + if blackoutTimer + 1 == Config.BlackoutTimer then + SetFlash(0, 0, 100, 7000, 100) + + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(0) + end + + if not IsPedRagdoll(player) and IsPedOnFoot(player) and not IsPedSwimming(player) then + ShakeGameplayCam('SMALL_EXPLOSION_SHAKE', 0.08) -- change this float to increase/decrease camera shake + SetPedToRagdollWithFall(player, 7500, 9000, 1, GetEntityForwardVector(player), 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + end + + Wait(1500) + DoScreenFadeIn(1000) + blackoutTimer = 0 + else + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(0) + end + DoScreenFadeIn(500) + + if isBleeding > 3 then + blackoutTimer = blackoutTimer + 2 + else + blackoutTimer = blackoutTimer + 1 + end + end + + fadeOutTimer = 0 + else + fadeOutTimer = fadeOutTimer + 1 + end + + local bleedDamage = tonumber(isBleeding) * Config.BleedTickDamage + ApplyDamageToPed(player, bleedDamage, false) + DoBleedAlert() + playerHealth = playerHealth - bleedDamage + local randX = math.random() + math.random(-1, 1) + local randY = math.random() + math.random(-1, 1) + local coords = GetOffsetFromEntityInWorldCoords(player, randX, randY, 0) + TriggerServerEvent("evidence:server:CreateBloodDrop", QBCore.Functions.GetPlayerData().citizenid, QBCore.Functions.GetPlayerData().metadata["bloodtype"], coords) + + if advanceBleedTimer >= Config.AdvanceBleedTimer then + ApplyBleed(1) + advanceBleedTimer = 0 + else + advanceBleedTimer = advanceBleedTimer + 1 + end + end + end + bleedTickTimer = 0 + else + if math.floor(bleedTickTimer % (Config.BleedTickRate / 10)) == 0 then + local currPos = GetEntityCoords(player, true) + local moving = #(vector2(prevPos.x, prevPos.y) - vector2(currPos.x, currPos.y)) + if (moving > 1 and not IsPedInAnyVehicle(player)) and isBleeding > 2 then + advanceBleedTimer = advanceBleedTimer + Config.BleedMovementAdvance + bleedTickTimer = bleedTickTimer + Config.BleedMovementTick + prevPos = currPos + else + bleedTickTimer = bleedTickTimer + 1 + end + end + bleedTickTimer = bleedTickTimer + 1 + end + end + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/config.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/config.lua new file mode 100644 index 0000000..fd305a2 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/config.lua @@ -0,0 +1,599 @@ +Config = {} +Config.UseTarget = GetConvar('UseTarget', 'false') == 'true' -- Use qb-target interactions (don't change this, go to your server.cfg and add setr UseTarget true) +Config.Debug = false -- Enables DebugPoly +Config.MinimalDoctors = 2 -- How many players with the ambulance job to prevent the hospital check-in system from being used +Config.DocCooldown = 1 -- Cooldown between doctor calls allowed, in minutes +Config.WipeInventoryOnRespawn = true -- Enable or disable removing all the players items when they respawn at the hospital +Config.BillCost = 300 -- Price that players are charged for using the hospital check-in system +Config.DeathTime = 30 -- How long the timer is for players to bleed out completely and respawn at the hospital +Config.PainkillerInterval = 60 -- Set the length of time painkillers last (per one) +Config.HealthDamage = 5 -- Minumum damage done to health before checking for injuries +Config.ArmorDamage = 5 -- Minumum damage done to armor before checking for injuries +Config.ForceInjury = 35 -- Maximum amount of damage a player can take before limb damage & effects are forced to occur +Config.AlwaysBleedChance = 70 -- Set the chance out of 100 that if a player is hit with a weapon, that also has a random chance, it will cause bleeding +Config.MessageTimer = 12 -- How long it will take to display limb/bleed message +Config.AIHealTimer = 20 -- How long it will take to be healed after checking in, in seconds +Config.BleedTickRate = 30 -- How much time, in seconds, between bleed ticks +Config.BleedMovementTick = 10 -- How many seconds is taken away from the bleed tick rate if the player is walking, jogging, or sprinting +Config.BleedMovementAdvance = 3 -- How much time moving while bleeding adds +Config.BleedTickDamage = 8 -- The base damage that is multiplied by bleed level everytime a bleed tick occurs +Config.FadeOutTimer = 2 -- How many bleed ticks occur before fadeout happens +Config.BlackoutTimer = 10 -- How many bleed ticks occur before blacking out +Config.AdvanceBleedTimer = 10 -- How many bleed ticks occur before bleed level increases +Config.HeadInjuryTimer = 30 -- How much time, in seconds, do head injury effects chance occur +Config.ArmInjuryTimer = 30 -- How much time, in seconds, do arm injury effects chance occur +Config.LegInjuryTimer = 15 -- How much time, in seconds, do leg injury effects chance occur +Config.HeadInjuryChance = 25 -- The chance, in percent, that head injury side-effects get applied +Config.LegInjuryChance = { -- The chance, in percent, that leg injury side-effects get applied + Running = 50, + Walking = 15 +} +Config.ReviveInterval = 360 +Config.MinimumRevive = 30 +Config.MajorArmoredBleedChance = 45 -- The chance, in percent, that a player will get a bleed effect when taking heavy damage while wearing armor +Config.MaxInjuryChanceMulti = 3 -- How many times the HealthDamage value above can divide into damage taken before damage is forced to be applied +Config.DamageMinorToMajor = 35 -- How much damage would have to be applied for a minor weapon to be considered a major damage event. Put this at 100 if you want to disable it +Config.AlertShowInfo = 2 -- How many injuries a player must have before being alerted about them +Config.FuelScript = 'qb-fuel' -- Fuel script u use (defaut: qb-fuel) +--Ranjit-EMS-bag config +Config.Bag = { + Job = { + "ambulance", + "police", + "sast", + "sheriff", + "bcso", + } +} +Config.Stash = { + MaxWeighStash = 50000, + MaxSlotsStash = 50, +} + + +-- PEDS + --Duty +Config.DutyPedScenario = "PROP_HUMAN_SEAT_CHAIR_UPRIGHT" --https://gtaforums.com/topic/796181-list-of-scenarios-for-peds/ +Config.DutyPed = 's_m_m_doctor_01' --https://docs.fivem.net/docs/game-references/ped-models/ + --Armory +Config.ArmoryPedScenario = "WORLD_HUMAN_CLIPBOARD" +Config.ArmoryPed = "s_m_y_autopsy_01" + --Garage +Config.GaragePedScenario = "WORLD_HUMAN_AA_SMOKE" +Config.GaragePed = 'mp_m_waremech_01' + --Helicopter +Config.HeliPedScenario = "WORLD_HUMAN_COP_IDLES" +Config.HeliPed = 'ig_casey' + --Checking +Config.CheckingPedScenario = "WORLD_HUMAN_CLIPBOARD" +Config.CheckingPed = 's_m_m_paramedic_01' + + +Config.Locations = { -- Edit the various interaction points for players or create new ones + ["checking"] = { + [1] = vector4(312.18, -582.66, 43.27, 79.02), + [2] = vector4(-254.54, 6331.78, 32.43, 00.0), -- paleto + }, + ["duty"] = { + [1] = vector4(313.15, -580.3, 43.27, 59.02), + [2] = vector4(-254.88, 6324.5, 32.58, 00.00), + }, + ["vehicle"] = { --not 100% done, vehspawn loc + [1] = { + vehspawn = vector4(358.4109, -566.0589, 28.8474, 69.2315), + pedspawn = vector4(363.7343, -572.8968, 28.8474, 30.6025) + }, + }, + ["helicopter"] = { + [1] = { + vehspawn = vector4(0.0, 0.0, 0.0, 0.0 ), + pedspawn = vector4(0.0, 0.0, 0.0, 0.0 ), + } + }, + ["armory"] = { + [1] = vector4(314.73, -581.17, 43.27, 77.0), + [2] = vector4(-245.13, 6315.71, 32.82, 00.00), + }, + ["roof"] = { + [1] = vector4(338.5, -583.85, 74.16, 245.5), + }, + ["main"] = { + [1] = vector3(334, -591.74, 43.27), + [2] = vector3(335.2, -588.61, 43.27), + }, + ["basement"] = { + [1] = vector3(325.4, -583.96, 29.85), + [2] = vector3(324.5, -587.28, 29.84), + }, + ["stash"] = { + [1] = vector3(314.25, -582.45, 43.27), + }, + ["beds"] = { + [1] = {coords = vector4(321.33, -581.38, 44.12, 165.27), taken = false, model = -421052012}, + [2] = {coords = vector4(327.63, -583.7, 44.12, 163.62), taken = false, model = -421052012}, + [3] = {coords = vector4(330.77, -584.71, 44.12, 166.54), taken = false, model = -421052012}, + [4] = {coords = vector4(328.41, -588.92, 44.12, 352.49), taken = false, model = -421052012}, + [5] = {coords = vector4(325.54, -587.99, 44.12, 350.07), taken = false, model = -421052012}, + [6] = {coords = vector4(322.67, -586.78, 44.12, 342.31), taken = false, model = -421052012}, + [7] = {coords = vector4(316.82, -584.69, 44.12, 341.13), taken = false, model = -421052012}, + [8] = {coords = vector4(319.77, -585.66, 44.12, 339.93), taken = false, model = -421052012}, + --- paleto + [10] = {coords = vector4(-252.43, 6312.25, 32.34, 313.48), taken = false, model = 2117668672}, + [11] = {coords = vector4(-247.04, 6317.95, 32.34, 134.64), taken = false, model = 2117668672}, + [12] = {coords = vector4(-255.98, 6315.67, 32.34, 313.91), taken = false, model = 2117668672}, + }, + ["jailbeds"] = { + [1] = {coords = vector4(1761.96, 2597.74, 45.66, 270.14), taken = false, model = 2117668672}, + [2] = {coords = vector4(1761.96, 2591.51, 45.66, 269.8), taken = false, model = 2117668672}, + [3] = {coords = vector4(1771.8, 2598.02, 45.66, 89.05), taken = false, model = 2117668672}, + [4] = {coords = vector4(1771.85, 2591.85, 45.66, 91.51), taken = false, model = 2117668672}, + }, + ["stations"] = { + [1] = {label = 'Pillbox Hospital', coords = vector4(304.27, -600.33, 43.28, 272.249)} + } +} + +Config.Helicopters = { + ["Polmav"] = "polmav", +} + +Config.VehicleTable = { + ["ambulances"] = { + "f450ambo", + }, +} + +Config.CarItems = { + [1] = { + name = "heavyarmor", + amount = 2, + info = {}, + type = "item", + slot = 1, + }, + [2] = { + name = "emsbag", + amount = 2, + info = {}, + type = "item", + slot = 2, + }, + [3] = { + name = "weapon_fireextinguisher", + amount = 2, + info = {}, + type = "item", + slot = 3, + }, +} + +Config.Items = { -- Items found in the ambulance shop for players with the ambulance job to purchase + label = Lang:t('info.safe'), + slots = 30, + items = { + [1] = { + name = "radio", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 1, + }, + [2] = { + name = "bandage", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 2, + }, + [3] = { + name = "painkillers", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 3, + }, + [4] = { + name = "firstaid", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 4, + }, + [5] = { + name = "weapon_flashlight", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 5, + }, + [6] = { + name = "weapon_fireextinguisher", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 6, + }, + [7] = { + name = "mdt", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 7, + }, + [8] = { + name = "emsbag", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 8, + }, + } +} + +Config.WeaponClasses = { -- Define gta weapon classe numbers + ['SMALL_CALIBER'] = 1, + ['MEDIUM_CALIBER'] = 2, + ['HIGH_CALIBER'] = 3, + ['SHOTGUN'] = 4, + ['CUTTING'] = 5, + ['LIGHT_IMPACT'] = 6, + ['HEAVY_IMPACT'] = 7, + ['EXPLOSIVE'] = 8, + ['FIRE'] = 9, + ['SUFFOCATING'] = 10, + ['OTHER'] = 11, + ['WILDLIFE'] = 12, + ['NOTHING'] = 13 +} + +Config.MinorInjurWeapons = { -- Define which weapons cause small injuries + [Config.WeaponClasses['SMALL_CALIBER']] = true, + [Config.WeaponClasses['MEDIUM_CALIBER']] = true, + [Config.WeaponClasses['CUTTING']] = true, + [Config.WeaponClasses['WILDLIFE']] = true, + [Config.WeaponClasses['OTHER']] = true, + [Config.WeaponClasses['LIGHT_IMPACT']] = true, +} + +Config.MajorInjurWeapons = { -- Define which weapons cause large injuries + [Config.WeaponClasses['HIGH_CALIBER']] = true, + [Config.WeaponClasses['HEAVY_IMPACT']] = true, + [Config.WeaponClasses['SHOTGUN']] = true, + [Config.WeaponClasses['EXPLOSIVE']] = true, +} + +Config.AlwaysBleedChanceWeapons = { -- Define which weapons will always cause bleedign + [Config.WeaponClasses['SMALL_CALIBER']] = true, + [Config.WeaponClasses['MEDIUM_CALIBER']] = true, + [Config.WeaponClasses['CUTTING']] = true, + [Config.WeaponClasses['WILDLIFE']] = false, +} + +Config.ForceInjuryWeapons = { -- Define which weapons will always cause injuries + [Config.WeaponClasses['HIGH_CALIBER']] = true, + [Config.WeaponClasses['HEAVY_IMPACT']] = true, + [Config.WeaponClasses['EXPLOSIVE']] = true, +} + +Config.CriticalAreas = { -- Define body areas that will always cause bleeding if wearing armor or not + ['UPPER_BODY'] = { armored = false }, + ['LOWER_BODY'] = { armored = true }, + ['SPINE'] = { armored = true }, +} + +Config.StaggerAreas = { -- Define body areas that will always cause staggering if wearing armor or not + ['SPINE'] = { armored = true, major = 60, minor = 30 }, + ['UPPER_BODY'] = { armored = false, major = 60, minor = 30 }, + ['LLEG'] = { armored = true, major = 100, minor = 85 }, + ['RLEG'] = { armored = true, major = 100, minor = 85 }, + ['LFOOT'] = { armored = true, major = 100, minor = 100 }, + ['RFOOT'] = { armored = true, major = 100, minor = 100 }, +} + +Config.WoundStates = { -- Translate wound alerts + Lang:t('states.irritated'), + Lang:t('states.quite_painful'), + Lang:t('states.painful'), + Lang:t('states.really_painful'), +} + +Config.BleedingStates = { -- Translate bleeding alerts + [1] = {label = Lang:t('states.little_bleed')}, + [2] = {label = Lang:t('states.bleed')}, + [3] = {label = Lang:t('states.lot_bleed')}, + [4] = {label = Lang:t('states.big_bleed')}, +} + +Config.MovementRate = { -- Set the player movement rate based on the level of damage they have + 0.98, + 0.96, + 0.94, + 0.92, +} + +Config.Bones = { -- Correspond bone hash numbers to their label + [0] = 'NONE', + [31085] = 'HEAD', + [31086] = 'HEAD', + [39317] = 'NECK', + [57597] = 'SPINE', + [23553] = 'SPINE', + [24816] = 'SPINE', + [24817] = 'SPINE', + [24818] = 'SPINE', + [10706] = 'UPPER_BODY', + [64729] = 'UPPER_BODY', + [11816] = 'LOWER_BODY', + [45509] = 'LARM', + [61163] = 'LARM', + [18905] = 'LHAND', + [4089] = 'LFINGER', + [4090] = 'LFINGER', + [4137] = 'LFINGER', + [4138] = 'LFINGER', + [4153] = 'LFINGER', + [4154] = 'LFINGER', + [4169] = 'LFINGER', + [4170] = 'LFINGER', + [4185] = 'LFINGER', + [4186] = 'LFINGER', + [26610] = 'LFINGER', + [26611] = 'LFINGER', + [26612] = 'LFINGER', + [26613] = 'LFINGER', + [26614] = 'LFINGER', + [58271] = 'LLEG', + [63931] = 'LLEG', + [2108] = 'LFOOT', + [14201] = 'LFOOT', + [40269] = 'RARM', + [28252] = 'RARM', + [57005] = 'RHAND', + [58866] = 'RFINGER', + [58867] = 'RFINGER', + [58868] = 'RFINGER', + [58869] = 'RFINGER', + [58870] = 'RFINGER', + [64016] = 'RFINGER', + [64017] = 'RFINGER', + [64064] = 'RFINGER', + [64065] = 'RFINGER', + [64080] = 'RFINGER', + [64081] = 'RFINGER', + [64096] = 'RFINGER', + [64097] = 'RFINGER', + [64112] = 'RFINGER', + [64113] = 'RFINGER', + [36864] = 'RLEG', + [51826] = 'RLEG', + [20781] = 'RFOOT', + [52301] = 'RFOOT', +} + +Config.BoneIndexes = { -- Correspond bone labels to their hash number + ['NONE'] = 0, + -- ['HEAD'] = 31085, + ['HEAD'] = 31086, + ['NECK'] = 39317, + -- ['SPINE'] = 57597, + -- ['SPINE'] = 23553, + -- ['SPINE'] = 24816, + -- ['SPINE'] = 24817, + ['SPINE'] = 24818, + -- ['UPPER_BODY'] = 10706, + ['UPPER_BODY'] = 64729, + ['LOWER_BODY'] = 11816, + -- ['LARM'] = 45509, + ['LARM'] = 61163, + ['LHAND'] = 18905, + -- ['LFINGER'] = 4089, + -- ['LFINGER'] = 4090, + -- ['LFINGER'] = 4137, + -- ['LFINGER'] = 4138, + -- ['LFINGER'] = 4153, + -- ['LFINGER'] = 4154, + -- ['LFINGER'] = 4169, + -- ['LFINGER'] = 4170, + -- ['LFINGER'] = 4185, + -- ['LFINGER'] = 4186, + -- ['LFINGER'] = 26610, + -- ['LFINGER'] = 26611, + -- ['LFINGER'] = 26612, + -- ['LFINGER'] = 26613, + ['LFINGER'] = 26614, + -- ['LLEG'] = 58271, + ['LLEG'] = 63931, + -- ['LFOOT'] = 2108, + ['LFOOT'] = 14201, + -- ['RARM'] = 40269, + ['RARM'] = 28252, + ['RHAND'] = 57005, + -- ['RFINGER'] = 58866, + -- ['RFINGER'] = 58867, + -- ['RFINGER'] = 58868, + -- ['RFINGER'] = 58869, + -- ['RFINGER'] = 58870, + -- ['RFINGER'] = 64016, + -- ['RFINGER'] = 64017, + -- ['RFINGER'] = 64064, + -- ['RFINGER'] = 64065, + -- ['RFINGER'] = 64080, + -- ['RFINGER'] = 64081, + -- ['RFINGER'] = 64096, + -- ['RFINGER'] = 64097, + -- ['RFINGER'] = 64112, + ['RFINGER'] = 64113, + -- ['RLEG'] = 36864, + ['RLEG'] = 51826, + -- ['RFOOT'] = 20781, + ['RFOOT'] = 52301, +} + +Config.Weapons = { -- Correspond weapon names to their class number + ----------------------- + + [`WEAPON_STUNGUN`] = Config.WeaponClasses['NONE'], + [`WEAPON_STUNGUN_MP`] = Config.WeaponClasses['NONE'], + [`WEAPON_BEANGBAGSHOTGUN`] = Config.WeaponClasses['NONE'], + --[[ Small Caliber ]]-- + [`WEAPON_PISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_COMBATPISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_APPISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_COMBATPDW`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_MACHINEPISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_MICROSMG`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_MINISMG`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_PISTOL_MK2`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_SNSPISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_SNSPISTOL_MK2`] = Config.WeaponClasses['SMALL_CALIBER'], + [`WEAPON_VINTAGEPISTOL`] = Config.WeaponClasses['SMALL_CALIBER'], + + --[[ Medium Caliber ]]-- + [`WEAPON_ADVANCEDRIFLE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_ASSAULTSMG`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_BULLPUPRIFLE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_BULLPUPRIFLE_MK2`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_TACTICALRIFLE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_CARBINERIFLE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_CARBINERIFLE_MK2`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_COMPACTRIFLE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_DOUBLEACTION`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_GUSENBERG`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_HEAVYPISTOL`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_MARKSMANPISTOL`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_PISTOL50`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_REVOLVER`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_REVOLVER_MK2`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_SMG`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_SMG_MK2`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_SPECIALCARBINE`] = Config.WeaponClasses['MEDIUM_CALIBER'], + [`WEAPON_SPECIALCARBINE_MK2`] = Config.WeaponClasses['MEDIUM_CALIBER'], + + --[[ High Caliber ]]-- + [`WEAPON_ASSAULTRIFLE`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_ASSAULTRIFLE_MK2`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_COMBATMG`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_COMBATMG_MK2`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_HEAVYSNIPER`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_HEAVYSNIPER_MK2`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_MARKSMANRIFLE`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_MARKSMANRIFLE_MK2`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_MG`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_MINIGUN`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_MUSKET`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_RAILGUN`] = Config.WeaponClasses['HIGH_CALIBER'], + [`WEAPON_HEAVYRIFLE`] = Config.WeaponClasses['HIGH_CALIBER'], + + --[[ Shotguns ]]-- + [`WEAPON_ASSAULTSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_BULLUPSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_DBSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_HEAVYSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_PUMPSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_PUMPSHOTGUN_MK2`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_SAWNOFFSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + [`WEAPON_SWEEPERSHOTGUN`] = Config.WeaponClasses['SHOTGUN'], + + --[[ Animals ]]-- + [`WEAPON_ANIMAL`] = Config.WeaponClasses['WILDLIFE'], -- Animal + [`WEAPON_COUGAR`] = Config.WeaponClasses['WILDLIFE'], -- Cougar + [`WEAPON_BARBED_WIRE`] = Config.WeaponClasses['WILDLIFE'], -- Barbed Wire + + --[[ Cutting Weapons ]]-- + [`WEAPON_BATTLEAXE`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_BOTTLE`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_DAGGER`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_HATCHET`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_KNIFE`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_MACHETE`] = Config.WeaponClasses['CUTTING'], + [`WEAPON_SWITCHBLADE`] = Config.WeaponClasses['CUTTING'], + + --[[ Light Impact ]]-- + [`WEAPON_KNUCKLE`] = Config.WeaponClasses['LIGHT_IMPACT'], + + --[[ Heavy Impact ]]-- + [`WEAPON_BAT`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_CROWBAR`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_FIREEXTINGUISHER`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_FIRWORK`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_GOLFLCUB`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_HAMMER`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_PETROLCAN`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_POOLCUE`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_WRENCH`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_RAMMED_BY_CAR`] = Config.WeaponClasses['HEAVY_IMPACT'], + [`WEAPON_RUN_OVER_BY_CAR`] = Config.WeaponClasses['HEAVY_IMPACT'], + + --[[ Explosives ]]-- + [`WEAPON_EXPLOSION`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_GRENADE`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_COMPACTLAUNCHER`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_HOMINGLAUNCHER`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_PIPEBOMB`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_PROXMINE`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_RPG`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_STICKYBOMB`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_HELI_CRASH`] = Config.WeaponClasses['EXPLOSIVE'], + [`WEAPON_EMPLAUNCHER`] = Config.WeaponClasses['EXPLOSIVE'], + + --[[ Other ]]-- + [`WEAPON_FALL`] = Config.WeaponClasses['OTHER'], -- Fall + [`WEAPON_HIT_BY_WATER_CANNON`] = Config.WeaponClasses['OTHER'], -- Water Cannon + + --[[ Fire ]]-- + [`WEAPON_ELECTRIC_FENCE`] = Config.WeaponClasses['FIRE'], + [`WEAPON_FIRE`] = Config.WeaponClasses['FIRE'], + [`WEAPON_MOLOTOV`] = Config.WeaponClasses['FIRE'], + [`WEAPON_FLARE`] = Config.WeaponClasses['FIRE'], + [`WEAPON_FLAREGUN`] = Config.WeaponClasses['FIRE'], + + --[[ Suffocate ]]-- + [`WEAPON_DROWNING`] = Config.WeaponClasses['SUFFOCATING'], -- Drowning + [`WEAPON_DROWNING_IN_VEHICLE`] = Config.WeaponClasses['SUFFOCATING'], -- Drowning Veh + [`WEAPON_EXHAUSTION`] = Config.WeaponClasses['SUFFOCATING'], -- Exhaust + [`WEAPON_BZGAS`] = Config.WeaponClasses['SUFFOCATING'], + [`WEAPON_SMOKEGRENADE`] = Config.WeaponClasses['SUFFOCATING'], +} + +Config.VehicleSettings = { -- Enable or disable vehicle extras when pulling them from the ambulance job vehicle spawner + ["car1"] = { -- Model name + ["extras"] = { + ["1"] = false, -- on/off + ["2"] = true, + ["3"] = true, + ["4"] = true, + ["5"] = true, + ["6"] = true, + ["7"] = true, + ["8"] = true, + ["9"] = true, + ["10"] = true, + ["11"] = true, + ["12"] = true, + } + }, + ["car2"] = { + ["extras"] = { + ["1"] = false, + ["2"] = true, + ["3"] = true, + ["4"] = true, + ["5"] = true, + ["6"] = true, + ["7"] = true, + ["8"] = true, + ["9"] = true, + ["10"] = true, + ["11"] = true, + ["12"] = true, + } + } +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/fxmanifest.lua new file mode 100644 index 0000000..cddd187 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/fxmanifest.lua @@ -0,0 +1,30 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-AmbulanceJob' +version '1.2.3' + +shared_scripts { + '@qb-core/shared/locale.lua', + 'locales/da.lua', + 'locales/*.lua', + 'config.lua' +} + +client_scripts { + 'client/main.lua', + 'client/wounding.lua', + 'client/laststand.lua', + 'client/job.lua', + 'client/dead.lua', + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/ComboZone.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server/main.lua' +} + +lua54 'yes' diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/locales/da.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/locales/da.lua new file mode 100644 index 0000000..8a73d46 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/locales/da.lua @@ -0,0 +1,133 @@ +local Translations = { + error = { + canceled = 'Annulleret', + bled_out = 'Du er blødt ud...', + impossible = 'Handling umulig...', + no_player = 'Ingen spiller i nærheden', + no_firstaid = 'Du har brug for et førstehjælpssæt', + no_bandage = 'Du skal bruge en bandage', + beds_taken = 'Sengene er optaget...', + possessions_taken = 'Alle dine ejendele er blevet taget...', + not_enough_money = 'Du har ikke penge nok på dig...', + cant_help = 'Du kan ikke hjælpe denne person...', + not_ems = 'Du er ikke EMS eller ikke logget ind', + not_online = 'Spiller ikke online', + }, + success = { + revived = 'Du genoplivede en person', + healthy_player = 'Spilleren er sund', + helped_player = 'Du hjalp personen', + wounds_healed = 'Dine sår er blevet helet!', + being_helped = 'Du bliver hjulpet...', + }, + info = { + civ_died = 'Borger død', + civ_down = 'Borger faldet om', + civ_call = 'Borger opkald', + self_death = 'sig selv eller en NPC', + wep_unknown = 'Ukendt', + respawn_txt = 'GENOPLIVER OM: ~r~%{deathtime}~s~ SEKUNDER', + respawn_revive = 'HOLD [~r~E~s~] I %{holdtime} SEKUNDER FOR AT RESPAWNE FOR ~r~%{cost}~s~ KR', + bleed_out = 'DU BLØDER UD OM: ~r~%{time}~s~ SEKUNDER', + bleed_out_help = 'DU BLØDER UD OM: ~r~%{time}~s~ SEKUNDER, DU KAN BLIVE HJULPET', + request_help = 'TRYK [~r~G~s~] FOR AT ANMODE HJÆLP', + help_requested = 'EMS-PERSONALE HAR FÅET BESKED', + amb_plate = 'AMBU', + heli_plate = 'LIFE', + status = 'Status Tjek', + is_status = 'Du %{status}', + healthy = 'Du er rask igen!', + safe = 'Hospital lager', + pb_hospital = 'Pillbox Hospital', + pain_message = '%{limb} %{severity}', + many_places = 'Du har ondt mange steder...', + bleed_alert = '%{bleedstate}', + ems_alert = 'EMS alarm - %{text}', + mr = 'Hr.', + mrs = 'Fru', + dr_needed = 'Der er brug for en læge på Pillbox Hospital', + ems_report = 'Lægerapport', + message_sent = 'Besked der skal sendes', + check_health = 'Tjek en spillers helbred', + heal_player = 'Helbred en spiller', + revive_player = 'Genopliv en spiller', + revive_player_a = 'Genopliv en spiller eller dig selv (kun admin)', + player_id = 'Spiller id (kan være tomt)', + pain_level = 'Indstil dit eller en spillers smerteniveau (kun admin)', + kill = 'Dræb en spiller eller dig selv (kun admin)', + heal_player_a = 'Heal en spiller eller dig selv (kun admin)', + }, + mail = { + sender = 'Pillbox Hospital', + subject = 'Hospitalomkostninger', + message = 'Kære %{gender} %{lastname},

Hermed har du modtaget en mail med omkostningerne ved det sidste hospitalsbesøg.
De endelige omkostninger er blevet: %{costs} kr.

Vi ønsker dig god bedring!', + }, + states = { + irritated = 'er irriteret', + quite_painful = 'er i store smerter', + painful = 'er i smerter', + really_painful = 'er i meget store smerter', + little_bleed = 'bløder en lille smule...', + bleed = 'bløder...', + lot_bleed = 'bløder meget...', + big_bleed = 'har en stor blødning...', + }, + menu = { + amb_vehicles = 'Ambulancebiler', + status = 'Sundhedsstatus', + close = '⬅ Luk menu', + }, + text = { + pstash_button = '[E] - Personligt lager', + pstash = 'Personligt lager', + onduty_button = '[E] - Gå på vagt', + offduty_button = '[E] - Gå af vagt', + duty = 'På/Af Vagt', + armory_button = '[E] - Lager', + armory = 'Lager', + veh_button = '[E] - Tag / Gem køretøj', + heli_button = '[E] - Tag / Gem Helikopter', + elevator_roof = '[E] - Tag elevatoren til taget', + elevator_main = '[E] - Tag elevatoren ned', + bed_out = '[E] - For at komme ud af sengen..', + call_doc = '[E] - Ring til læge', + call = 'Ring', + check_in = '[E] Tjek ind', + check = 'Tjek ind', + lie_bed = '[E] - At ligge i sengen', + }, + body = { + head = 'Hoved', + neck = 'Hals', + spine = 'Rygrad', + upper_body = 'Overkroppen', + lower_body = 'Underkrop', + left_arm = 'Venstre arm', + left_hand = 'Venstre hånd', + left_fingers = 'Venstre fingre', + left_leg = 'Venstre ben', + left_foot = 'Venstre fod', + right_arm = 'Højre arm', + right_hand = 'Højre hånd', + right_fingers = 'Højre fingre', + right_leg = 'Højre ben', + right_foot = 'Højre fod', + }, + progress = { + ifaks = 'Tager ifak...', + bandage = 'Bruger bandage...', + painkillers = 'Tager smertestillende medicin...', + revive = 'Genopliver person...', + healing = 'Heler sår...', + checking_in = 'Tjekker ind...', + }, + logs = { + death_log_title = "%{playername} (%{playerid}) er død", + death_log_message = "%{killername} har dræbt %{playername} med **%{weaponlabel}** (%{weaponname})", + } +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +}) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/emsbag_sv.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/emsbag_sv.lua new file mode 100644 index 0000000..0006ec1 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/emsbag_sv.lua @@ -0,0 +1,39 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local Objects = {} + +local function CreateObjectId() + if Objects then + local objectId = math.random(10000, 99999) + while Objects[objectId] do + objectId = math.random(10000, 99999) + end + return objectId + else + local objectId = math.random(10000, 99999) + return objectId + end +end + +QBCore.Functions.CreateUseableItem('emsbag', function(source, item)TriggerClientEvent("Ranjit-EmsBag:Client:spawnLight", source)end) + +RegisterNetEvent('Ranjit-EmsBag:Server:SpawnAmbulanceBag', function(type) + local src = source + local objectId = CreateObjectId() + Objects[objectId] = type + TriggerClientEvent("Ranjit-EmsBag:Client:SpawnAmbulanceBag", src, objectId, type, src) +end) + +RegisterNetEvent('Ranjit-EmsBag:Server:RemoveItem', function(item, amount) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + Player.Functions.RemoveItem(item, amount) +end) + +RegisterNetEvent('Ranjit-EmsBag:Server:AddItem', function(item, amount) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + Player.Functions.AddItem(item, amount) +end) + + diff --git a/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/main.lua b/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/main.lua new file mode 100644 index 0000000..4eb0740 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-ambulancejob/server/main.lua @@ -0,0 +1,482 @@ +local PlayerInjuries = {} +local PlayerWeaponWounds = {} +local QBCore = exports['qb-core']:GetCoreObject() +local doctorCount = 0 +local doctorCalled = false +local Doctors = {} + +-- Events + +-- Compatibility with txAdmin Menu's heal options. +-- This is an admin only server side event that will pass the target player id or -1. +AddEventHandler('txAdmin:events:healedPlayer', function(eventData) + if GetInvokingResource() ~= "monitor" or type(eventData) ~= "table" or type(eventData.id) ~= "number" then + return + end + + TriggerClientEvent('hospital:client:Revive', eventData.id) + TriggerClientEvent("hospital:client:HealInjuries", eventData.id, "full") +end) + +RegisterNetEvent('hospital:server:SendToBed', function(bedId, isRevive) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + TriggerClientEvent('hospital:client:SendToBed', src, bedId, Config.Locations["beds"][bedId], isRevive) + TriggerClientEvent('hospital:client:SetBed', -1, bedId, true) + Player.Functions.RemoveMoney("bank", Config.BillCost , "respawned-at-hospital") + exports['qb-management']:AddMoney("ambulance", Config.BillCost) + TriggerClientEvent('hospital:client:SendBillEmail', src, Config.BillCost) +end) + +RegisterNetEvent('hospital:server:RespawnAtHospital', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.metadata["injail"] > 0 then + for k, v in pairs(Config.Locations["jailbeds"]) do + if not v.taken then + TriggerClientEvent('hospital:client:SendToBed', src, k, v, true) + TriggerClientEvent('hospital:client:SetBed2', -1, k, true) + if Config.WipeInventoryOnRespawn then + Player.Functions.ClearInventory() + MySQL.Async.execute('UPDATE players SET inventory = ? WHERE citizenid = ?', { json.encode({}), Player.PlayerData.citizenid }) + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.possessions_taken'), 'error') + end + Player.Functions.RemoveMoney("bank", Config.BillCost, "respawned-at-hospital") + exports['qb-management']:AddMoney("ambulance", Config.BillCost) + TriggerClientEvent('hospital:client:SendBillEmail', src, Config.BillCost) + return + end + end + + TriggerClientEvent('hospital:client:SendToBed', src, 1, Config.Locations["jailbeds"][1], true) + TriggerClientEvent('hospital:client:SetBed', -1, 1, true) + if Config.WipeInventoryOnRespawn then + Player.Functions.ClearInventory() + MySQL.Async.execute('UPDATE players SET inventory = ? WHERE citizenid = ?', { json.encode({}), Player.PlayerData.citizenid }) + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.possessions_taken'), 'error') + end + Player.Functions.RemoveMoney("bank", Config.BillCost, "respawned-at-hospital") + exports['qb-management']:AddMoney("ambulance", Config.BillCost) + TriggerClientEvent('hospital:client:SendBillEmail', src, Config.BillCost) + else + for k, v in pairs(Config.Locations["beds"]) do + if not v.taken then + TriggerClientEvent('hospital:client:SendToBed', src, k, v, true) + TriggerClientEvent('hospital:client:SetBed', -1, k, true) + if Config.WipeInventoryOnRespawn then + Player.Functions.ClearInventory() + MySQL.update('UPDATE players SET inventory = ? WHERE citizenid = ?', { json.encode({}), Player.PlayerData.citizenid }) + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.possessions_taken'), 'error') + end + Player.Functions.RemoveMoney("bank", Config.BillCost, "respawned-at-hospital") + exports['qb-management']:AddMoney("ambulance", Config.BillCost) + TriggerClientEvent('hospital:client:SendBillEmail', src, Config.BillCost) + return + end + end + --print("All beds were full, placing in first bed as fallback") + + TriggerClientEvent('hospital:client:SendToBed', src, 1, Config.Locations["beds"][1], true) + TriggerClientEvent('hospital:client:SetBed', -1, 1, true) + if Config.WipeInventoryOnRespawn then + Player.Functions.ClearInventory() + MySQL.update('UPDATE players SET inventory = ? WHERE citizenid = ?', { json.encode({}), Player.PlayerData.citizenid }) + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.possessions_taken'), 'error') + end + Player.Functions.RemoveMoney("bank", Config.BillCost, "respawned-at-hospital") + exports['qb-management']:AddMoney("ambulance", Config.BillCost) + TriggerClientEvent('hospital:client:SendBillEmail', src, Config.BillCost) + end +end) + +RegisterNetEvent('hospital:server:ambulanceAlert', function(text) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local players = QBCore.Functions.GetQBPlayers() + for _, v in pairs(players) do + if v.PlayerData.job.name == 'ambulance' and v.PlayerData.job.onduty then + TriggerClientEvent('hospital:client:ambulanceAlert', v.PlayerData.source, coords, text) + end + end +end) + +RegisterNetEvent('hospital:server:LeaveBed', function(id) + TriggerClientEvent('hospital:client:SetBed', -1, id, false) +end) + +RegisterNetEvent('hospital:server:SyncInjuries', function(data) + local src = source + PlayerInjuries[src] = data +end) + +RegisterNetEvent('hospital:server:SetWeaponDamage', function(data) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player then + PlayerWeaponWounds[Player.PlayerData.source] = data + end +end) + +RegisterNetEvent('hospital:server:RestoreWeaponDamage', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + PlayerWeaponWounds[Player.PlayerData.source] = nil +end) + +RegisterNetEvent('hospital:server:SetDeathStatus', function(isDead) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player then + Player.Functions.SetMetaData("isdead", isDead) + end +end) + +RegisterNetEvent('hospital:server:SetLaststandStatus', function(bool) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player then + Player.Functions.SetMetaData("inlaststand", bool) + end +end) + +RegisterNetEvent('hospital:server:SetArmor', function(amount) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player then + Player.Functions.SetMetaData("armor", amount) + end +end) + +RegisterNetEvent('hospital:server:TreatWounds', function(playerId) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local Patient = QBCore.Functions.GetPlayer(playerId) + if Patient then + if Player.PlayerData.job.name =="ambulance" then + Player.Functions.RemoveItem('bandage', 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items['bandage'], "remove") + TriggerClientEvent("hospital:client:HealInjuries", Patient.PlayerData.source, "full") + end + end +end) + +RegisterNetEvent('hospital:server:AddDoctor', function(job) + if job == 'ambulance' then + local src = source + doctorCount = doctorCount + 1 + TriggerClientEvent("hospital:client:SetDoctorCount", -1, doctorCount) + Doctors[src] = true + end +end) + +RegisterNetEvent('hospital:server:RemoveDoctor', function(job) + if job == 'ambulance' then + local src = source + doctorCount = doctorCount - 1 + TriggerClientEvent("hospital:client:SetDoctorCount", -1, doctorCount) + Doctors[src] = nil + end +end) + +AddEventHandler("playerDropped", function() + local src = source + if Doctors[src] then + doctorCount = doctorCount - 1 + TriggerClientEvent("hospital:client:SetDoctorCount", -1, doctorCount) + Doctors[src] = nil + end +end) + +RegisterNetEvent("hospital:server:addTrunkItems", function(plate, items) exports["ps-inventory"]:addTrunkItems(plate, items) end) + +RegisterNetEvent('hospital:server:RevivePlayer', function(playerId, isOldMan) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local Patient = QBCore.Functions.GetPlayer(playerId) + local oldMan = isOldMan or false + if Patient then + if Player.PlayerData.job.name == "ambulance" or QBCore.Functions.HasItem(src, "firstaid", 1) then + if oldMan then + if Player.Functions.RemoveMoney("cash", 5000, "revived-player") then + Player.Functions.RemoveItem('firstaid', 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items['firstaid'], "remove") + TriggerClientEvent('hospital:client:Revive', Patient.PlayerData.source) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_enough_money'), "error") + end + else + Player.Functions.RemoveItem('firstaid', 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items['firstaid'], "remove") + TriggerClientEvent('hospital:client:Revive', Patient.PlayerData.source) + end + else + MySQL.insert('INSERT INTO bans (name, license, discord, ip, reason, expire, bannedby) VALUES (?, ?, ?, ?, ?, ?, ?)', { + GetPlayerName(src), + QBCore.Functions.GetIdentifier(src, 'license'), + QBCore.Functions.GetIdentifier(src, 'discord'), + '0.0.0.0', + "Trying to revive themselves or other players", + 2147483647, + 'qb-ambulancejob' + }) + TriggerEvent('qb-log:server:CreateLog', 'ambulancejob', 'Player Banned', 'red', string.format('%s was banned by %s for %s', GetPlayerName(src), 'qb-ambulancejob', "Trying to revive themselves or other players"), true) + DropPlayer(src, 'You were permanently banned by the server for: Exploiting') + end + end +end) + +RegisterNetEvent('hospital:server:SendDoctorAlert', function() + local src = source + if not doctorCalled then + doctorCalled = true + local players = QBCore.Functions.GetQBPlayers() + for _, v in pairs(players) do + if v.PlayerData.job.name == 'ambulance' and v.PlayerData.job.onduty then + TriggerClientEvent('QBCore:Notify', v.PlayerData.source, Lang:t('info.dr_needed'), 'ambulance') + end + end + SetTimeout(Config.DocCooldown * 60000, function() + doctorCalled = false + end) + else + TriggerClientEvent('QBCore:Notify', src, 'Læge er allerede underrettet', 'error') + end +end) + +RegisterNetEvent('hospital:server:UseFirstAid', function(targetId) + local src = source + local Target = QBCore.Functions.GetPlayer(targetId) + if Target then + TriggerClientEvent('hospital:client:CanHelp', targetId, src) + end +end) + +RegisterNetEvent('hospital:server:CanHelp', function(helperId, canHelp) + local src = source + if canHelp then + TriggerClientEvent('hospital:client:HelpPerson', helperId, src) + else + TriggerClientEvent('QBCore:Notify', helperId, Lang:t('error.cant_help'), "error") + end +end) + +RegisterNetEvent('hospital:server:removeBandage', function() + local Player = QBCore.Functions.GetPlayer(source) + + if not Player then return end + + Player.Functions.RemoveItem('bandage', 1) +end) + +RegisterNetEvent('hospital:server:removeIfaks', function() + local Player = QBCore.Functions.GetPlayer(source) + + if not Player then return end + + Player.Functions.RemoveItem('ifaks', 1) +end) + +RegisterNetEvent('hospital:server:removePainkillers', function() + local Player = QBCore.Functions.GetPlayer(source) + + if not Player then return end + + Player.Functions.RemoveItem('painkillers', 1) +end) + +RegisterNetEvent('hospital:server:resetHungerThirst', function() + local Player = QBCore.Functions.GetPlayer(source) + + if not Player then return end + + Player.Functions.SetMetaData('hunger', 100) + Player.Functions.SetMetaData('thirst', 100) + + TriggerClientEvent('hud:client:UpdateNeeds', source, 100, 100) +end) + +-- Callbacks + +QBCore.Functions.CreateCallback('hospital:GetDoctors', function(_, cb) + local amount = 0 + local players = QBCore.Functions.GetQBPlayers() + for _, v in pairs(players) do + if v.PlayerData.job.name == 'ambulance' and v.PlayerData.job.onduty then + amount = amount + 1 + end + end + cb(amount) +end) + +QBCore.Functions.CreateCallback('hospital:GetPlayerStatus', function(_, cb, playerId) + local Player = QBCore.Functions.GetPlayer(playerId) + local injuries = {} + injuries["WEAPONWOUNDS"] = {} + if Player then + if PlayerInjuries[Player.PlayerData.source] then + if (PlayerInjuries[Player.PlayerData.source].isBleeding > 0) then + injuries["BLEED"] = PlayerInjuries[Player.PlayerData.source].isBleeding + end + for k, _ in pairs(PlayerInjuries[Player.PlayerData.source].limbs) do + if PlayerInjuries[Player.PlayerData.source].limbs[k].isDamaged then + injuries[k] = PlayerInjuries[Player.PlayerData.source].limbs[k] + end + end + end + if PlayerWeaponWounds[Player.PlayerData.source] then + for k, v in pairs(PlayerWeaponWounds[Player.PlayerData.source]) do + injuries["WEAPONWOUNDS"][k] = v + end + end + end + cb(injuries) +end) + +QBCore.Functions.CreateCallback('hospital:GetPlayerBleeding', function(source, cb) + local src = source + if PlayerInjuries[src] and PlayerInjuries[src].isBleeding then + cb(PlayerInjuries[src].isBleeding) + else + cb(nil) + end +end) + +-- Commands + +--[[QBCore.Commands.Add('911e', Lang:t('info.ems_report'), {{name = 'message', help = Lang:t('info.message_sent')}}, false, function(source, args) + local src = source + local message + if args[1] then message = table.concat(args, " ") else message = Lang:t('info.civ_call') end + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local players = QBCore.Functions.GetQBPlayers() + for _, v in pairs(players) do + if v.PlayerData.job.name == 'ambulance' and v.PlayerData.job.onduty then + TriggerClientEvent('hospital:client:ambulanceAlert', v.PlayerData.source, coords, message) + end + end +end)]] + +QBCore.Commands.Add("status", Lang:t('info.check_health'), {}, false, function(source, _) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.job.name == "ambulance" then + TriggerClientEvent("hospital:client:CheckStatus", src) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_ems'), "error") + end +end) + +QBCore.Commands.Add("heal", Lang:t('info.heal_player'), {}, false, function(source, _) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.job.name == "ambulance" then + TriggerClientEvent("hospital:client:TreatWounds", src) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_ems'), "error") + end +end) + +QBCore.Commands.Add("revivep", Lang:t('info.revive_player'), {}, false, function(source, _) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.job.name == "ambulance" then + TriggerClientEvent("hospital:client:RevivePlayer", src) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_ems'), "error") + end +end) + +QBCore.Commands.Add("revive", Lang:t('info.revive_player_a'), {{name = "id", help = Lang:t('info.player_id')}}, false, function(source, args) + local src = source + if args[1] then + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + TriggerClientEvent('hospital:client:Revive', Player.PlayerData.source) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_online'), "error") + end + else + TriggerClientEvent('hospital:client:Revive', src) + end +end, "admin") + +QBCore.Commands.Add("setpain", Lang:t('info.pain_level'), {{name = "id", help = Lang:t('info.player_id')}}, false, function(source, args) + local src = source + if args[1] then + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + TriggerClientEvent('hospital:client:SetPain', Player.PlayerData.source) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_online'), "error") + end + else + TriggerClientEvent('hospital:client:SetPain', src) + end +end, "admin") + +QBCore.Commands.Add("kill", Lang:t('info.kill'), {{name = "id", help = Lang:t('info.player_id')}}, false, function(source, args) + local src = source + if args[1] then + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + TriggerClientEvent('hospital:client:KillPlayer', Player.PlayerData.source) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_online'), "error") + end + else + TriggerClientEvent('hospital:client:KillPlayer', src) + end +end, "admin") + +QBCore.Commands.Add('aheal', Lang:t('info.heal_player_a'), {{name = 'id', help = Lang:t('info.player_id')}}, false, function(source, args) + local src = source + if args[1] then + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + TriggerClientEvent('hospital:client:adminHeal', Player.PlayerData.source) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_online'), "error") + end + else + TriggerClientEvent('hospital:client:adminHeal', src) + end +end, 'admin') + +-- Items + +QBCore.Functions.CreateUseableItem("ifaks", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.Functions.GetItemByName(item.name) ~= nil then + TriggerClientEvent("hospital:client:UseIfaks", src) + end +end) + +QBCore.Functions.CreateUseableItem("bandage", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.Functions.GetItemByName(item.name) ~= nil then + TriggerClientEvent("hospital:client:UseBandage", src) + end +end) + +QBCore.Functions.CreateUseableItem("painkillers", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.Functions.GetItemByName(item.name) ~= nil then + TriggerClientEvent("hospital:client:UsePainkillers", src) + end +end) + +QBCore.Functions.CreateUseableItem("firstaid", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.Functions.GetItemByName(item.name) ~= nil then + TriggerClientEvent("hospital:client:UseFirstAid", src) + end +end) + +exports('GetDoctorCount', function() return doctorCount end) + diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/LICENSE b/resources/[qb]/[qb_jobs]/qb-busjob/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/README.md b/resources/[qb]/[qb_jobs]/qb-busjob/README.md new file mode 100644 index 0000000..bf95e0b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/README.md @@ -0,0 +1,21 @@ +# qb-busjob +Bus Job For QB-Core + +# License + + QBCore Framework + Copyright (C) 2021 Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/client/main.lua b/resources/[qb]/[qb_jobs]/qb-busjob/client/main.lua new file mode 100644 index 0000000..d4cf693 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/client/main.lua @@ -0,0 +1,343 @@ +-- Variables +local QBCore = exports['qb-core']:GetCoreObject() +local PlayerData = QBCore.Functions.GetPlayerData() +local route = 1 +local max = #Config.NPCLocations.Locations +local busBlip = nil + +local NpcData = { + Active = false, + CurrentNpc = nil, + LastNpc = nil, + CurrentDeliver = nil, + LastDeliver = nil, + Npc = nil, + NpcBlip = nil, + DeliveryBlip = nil, + NpcTaken = false, + NpcDelivered = false, + CountDown = 180 +} + +local BusData = { + Active = false, +} + +-- Functions +local function resetNpcTask() + NpcData = { + Active = false, + CurrentNpc = nil, + LastNpc = nil, + CurrentDeliver = nil, + LastDeliver = nil, + Npc = nil, + NpcBlip = nil, + DeliveryBlip = nil, + NpcTaken = false, + NpcDelivered = false, + } +end + +local function updateBlip() + if PlayerData.job.name == "bus" then + busBlip = AddBlipForCoord(Config.Location) + SetBlipSprite(busBlip, 513) + SetBlipDisplay(busBlip, 4) + SetBlipScale(busBlip, 0.6) + SetBlipAsShortRange(busBlip, true) + SetBlipColour(busBlip, 49) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Lang:t('info.bus_depot')) + EndTextCommandSetBlipName(busBlip) + elseif busBlip ~= nil then + RemoveBlip(busBlip) + end +end + +local function whitelistedVehicle() + local ped = PlayerPedId() + local veh = GetEntityModel(GetVehiclePedIsIn(ped)) + local retval = false + + for i = 1, #Config.AllowedVehicles, 1 do + if veh == GetHashKey(Config.AllowedVehicles[i].model) then + retval = true + end + end + + if veh == GetHashKey("dynasty") then + retval = true + end + + return retval +end + +local function nextStop() + if route <= (max - 1) then + route = route + 1 + else + route = 1 + end +end + +local function GetDeliveryLocation() + nextStop() + if NpcData.DeliveryBlip ~= nil then + RemoveBlip(NpcData.DeliveryBlip) + end + NpcData.DeliveryBlip = AddBlipForCoord(Config.NPCLocations.Locations[route].x, Config.NPCLocations.Locations[route].y, Config.NPCLocations.Locations[route].z) + SetBlipColour(NpcData.DeliveryBlip, 3) + SetBlipRoute(NpcData.DeliveryBlip, true) + SetBlipRouteColour(NpcData.DeliveryBlip, 3) + NpcData.LastDeliver = route + local inRange = false + local PolyZone = CircleZone:Create(vector3(Config.NPCLocations.Locations[route].x, + Config.NPCLocations.Locations[route].y, Config.NPCLocations.Locations[route].z), 5, { + name = "busjobdeliver", + useZ = true, + -- debugPoly=true + }) + PolyZone:onPlayerInOut(function(isPointInside) + if isPointInside then + inRange = true + exports["qb-core"]:DrawText(Lang:t('info.busstop_text'), 'top') + CreateThread(function() + repeat + Wait(0) + if IsControlJustPressed(0, 38) then + local ped = PlayerPedId() + local veh = GetVehiclePedIsIn(ped, 0) + TaskLeaveVehicle(NpcData.Npc, veh, 0) + SetEntityAsMissionEntity(NpcData.Npc, false, true) + SetEntityAsNoLongerNeeded(NpcData.Npc) + local targetCoords = Config.NPCLocations.Locations[NpcData.LastNpc] + TaskGoStraightToCoord(NpcData.Npc, targetCoords.x, targetCoords.y, targetCoords.z, 1.0, -1, 0.0, 0.0) + QBCore.Functions.Notify(Lang:t('success.dropped_off'), 'success') + if NpcData.DeliveryBlip ~= nil then + RemoveBlip(NpcData.DeliveryBlip) + end + local RemovePed = function(pped) + SetTimeout(60000, function() + DeletePed(pped) + end) + end + RemovePed(NpcData.Npc) + resetNpcTask() + nextStop() + TriggerEvent('qb-busjob:client:DoBusNpc') + exports["qb-core"]:HideText() + PolyZone:destroy() + break + end + until not inRange + end) + else + exports["qb-core"]:HideText() + inRange = false + end + end) +end + +local function closeMenuFull() + exports['qb-menu']:closeMenu() +end + +-- Old Menu Code (being removed) +local function busGarage() + local vehicleMenu = { + { + header = Lang:t('menu.bus_header'), + isMenuHeader = true + } + } + for _, v in pairs(Config.AllowedVehicles) do + vehicleMenu[#vehicleMenu + 1] = { + header = v.label, + params = { + event = "qb-busjob:client:TakeVehicle", + args = { + model = v.model + } + } + } + end + vehicleMenu[#vehicleMenu + 1] = { + header = Lang:t('menu.bus_close'), + params = { + event = "qb-menu:client:closeMenu" + } + } + exports['qb-menu']:openMenu(vehicleMenu) +end + +RegisterNetEvent("qb-busjob:client:TakeVehicle", function(data) + local coords = Config.Location + if (BusData.Active) then + QBCore.Functions.Notify(Lang:t('error.one_bus_active'), 'error') + return + else + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleNumberPlateText(veh, Lang:t('info.bus_plate') .. tostring(math.random(1000, 9999))) + exports['qb-fuel']:SetFuel(veh, 100.0) + closeMenuFull() + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + SetVehicleEngineOn(veh, true, true) + end, data.model, coords, true) + Wait(1000) + TriggerEvent('qb-busjob:client:DoBusNpc') + end +end) + +-- Events +AddEventHandler('onResourceStart', function(resourceName) + -- handles script restarts + if GetCurrentResourceName() == resourceName then + updateBlip() + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + PlayerData = QBCore.Functions.GetPlayerData() + updateBlip() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + PlayerData = {} +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + PlayerData.job = JobInfo + updateBlip() + +end) + +RegisterNetEvent('qb-busjob:client:DoBusNpc', function() + if whitelistedVehicle() then + if not NpcData.Active then + local Gender = math.random(1, #Config.NpcSkins) + local PedSkin = math.random(1, #Config.NpcSkins[Gender]) + local model = GetHashKey(Config.NpcSkins[Gender][PedSkin]) + RequestModel(model) + while not HasModelLoaded(model) do + Wait(0) + end + NpcData.Npc = CreatePed(3, model, Config.NPCLocations.Locations[route].x, Config.NPCLocations.Locations[route].y, Config.NPCLocations.Locations[route].z - 0.98, Config.NPCLocations.Locations[route].w, false, true) + PlaceObjectOnGroundProperly(NpcData.Npc) + FreezeEntityPosition(NpcData.Npc, true) + if NpcData.NpcBlip ~= nil then + RemoveBlip(NpcData.NpcBlip) + end + QBCore.Functions.Notify(Lang:t('info.goto_busstop'), 'primary') + NpcData.NpcBlip = AddBlipForCoord(Config.NPCLocations.Locations[route].x, Config.NPCLocations.Locations[route].y, Config.NPCLocations.Locations[route].z) + SetBlipColour(NpcData.NpcBlip, 3) + SetBlipRoute(NpcData.NpcBlip, true) + SetBlipRouteColour(NpcData.NpcBlip, 3) + NpcData.LastNpc = route + NpcData.Active = true + local inRange = false + local PolyZone = CircleZone:Create(vector3(Config.NPCLocations.Locations[route].x, + Config.NPCLocations.Locations[route].y, Config.NPCLocations.Locations[route].z), 5, { + name = "busjobdeliver", + useZ = true, + -- debugPoly=true + }) + PolyZone:onPlayerInOut(function(isPointInside) + if isPointInside then + inRange = true + exports["qb-core"]:DrawText(Lang:t('info.busstop_text'), 'top') + CreateThread(function() + repeat + Wait(5) + if IsControlJustPressed(0, 38) then + local ped = PlayerPedId() + local veh = GetVehiclePedIsIn(ped, 0) + local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(veh) + + for i = maxSeats - 1, 0, -1 do + if IsVehicleSeatFree(veh, i) then + freeSeat = i + break + end + end + + ClearPedTasksImmediately(NpcData.Npc) + FreezeEntityPosition(NpcData.Npc, false) + TaskEnterVehicle(NpcData.Npc, veh, -1, freeSeat, 1.0, 0) + QBCore.Functions.Notify(Lang:t('info.goto_busstop'), 'primary') + if NpcData.NpcBlip ~= nil then + RemoveBlip(NpcData.NpcBlip) + end + GetDeliveryLocation() + NpcData.NpcTaken = true + TriggerServerEvent('qb-busjob:server:NpcPay') + exports["qb-core"]:HideText() + PolyZone:destroy() + break + end + until not inRange + end) + else + exports["qb-core"]:HideText() + inRange = false + end + end) + else + QBCore.Functions.Notify(Lang:t('error.already_driving_bus'), 'error') + end + else + QBCore.Functions.Notify(Lang:t('error.not_in_bus'), 'error') + end +end) + +-- Threads +CreateThread(function() + local inRange = false + local PolyZone = CircleZone:Create(vector3(Config.Location.x, Config.Location.y, Config.Location.z), 5, { + name = "busMain", + useZ = true, + debugPoly = false + }) + PolyZone:onPlayerInOut(function(isPointInside) + local inVeh = whitelistedVehicle() + if PlayerData.job.name == "bus" then + if isPointInside then + inRange = true + CreateThread(function() + repeat + Wait(5) + if not inVeh then + exports["qb-core"]:DrawText(Lang:t('info.busstop_text'), 'top') + if IsControlJustReleased(0, 38) then + busGarage() + exports["qb-core"]:HideText() + break + end + else + exports["qb-core"]:DrawText(Lang:t('info.bus_stop_work'), 'top') + if IsControlJustReleased(0, 38) then + if (not NpcData.Active or NpcData.Active and NpcData.NpcTaken == false) then + if IsPedInAnyVehicle(PlayerPedId(), false) then + BusData.Active = false; + DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) + RemoveBlip(NpcData.NpcBlip) + exports["qb-core"]:HideText() + resetNpcTask() + break + end + else + QBCore.Functions.Notify(Lang:t('error.drop_off_passengers'), 'error') + end + end + end + until not inRange + end) + else + exports["qb-core"]:HideText() + inRange = false + end + end + end) +end) diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/config.lua b/resources/[qb]/[qb_jobs]/qb-busjob/config.lua new file mode 100644 index 0000000..63b2b1e --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/config.lua @@ -0,0 +1,164 @@ +Config = Config or {} + +Config.AllowedVehicles = { + [1] = {model = "bus", label = Lang:t('info.bus')}, +} + +Config.Location = vector4(462.22, -641.15, 28.45, 175.0) + +Config.NPCLocations = { + Locations = { + vector4(304.36, -764.56, 29.31, 252.09), + vector4(-110.31, -1686.29, 29.31, 223.84), + vector4(-712.83, -824.56, 23.54, 194.7), + vector4(-692.63, -670.44, 30.86, 61.84), + vector4(-250.14, -886.78, 30.63, 8.67), + } +} + +Config.NpcSkins = { + [1] = { + 'a_f_m_skidrow_01', + 'a_f_m_soucentmc_01', + 'a_f_m_soucent_01', + 'a_f_m_soucent_02', + 'a_f_m_tourist_01', + 'a_f_m_trampbeac_01', + 'a_f_m_tramp_01', + 'a_f_o_genstreet_01', + 'a_f_o_indian_01', + 'a_f_o_ktown_01', + 'a_f_o_salton_01', + 'a_f_o_soucent_01', + 'a_f_o_soucent_02', + 'a_f_y_beach_01', + 'a_f_y_bevhills_01', + 'a_f_y_bevhills_02', + 'a_f_y_bevhills_03', + 'a_f_y_bevhills_04', + 'a_f_y_business_01', + 'a_f_y_business_02', + 'a_f_y_business_03', + 'a_f_y_business_04', + 'a_f_y_eastsa_01', + 'a_f_y_eastsa_02', + 'a_f_y_eastsa_03', + 'a_f_y_epsilon_01', + 'a_f_y_fitness_01', + 'a_f_y_fitness_02', + 'a_f_y_genhot_01', + 'a_f_y_golfer_01', + 'a_f_y_hiker_01', + 'a_f_y_hipster_01', + 'a_f_y_hipster_02', + 'a_f_y_hipster_03', + 'a_f_y_hipster_04', + 'a_f_y_indian_01', + 'a_f_y_juggalo_01', + 'a_f_y_runner_01', + 'a_f_y_rurmeth_01', + 'a_f_y_scdressy_01', + 'a_f_y_skater_01', + 'a_f_y_soucent_01', + 'a_f_y_soucent_02', + 'a_f_y_soucent_03', + 'a_f_y_tennis_01', + 'a_f_y_tourist_01', + 'a_f_y_tourist_02', + 'a_f_y_vinewood_01', + 'a_f_y_vinewood_02', + 'a_f_y_vinewood_03', + 'a_f_y_vinewood_04', + 'a_f_y_yoga_01', + 'g_f_y_ballas_01', + }, + [2] = { + 'ig_barry', + 'ig_bestmen', + 'ig_beverly', + 'ig_car3guy1', + 'ig_car3guy2', + 'ig_casey', + 'ig_chef', + 'ig_chengsr', + 'ig_chrisformage', + 'ig_clay', + 'ig_claypain', + 'ig_cletus', + 'ig_dale', + 'ig_dreyfuss', + 'ig_fbisuit_01', + 'ig_floyd', + 'ig_groom', + 'ig_hao', + 'ig_hunter', + 'csb_prolsec', + 'ig_joeminuteman', + 'ig_josef', + 'ig_josh', + 'ig_lamardavis', + 'ig_lazlow', + 'ig_lestercrest', + 'ig_lifeinvad_01', + 'ig_lifeinvad_02', + 'ig_manuel', + 'ig_milton', + 'ig_mrk', + 'ig_nervousron', + 'ig_nigel', + 'ig_old_man1a', + 'ig_old_man2', + 'ig_oneil', + 'ig_orleans', + 'ig_ortega', + 'ig_paper', + 'ig_priest', + 'ig_prolsec_02', + 'ig_ramp_gang', + 'ig_ramp_hic', + 'ig_ramp_hipster', + 'ig_ramp_mex', + 'ig_roccopelosi', + 'ig_russiandrunk', + 'ig_siemonyetarian', + 'ig_solomon', + 'ig_stevehains', + 'ig_stretch', + 'ig_talina', + 'ig_taocheng', + 'ig_taostranslator', + 'ig_tenniscoach', + 'ig_terry', + 'ig_tomepsilon', + 'ig_tylerdix', + 'ig_wade', + 'ig_zimbor', + 's_m_m_paramedic_01', + 'a_m_m_afriamer_01', + 'a_m_m_beach_01', + 'a_m_m_beach_02', + 'a_m_m_bevhills_01', + 'a_m_m_bevhills_02', + 'a_m_m_business_01', + 'a_m_m_eastsa_01', + 'a_m_m_eastsa_02', + 'a_m_m_farmer_01', + 'a_m_m_fatlatin_01', + 'a_m_m_genfat_01', + 'a_m_m_genfat_02', + 'a_m_m_golfer_01', + 'a_m_m_hasjew_01', + 'a_m_m_hillbilly_01', + 'a_m_m_hillbilly_02', + 'a_m_m_indian_01', + 'a_m_m_ktown_01', + 'a_m_m_malibu_01', + 'a_m_m_mexcntry_01', + 'a_m_m_mexlabor_01', + 'a_m_m_og_boss_01', + 'a_m_m_paparazzi_01', + 'a_m_m_polynesian_01', + 'a_m_m_prolhost_01', + 'a_m_m_rurmeth_01', + } +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-busjob/fxmanifest.lua new file mode 100644 index 0000000..43b9988 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/fxmanifest.lua @@ -0,0 +1,25 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-BusJob' +version '1.2.0' + +shared_scripts { + '@qb-core/shared/locale.lua', + 'locales/da.lua', + 'locales/*.lua', + 'config.lua' +} + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/EntityZone.lua', + '@PolyZone/CircleZone.lua', + '@PolyZone/ComboZone.lua', + 'client/main.lua' +} + +server_script 'server/main.lua' + +lua54 'yes' diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/locales/da.lua b/resources/[qb]/[qb_jobs]/qb-busjob/locales/da.lua new file mode 100644 index 0000000..4479325 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/locales/da.lua @@ -0,0 +1,29 @@ +local Translations = { + error = { + already_driving_bus = 'Du kører allerede en bus', + not_in_bus = 'Du er ikke i en bus', + one_bus_active = 'Du kan kun have en aktiv bus ad gangen', + drop_off_passengers = 'Sæt alle passagererne af før du afslutter ruten', + }, + success = { + dropped_off = 'Personen blev sat af', + }, + info = { + bus = 'Standard Bus', + goto_busstop = 'Gå til busstoppestedet', + busstop_text = '[E] Bus Stop', + bus_plate = 'BUS-', + bus_depot = 'Bus Depot', + bus_stop_work = '[E] Stop job', + bus_job_vehicles = '[E] Jobkøretøjer' + }, + menu = { + bus_header = 'Busser', + bus_close = '⬅ Luk menu' + } +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +}) diff --git a/resources/[qb]/[qb_jobs]/qb-busjob/server/main.lua b/resources/[qb]/[qb_jobs]/qb-busjob/server/main.lua new file mode 100644 index 0000000..4040545 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-busjob/server/main.lua @@ -0,0 +1,28 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +function NearBus(src) + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + for _, v in pairs(Config.NPCLocations.Locations) do + local dist = #(coords - vector3(v.x,v.y,v.z)) + if dist < 20 then + return true + end + end +end + +RegisterNetEvent('qb-busjob:server:NpcPay', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local Payment = math.random(15, 25) + if Player.PlayerData.job.name == "bus" then + if NearBus(src) then + local randomAmount = math.random(1, 5) + local r1, r2 = math.random(1, 5), math.random(1, 5) + TriggerClientEvent('qb-jobselector:addxp:client', 30) + if randomAmount == r1 or randomAmount == r2 then Payment = Payment + math.random(10, 20) end + Player.Functions.AddMoney('cash', Payment) + TriggerClientEvent('qb-jobselector:addxp:client', 50) -- 100 is amount of exp + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/client/client.lua b/resources/[qb]/[qb_jobs]/qb-deliveries/client/client.lua new file mode 100644 index 0000000..7b7a2f7 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-deliveries/client/client.lua @@ -0,0 +1,422 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local InStartOption = nil +local InShopOption = nil +local collected = false +local pedinveh = false +local GotJob = false +local prop = nil +local PackageDelivered = false +local deliveredboxes = 0 +local InReturn = nil +local VehicleReturned = false +local data = {} +local PlayerJob = {} +local Zone +local ReturnZone + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + PlayerJob = QBCore.Functions.GetPlayerData().job +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function() + PlayerJob = QBCore.Functions.GetPlayerData().job +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() == resourceName then + PlayerJob = QBCore.Functions.GetPlayerData().job + end +end) + +CreateThread(function() + PedBlip = AddBlipForCoord(Config.JobPedLocation) + SetBlipSprite(PedBlip, 304) + SetBlipColour(PedBlip, 32) + SetBlipAsShortRange(PedBlip, true) + SetBlipScale(PedBlip, 0.5) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Config.JobBlipName) + EndTextCommandSetBlipName(PedBlip) + QBCore.Functions.LoadModel(Config.JobPed) + local startloc = Config.JobPedLocation + local ped = CreatePed(0, Config.JobPed, startloc.x, startloc.y, startloc.z-1.0, startloc.w, false, false) + TaskStartScenarioInPlace(ped, 'WORLD_HUMAN_CLIPBOARD', true) + FreezeEntityPosition(ped, true) + SetEntityInvincible(ped, true) + SetBlockingOfNonTemporaryEvents(ped, true) + + if Config.Interaction == 'target' then + if PlayerJob.name == Config.JobName then + exports['qb-target']:AddTargetEntity(ped, { + options = { + { + icon = 'fas fa-circle', + label = 'Gå på arbejde', + canInteract = function() + if not GotJob then return true end + return false + end, + action = function() + Checkin() + end, + }, + { + icon = 'fas fa-circle', + label = 'Få løn', + canInteract = function() + if VehicleReturned then return true end + return false + end, + action = function() + JobFinish() + end, + }, + { + type = 'client', + icon = 'fas fa-circle', + label = 'Returner køretøj', + event = 'kevin-deliveries:Return', + canInteract = function() + if PackageDelivered then return true end + return false + end, + }, + }, + distance = 2.0 + }) + end + end +end) + +RegisterNetEvent('kevin-deliveries:start', function () + Checkin() +end) + +RegisterNetEvent('kevin-deliveries:finish', function () + JobFinish() +end) + +function Checkin() + if Config.JobNeeded == 'true' then + if PlayerJob.name == Config.JobName then + if Config.UseCoolDown == 'true' then + QBCore.Functions.TriggerCallback("kevin-deliveries:coolc",function(isCooldown) + if not isCooldown then + if not GotJob then + StartRun() + end + else + QBCore.Functions.Notify("Der er ikke flere leveringer, kom tilbage senere", 'error') + end + end) + else + if not GotJob then + StartRun() + end + end + end + else + if Config.UseCoolDown == 'true' then + QBCore.Functions.TriggerCallback("kevin-deliveries:coolc",function(isCooldown) + if not isCooldown then + if not GotJob then + StartRun() + end + else + QBCore.Functions.Notify("Der er ikke flere leveringer, kom tilbage senere", 'error') + end + end) + else + if not GotJob then + StartRun() + end + end + end +end + +function SetTrunkItemInfo() + local items = {} + for k, item in pairs(Config.TrunkItems) do + local itemInfo = QBCore.Shared.Items[item.name:lower()] + items[item.slot] = { + name = itemInfo['name'], + amount = givenboxes, + info = item.info, + label = itemInfo['label'], + description = itemInfo['description'] and itemInfo['description'] or '', + weight = itemInfo['weight'], + type = itemInfo['type'], + unique = itemInfo['unique'], + useable = itemInfo['useable'], + image = itemInfo['image'], + slot = item.slot, + } + end + Config.TrunkItems = items +end + +function StartRun() + local vehspawn = Config.VehicleSpawn + givenboxes = Config.Packages + if not IsAnyVehicleNearPoint(vehspawn.x, vehspawn.y, vehspawn.z, 3.0) then + GotJob = true + data = Config.ShopLocations[math.random(#Config.ShopLocations)] + TriggerEvent('qb-phone:client:CustomNotification', 'NUVÆRRENDE JOB', 'Du fik '..givenboxes..' pakker der skal leveres', 'fas fa-truck', '#83a9f7', 5500) + QBCore.Functions.LoadModel('mule2') + JobVeh = CreateVehicle('mule2', vehspawn.x, vehspawn.y, vehspawn.z, vehspawn.w, true, true) + SetVehicleLivery(JobVeh, data.VehicleLivery) + SetVehicleDirtLevel(JobVeh, 0) + exports['qb-fuel']:SetFuel(JobVeh, 100) + TaskWarpPedIntoVehicle(PlayerPedId(), JobVeh, -1) + SetTrunkItemInfo() + TriggerEvent('vehiclekeys:client:SetOwner', GetVehicleNumberPlateText(JobVeh)) + SetVehicleEngineOn(JobVeh, true, true, false) + SetVehicleDoorsLocked(JobVeh, 1) + + TriggerServerEvent('kevin-delivery:server:addTrunkItems', QBCore.Functions.GetPlate(JobVeh), Config.TrunkItems) + TriggerServerEvent("kevin-deliveries:coolout") + else + QBCore.Functions.Notify('Køretøj blokerer garagen', 'error') + end + + if DoesEntityExist(JobVeh) and not pedinveh then + Wait(2500) + local dest = data.Zone[math.random(#data.Zone)] + DestBlip = AddBlipForCoord(dest.x, dest.y, dest.y) + SetBlipSprite(DestBlip, 304) + SetBlipColour(DestBlip, 32) + SetBlipRoute(DestBlip, true) + SetBlipRouteColour(DestBlip, 32) + SetBlipAsShortRange(DestBlip, false) + SetBlipScale(DestBlip, 0.75) + pedinveh = true + Deliver(dest) + end +end + +CreateThread(function() + while true do + if GotJob then + QBCore.Functions.TriggerCallback('kevin-deliveries:hasPackage', function(Package) + local ped = PlayerPedId() + local boxhash = data.BoxModel[math.random(#data.BoxModel)] + if Package then + if prop == nil then + HasBox = true + CarryAnimation() + prop = CreateObject(boxhash, 0, 0, 0, true, true, true) + AttachEntityToEntity(prop, ped, GetPedBoneIndex(ped, 0xEB95), 0.075, -0.10, 0.255, -130.0, 105.0, 0.0, true, true, false, false, 0, true) + DisableControls() + end + else + if prop ~= nil then + DeleteEntity(prop) + HasBox = false + prop = nil + ClearPedTasks(ped) + end + end + end) + end + Wait(1000) + end +end) + +function DisableControls() + while true do + if HasBox then + DisableControlAction(0, 21, true ) -- sprinting + DisableControlAction(0, 22, true) -- Jumping + end + Wait(1) + end +end + +function CarryAnimation() + LoadAnim('anim@heists@box_carry@') + TaskPlayAnim(PlayerPedId(), 'anim@heists@box_carry@', 'idle', 6.0, -6.0, -1, 49, 0, 0, 0, 0) + CreateThread( function () + while HasBox do + if not IsEntityPlayingAnim(PlayerPedId(), 'anim@heists@box_carry@', 'idle', 3) then + TaskPlayAnim(PlayerPedId(), 'anim@heists@box_carry@', 'idle', 6.0, -6.0, -1, 49, 0, 0, 0, 0) + end + Wait(1000) + end + end) +end + +function LoadAnim(dict) + while not HasAnimDictLoaded(dict) do + RequestAnimDict(dict) + Wait(1) + end +end + +function Deliver(dest) + if GotJob then + if Config.Interaction == 'target' then + exports['qb-target']:AddBoxZone('BoxZoneName', vector3(dest.x, dest.y, dest.z), 3.5, 2.0, { + name='BoxZoneName', + heading= dest.w, + debugPoly= false, + -- minZ = 6.04, + -- maxZ = 7.64, + }, { + options = { + { + type = 'client', + event = 'kevin-deliveries:Deliver', + icon = 'fas fa-circle', + label = 'Aflever pakke', + canInteract = function() + if not PackageDelivered and HasBox then return true end + return false + end, + }, + }, + distance = 2.0 + }) + elseif Config.Interaction == 'radialmenu' then + Zone = BoxZone:Create(vector3(dest.x, dest.y, dest.y), 3.5, 2.0, { + heading = dest.w, + name = 'Shop', + debugPoly = false, + -- minZ = 53.64, + -- maxZ = 56.24 + }) + Zone:onPlayerInOut(function(isPointInside) + if isPointInside and not PackageDelivered then + if HasBox then + InShopOption = exports['qb-radialmenu']:AddOption({ + id = 'deliver-package', + title = 'Lever', + icon = 'box', + type = 'client', + event = 'kevin-deliveries:Deliver', + shouldClose = true + }, InShopOption) + --print('option added') + end + else + if InShopOption ~= nil then + exports['qb-radialmenu']:RemoveOption(InShopOption) + InShopOption = nil + --print('option removed') + end + end + end) + end + end +end + +RegisterNetEvent('kevin-deliveries:Deliver', function () + if not PackageDelivered then + deliveredboxes = deliveredboxes + 1 + --print(deliveredboxes) + TriggerServerEvent('kevin-deliveries:RemovePackage') + TriggerEvent('qb-phone:client:CustomNotification', 'NUVÆRRENDE JOB', deliveredboxes..' / '.. givenboxes..' pakker leveret', 'fas fa-truck', '#83a9f7', 5500) + + if deliveredboxes == givenboxes then + PackageDelivered = true + Wait(2000) + TriggerEvent('qb-phone:client:CustomNotification', 'OPGAVE KLARET', givenboxes..' pakker leveret', 'fas fa-truck', '#83a9f7', 5500) + Wait(2000) + TriggerEvent('qb-phone:client:CustomNotification', 'NUVÆRRENDE JOB', 'Kør tilbage til depottet og parker bilen!', 'fas fa-truck', '#83a9f7', 5500) + --print('no more packages') + RemoveBlip(DestBlip) + Return() + end + else + QBCore.Functions.Notify('You have no more packages', 'error', 5000) + end +end) + +function Return() + local Retarea = Config.VehicleReturnCoords + RetBlip = AddBlipForCoord(Retarea.x, Retarea.y, Retarea.y) + SetBlipSprite(RetBlip, 50) + SetBlipColour(RetBlip, 32) + SetBlipRoute(RetBlip, true) + SetBlipRouteColour(RetBlip, 32) + SetBlipAsShortRange(RetBlip, false) + SetBlipScale(RetBlip, 0.75) + + ReturnZone = BoxZone:Create(vector3(Retarea.x, Retarea.y, Retarea.y), 10.5, 35.0, { + heading = Retarea.w, + name = 'Shop', + debugPoly = false, + -- minZ = 53.64, + -- maxZ = 56.24 + }) + ReturnZone:onPlayerInOut(function(isPointInside) + if isPointInside and PackageDelivered then + InReturn = exports['qb-radialmenu']:AddOption({ + id = 'deliver-package', + title = 'Parker', + icon = 'truck', + type = 'client', + event = 'kevin-deliveries:Return', + shouldClose = true + }, InReturn) + else + if InReturn ~= nil then + exports['qb-radialmenu']:RemoveOption(InReturn) + InReturn = nil + end + end + end) +end + +RegisterNetEvent('kevin-deliveries:Return', function() + if Config.Interaction == 'target' then + doreturn() + elseif Config.Interaction == 'radialmenu' then + if DoesEntityExist(JobVeh) and IsPedInVehicle(PlayerPedId(), JobVeh, true) then + doreturn() + else + QBCore.Functions.Notify('Du er ikke i et køretøj', 'error') + end + end +end) + +function doreturn() + QBCore.Functions.DeleteVehicle(JobVeh) + Wait(1000) + RemoveBlip(RetBlip) + TriggerEvent('qb-phone:client:CustomNotification', 'NUVÆRRENDE JOB', 'Kør tilbage til depottet og parker bilen!', 'fas fa-truck', '#83a9f7', 5500) + VehicleReturned = true +end + +function JobFinish() + if Config.Interaction == 'target' then + TriggerServerEvent('kevin-deliveries:Payouts', data) + TriggerEvent('qb-phone:client:CustomNotification', 'OPGAVE KLARET', 'Hop ind i køretøjer og få leveret nogler pakker!', 'fas fa-truck', '#83a9f7', 5500) + InShopOption = nil + pedinveh = false + GotJob = false + prop = nil + PackageDelivered = false + deliveredboxes = 0 + InReturn = nil + VehicleReturned = false + deliveredboxes = 0 + elseif Config.Interaction == 'radialmenu' then + if not collected then + Zone:destroy() + ReturnZone:destroy() + TriggerServerEvent('kevin-deliveries:Payouts', data) + TriggerEvent('qb-phone:client:CustomNotification', 'OPGAVE KLARET', 'Hop ind i køretøjer og få leveret nogler pakker!', 'fas fa-truck', '#83a9f7', 5500) + InShopOption = nil + pedinveh = false + GotJob = false + prop = nil + PackageDelivered = false + deliveredboxes = 0 + InReturn = nil + VehicleReturned = false + deliveredboxes = 0 + collected = true + end + end +end \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/config.lua b/resources/[qb]/[qb_jobs]/qb-deliveries/config.lua new file mode 100644 index 0000000..844e608 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-deliveries/config.lua @@ -0,0 +1,90 @@ +Config = Config or {} + +Config.Interaction = 'target' --- target/radialmenu for the job interaction that you want + +Config.UseCoolDown = 'true' -- true/false +Config.CoolDown = 1500 * 1000 --- Cooldown until can start next job, default its 25 minutes + +Config.JobNeeded = 'true' -- if you need a specific job to do the deliveries true/false +Config.JobName = 'delivery' -- Job needed to do the deliveries if the config above is set to true +Config.JobPed = 's_m_m_ups_01' -- Model of the starting ped +Config.JobPedLocation = vector4(-429.53, -2786.3, 6.0, 53.77) -- Where the starting ped is +Config.JobBlipName = "UBS" -- Blip of where the starting ped is + +Config.VehicleSpawn = vector4(-445.69, -2789.91, 5.39, 43.89) -- Spot the vehicle spawns + +Config.Packages = math.random(5, 9) -- random amount of packages given for delivery +Config.TrunkItems = { + [1] = { + name = "delivery-box",-- Item name in the core shared + info = {}, + type = "item", + slot = 1, + }, +} +Config.VehicleReturnCoords = vector4(-454.36, -2799.81, 5.39, 44.51) -- area where to return vehicle +Config.PaymentMethod = 'bank' -- cash/bank + +Config.ShopLocations = { + [1] = { + Zone = {--- 24/7 Locations + vector4(24.47, -1346.62, 29.5, 271.66), + vector4(-3039.54, 584.38, 7.91, 17.27), + vector4(-3242.97, 1000.01, 12.83, 357.57), + vector4(1728.07, 6415.63, 35.04, 242.95), + vector4(1959.82, 3740.48, 32.34, 301.57), + vector4(549.13, 2670.85, 42.16, 99.39), + vector4(2677.47, 3279.76, 55.24, 335.08), + vector4(2556.66, 380.84, 108.62, 356.67), + vector4(372.66, 326.98, 103.57, 253.73), + }, + VehicleLivery = 11, -- livery the vehicle will spawn with for the location + BoxModel = { + `prop_cs_cardbox_01`, -- Props that spawn in the player hands when package is in the inventory, not all fit on ped(hands) properly so pick and choose lol https://forge.plebmasters.de/ + `prop_cardbordbox_02a`, + }, + Payment = math.random(450, 800) -- self explanatory + }, + [2] = { + Zone = { --- Youtool/ Hardware Locations + vector4(45.68, -1749.04, 29.61, 53.13), + vector4(2747.71, 3472.85, 55.67, 255.08), + vector4(-421.83, 6136.13, 31.88, 228.2), + }, + VehicleLivery = 7, + BoxModel = { + `v_ind_meatboxsml_02`, + `v_ind_meatboxsml`, + `prop_cs_cardbox_01`, + `prop_cardbordbox_02a`, + `v_ind_cs_toolbox3`, + `prop_tool_box_01` + }, + Payment = math.random(450, 800) + }, + [3] = { + Zone = { --- Ammunation Locations + vector4(-661.96, -933.53, 21.83, 177.05), + vector4(809.68, -2159.13, 29.62, 1.43), + vector4(1692.67, 3761.38, 34.71, 227.65), + vector4(-331.23, 6085.37, 31.45, 228.02), + vector4(253.63, -51.02, 69.94, 72.91), + vector4(23.0, -1105.67, 29.8, 162.91), + vector4(2567.48, 292.59, 108.73, 349.68), + vector4(-1118.59, 2700.05, 18.55, 221.89), + vector4(841.92, -1035.32, 28.19, 1.56), + vector4(-1304.19, -395.12, 36.7, 75.03), + vector4(-3173.31, 1088.85, 20.84, 244.18), + }, + VehicleLivery = 7, + BoxModel = { + `prop_drop_crate_01`, + `ba_prop_battle_case_sm_03`, + `ba_prop_battle_rsply_crate_02a`, + `v_ind_cs_toolbox3`, + `prop_box_ammo04a`, + `prop_box_ammo06a`, + }, + Payment = math.random(450, 800) + }, +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-deliveries/fxmanifest.lua new file mode 100644 index 0000000..3a66060 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-deliveries/fxmanifest.lua @@ -0,0 +1,23 @@ +fx_version 'cerulean' +game 'gta5' + +shared_script { + 'config.lua', +} + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/EntityZone.lua', + '@PolyZone/CircleZone.lua', + '@PolyZone/ComboZone.lua', + 'client/*.lua', +} + +server_scripts { + 'server/*.lua' +} + +lua54 'yes' + +dependency '/assetpacks' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/images/delivery-package.png b/resources/[qb]/[qb_jobs]/qb-deliveries/images/delivery-package.png new file mode 100644 index 0000000..772af98 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/qb-deliveries/images/delivery-package.png differ diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/readme.md b/resources/[qb]/[qb_jobs]/qb-deliveries/readme.md new file mode 100644 index 0000000..6af98a8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-deliveries/readme.md @@ -0,0 +1,47 @@ +# If you use any custom maps for the shops For example Gabz Ammunation and you had to change the location from default qb-shops location be sure to change the vectors/coords to match as be default the script uses default qb-shops locations. + +# DEPENDENCIES (MUST HAVE IN YOUR SERVER FOR EVERYTHING TO WORK PROPERLY) + +* qbcore (latest version or any of the newer version once its not on old core) +* qb-target +* qb-menu +* qb-radialmenu (the edited version i have on the video can be found in my discord FOR FREE if you want the one i used) +* qb-phone (the edited version i have on the video can be found in my discord FOR FREE if you want the one i used) +* polyzone +* Vehicle (free) https://www.gta5-mods.com/vehicles/maibatsu-mule-mapped-edition-add-on-replace-template + +# To easyly get the vehicle if you do not know how to get the vehicle to load in your game got to the link below and paste the link above in the page and it will download the folder for you and all you need to do is drop the folder into your resources/vehicle resource folder or what have you +* https://gta5mods.hk416.org/en + +# INSTALLING + +* Drop the kevin-deliveries folder into your resource be sure that the resource name is "kevin-deliveries" and nothing else +* Copy the image inside the images folder and paste it into you inventory> html> images folder +* Paste the snippet below in you qb-core>shared>items.lua +```lua + ["delivery-box"] = {["name"] = "delivery-box", ["label"] = "Delivery Package", ["weight"] = 50000, ["type"] = "item", ["image"] = "delivery-box.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 1.0 }, +``` + +# If you want it to be using a specifc job if the config is set to true then add the snip below to qb-core > shared > job.lua +```lua + ['delivery'] = { + label = 'Kevin Deliveries', --- change if you like + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Delivery Driver', + payment = 50 + }, + }, + }, +``` + +# By default you might have to get into the vehicle trunk at the side so to fix that issue please refer to the link below +* https://github.com/qbcore-framework/qb-inventory/pull/292/commits/0e4996fc3071a6757fa668186defaa236d214c7a + +# Any problems please join my discord +Discord: https://discord.gg/SCnKXKN7cA + + + diff --git a/resources/[qb]/[qb_jobs]/qb-deliveries/server/server.lua b/resources/[qb]/[qb_jobs]/qb-deliveries/server/server.lua new file mode 100644 index 0000000..e1e3320 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-deliveries/server/server.lua @@ -0,0 +1,55 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local CoolDown = false + +RegisterNetEvent("kevin-delivery:server:addTrunkItems", function(plate, items) exports["ps-inventory"]:addTrunkItems(plate, items) end) +RegisterServerEvent('kevin-deliveries:coolout', function() + CoolDown = true + local timer = Config.CoolDown + while timer > 0 do + Wait(1000) + timer = timer - 1000 + if timer == 0 then + CoolDown = false + end + end +end) + +QBCore.Functions.CreateCallback("kevin-deliveries:coolc",function(source, cb) + if CoolDown then + cb(true) + else + cb(false) + end +end) + +QBCore.Functions.CreateCallback('kevin-deliveries:hasPackage', function(source, cb) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local hasPackage = Player.Functions.GetItemByName("delivery-box") + if hasPackage then + cb(true) + else + cb(false) + end +end) + +RegisterServerEvent('kevin-deliveries:RemovePackage', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + Player.Functions.RemoveItem("delivery-box", 1, false) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items["delivery-box"], "remove") + Wait(2500) +end) + +RegisterServerEvent('kevin-deliveries:Payouts', function(data) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local job = Player.PlayerData.job.name + local pay = data.Payment + + if job == Config.JobName then + Player.Functions.AddMoney(Config.PaymentMethod, pay, 'UBS Indbetaling') + Wait(2500) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-djbooth/README.md b/resources/[qb]/[qb_jobs]/qb-djbooth/README.md new file mode 100644 index 0000000..c4b9328 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-djbooth/README.md @@ -0,0 +1,28 @@ +# qb-djbooth +Play music on configured coords! + +## Dependencies +* [xsound](https://github.com/Xogy/xsound) +* [PolyZone](https://github.com/qbcore-framework/PolyZone) +* [qb-menu](https://github.com/qbcore-framework/qb-menu) + +## Preview +![unknown (12)](https://user-images.githubusercontent.com/57848836/139512432-729dbcff-d6b1-49b7-9bc3-e82c163c8621.png) + +# License + + QBCore Framework + Copyright (C) 2021 Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see diff --git a/resources/[qb]/[qb_jobs]/qb-djbooth/client.lua b/resources/[qb]/[qb_jobs]/qb-djbooth/client.lua new file mode 100644 index 0000000..f5bacb8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-djbooth/client.lua @@ -0,0 +1,161 @@ +-- Variables + +local QBCore = exports['qb-core']:GetCoreObject() +local currentZone = nil +local PlayerData = {} + +-- Handlers + +AddEventHandler('onResourceStart', function(resourceName) + if (GetCurrentResourceName() ~= resourceName) then return end + PlayerData = QBCore.Functions.GetPlayerData() +end) + +AddEventHandler('QBCore:Client:OnPlayerLoaded', function() + PlayerData = QBCore.Functions.GetPlayerData() +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + PlayerData.job = JobInfo +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + PlayerData = {} +end) + +-- Static Header + +local musicHeader = { + { + header = 'Spil musik!', + params = { + event = 'qb-djbooth:client:playMusic' + } + } +} + +-- Main Menu + +function createMusicMenu() + musicMenu = { + { + isHeader = true, + header = '💿 | DJ bås' + }, + { + header = '🎶 | Spil en sang', + txt = 'Youtube URL', + params = { + event = 'qb-djbooth:client:musicMenu', + args = { + zoneName = currentZone + } + } + }, + { + header = '⏸️ | Pause Musik', + txt = 'Pause musikken', + params = { + isServer = true, + event = 'qb-djbooth:server:pauseMusic', + args = { + zoneName = currentZone + } + } + }, + { + header = '▶️ | Start musik', + txt = 'Start musikken', + params = { + isServer = true, + event = 'qb-djbooth:server:resumeMusic', + args = { + zoneName = currentZone + } + } + }, + { + header = '🔈 | Skift Volume', + txt = 'Skift musik volumen', + params = { + event = 'qb-djbooth:client:changeVolume', + args = { + zoneName = currentZone + } + } + }, + { + header = '❌ | Sluk musik', + txt = 'Sluk musikken', + params = { + isServer = true, + event = 'qb-djbooth:server:stopMusic', + args = { + zoneName = currentZone + } + } + } + } +end + +-- DJ Booths + +local vanilla = BoxZone:Create(Config.Locations['vanilla'].coords, 1, 1, { + name="vanilla", + heading=0 +}) + +vanilla:onPlayerInOut(function(isPointInside) + if isPointInside and PlayerData.job.name == Config.Locations['vanilla'].job then + currentZone = 'vanilla' + exports['qb-menu']:showHeader(musicHeader) + else + currentZone = nil + exports['qb-menu']:closeMenu() + end +end) + +-- Events + +RegisterNetEvent('qb-djbooth:client:playMusic', function() + createMusicMenu() + exports['qb-menu']:openMenu(musicMenu) +end) + +RegisterNetEvent('qb-djbooth:client:musicMenu', function() + local dialog = exports['qb-input']:ShowInput({ + header = 'Sang valg', + submitText = "Send", + inputs = { + { + type = 'text', + isRequired = true, + name = 'sang', + text = 'YouTube URL' + } + } + }) + if dialog then + if not dialog.song then return end + TriggerServerEvent('qb-djbooth:server:playMusic', dialog.song, currentZone) + end +end) + +RegisterNetEvent('qb-djbooth:client:changeVolume', function() + local dialog = exports['qb-input']:ShowInput({ + header = 'Musik Volume', + submitText = "Gen", + inputs = { + { + type = 'text', -- number doesn't accept decimals?? + isRequired = true, + name = 'Volume', + text = 'Min: 0.01 - Max: 1' + } + } + }) + if dialog then + if not dialog.volume then return end + TriggerServerEvent('qb-djbooth:server:changeVolume', dialog.volume, currentZone) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-djbooth/config.lua b/resources/[qb]/[qb_jobs]/qb-djbooth/config.lua new file mode 100644 index 0000000..bd7b1d8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-djbooth/config.lua @@ -0,0 +1,12 @@ +Config = {} + +Config.DefaultVolume = 0.5 -- Accepted values are 0.01 - 1 + +Config.Locations = { + ['vanilla'] = { + ['job'] = 'vanilla', -- Required job to use booth + ['radius'] = 30, -- The radius of the sound from the booth + ['coords'] = vector3(120.52, -1281.5, 29.48), -- Where the booth is located + ['playing'] = false + } +} diff --git a/resources/[qb]/[qb_jobs]/qb-djbooth/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-djbooth/fxmanifest.lua new file mode 100644 index 0000000..88766d8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-djbooth/fxmanifest.lua @@ -0,0 +1,22 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-DJBOOTH' +version '1.0.0' + +shared_script 'config.lua' + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/EntityZone.lua', + '@PolyZone/CircleZone.lua', + '@PolyZone/ComboZone.lua', + 'client.lua' +} + +server_script 'server.lua' + +dependency 'xsound' + +lua54 'yes' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-djbooth/server.lua b/resources/[qb]/[qb_jobs]/qb-djbooth/server.lua new file mode 100644 index 0000000..bd7ef76 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-djbooth/server.lua @@ -0,0 +1,70 @@ +local xSound = exports.xsound + +RegisterNetEvent('qb-djbooth:server:playMusic', function(song, zoneName) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local boothCoords = Config.Locations[zoneName].coords + local dist = #(coords - boothCoords) + if dist > 3 then return end + xSound:PlayUrlPos(-1, zoneName, song, Config.DefaultVolume, coords) + xSound:Distance(-1, zoneName, Config.Locations[zoneName].radius) + Config.Locations[zoneName].playing = true + TriggerClientEvent('qb-djbooth:client:playMusic', src) +end) + +RegisterNetEvent('qb-djbooth:server:stopMusic', function(data) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local boothCoords = Config.Locations[data.zoneName].coords + local dist = #(coords - boothCoords) + if dist > 3 then return end + if Config.Locations[data.zoneName].playing then + Config.Locations[data.zoneName].playing = false + xSound:Destroy(-1, data.zoneName) + end + TriggerClientEvent('qb-djbooth:client:playMusic', src) +end) + +RegisterNetEvent('qb-djbooth:server:pauseMusic', function(data) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local boothCoords = Config.Locations[data.zoneName].coords + local dist = #(coords - boothCoords) + if dist > 3 then return end + if Config.Locations[data.zoneName].playing then + Config.Locations[data.zoneName].playing = false + xSound:Pause(-1, data.zoneName) + end + TriggerClientEvent('qb-djbooth:client:playMusic', src) +end) + +RegisterNetEvent('qb-djbooth:server:resumeMusic', function(data) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local boothCoords = Config.Locations[data.zoneName].coords + local dist = #(coords - boothCoords) + if dist > 3 then return end + if not Config.Locations[data.zoneName].playing then + Config.Locations[data.zoneName].playing = true + xSound:Resume(-1, data.zoneName) + end + TriggerClientEvent('qb-djbooth:client:playMusic', src) +end) + +RegisterNetEvent('qb-djbooth:server:changeVolume', function(volume, zoneName) + local src = source + local ped = GetPlayerPed(src) + local coords = GetEntityCoords(ped) + local boothCoords = Config.Locations[zoneName].coords + local dist = #(coords - boothCoords) + if dist > 3 then return end + if not tonumber(volume) then return end + if Config.Locations[zoneName].playing then + xSound:setVolume(-1, zoneName, volume) + end + TriggerClientEvent('qb-djbooth:client:playMusic', src) +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/LICENSE b/resources/[qb]/[qb_jobs]/qb-frontdesk/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/README.md b/resources/[qb]/[qb_jobs]/qb-frontdesk/README.md new file mode 100644 index 0000000..9db03e3 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/README.md @@ -0,0 +1,16 @@ +![Redline Studios Banner](https://i.imgur.com/VFEXnGd.png) +# Redline Studios Discord: +https://discord.gg/RCU9XEvnsE + +## Front Desk + +## Install +- place qb-frontdesk in [qb] folder +- Launch your Server +- Head to Mission Row PD and third eye the front desk, the menu will appear. + + +## Previews + +![1](https://i.imgur.com/4ZdMQWa.png) +![2](https://i.imgur.com/HuVIfgB.png) diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/client/cl_main.lua b/resources/[qb]/[qb_jobs]/qb-frontdesk/client/cl_main.lua new file mode 100644 index 0000000..c00229c --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/client/cl_main.lua @@ -0,0 +1,333 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local CurrentCops = 0 +local closestDesk = nil +local CurrentCops = 0 +local doctorCount = 0 +local PlayerData = QBCore.Functions.GetPlayerData() +local PlayerJob = QBCore.Functions.GetPlayerData().job + +-- Front Desk Target Zones +local function FrontDeskZones() + for k, v in pairs(Config.Locations) do + exports['qb-target']:AddBoxZone(v.Zone.name, v.Zone.coords, v.Zone.length, v.Zone.width, { + name = v.Zone.name, + debugPoly = Config.Debug, + heading = v.Zone.heading, + minZ = v.Zone.minZ, + maxZ = v.Zone.maxZ, + }, { + options = { + { + type = "client", + action = function() + TriggerEvent("qb-frontdesk:client:OpenFrontDesk", closestDesk) + end, + icon = "fas fa-desktop", + label = "Reception", + }, + }, + distance = 2.0 + }) + end +end + +-- Gets closest front desk to pass the correct data +CreateThread(function() + while true do + Wait(100) + for k in pairs(Config.Locations) do + local Pos = GetEntityCoords(PlayerPedId()) + local Distance = #(Pos - vector3(Config.Locations[k].Zone.coords.x,Config.Locations[k].Zone.coords.y,Config.Locations[k].Zone.coords.z)) + if Distance < 5 then + closestDesk = k + + if Config.Debug then + print(closestDesk) + end + else + Wait(100) + end + end + end +end) + +-- Front Desk Menu +RegisterNetEvent('qb-frontdesk:client:OpenFrontDesk',function(job) + if PlayerJob.name == job then + local FrontDeskMenu = { + { + header = Config.Locations[job].Zone.name, + isMenuHeader = true, + }, + { + header = 'Gå på arbejde/Gå hjem', + icon = 'fas fa-power-off', + params = { + event = 'qb-frontdesk:client:ToggleDuty', + args = job + } + }, + { + header = 'Assistance Menu', + icon = 'fas fa-hand-holding-heart', + params = { + event = 'qb-frontdesk:client:OpenAssistanceMenu', + args = job + } + }, + { + header = 'Luk Menu', + icon = 'fas fa-x', + }, + } + exports['qb-menu']:openMenu(FrontDeskMenu) + else + local FrontDeskMenu = { + { + header = Config.Locations[job].Zone.name, + isMenuHeader = true, + }, + { + header = 'Assistance Menu', + icon = 'fas fa-hand-holding-heart', + params = { + event = 'qb-frontdesk:client:OpenAssistanceMenu', + args = job + } + }, + { + header = 'Luk Menu', + icon = 'fas fa-x', + }, + } + exports['qb-menu']:openMenu(FrontDeskMenu) + end +end) + +-- Toggle Duty Event +RegisterNetEvent('qb-frontdesk:client:ToggleDuty',function(job) + if job == 'police' then + TriggerEvent('qb-policejob:ToggleDuty') + elseif job == 'ambulance' then + TriggerEvent('EMSToggle:Duty') + else + TriggerServerEvent("QBCore:ToggleDuty") + end +end) + +-- Assistance Menu +RegisterNetEvent('qb-frontdesk:client:OpenAssistanceMenu',function(job) + local AssistanceMenu = {} + AssistanceMenu[#AssistanceMenu + 1] = { + header = 'Assistance Menu', + txt = 'Vælg en valgmulighed', + icon = 'fas fa-code', + isMenuHeader = true, + } + + for r, s in pairs(Config.Locations[job].Menu) do + AssistanceMenu[#AssistanceMenu + 1] = { + header = s.Header, + txt = s.Txt, + icon = s.Icon, + params = { + event = s.Event, + args = { + type = s.Args, + job = job + } + } + } + end + + AssistanceMenu[#AssistanceMenu + 1] = { + header = 'Tilbage', + icon = 'fas fa-arrow-left-long', + params = { + event = 'qb-frontdesk:client:OpenFrontDesk' + } + } + + exports['qb-menu']:openMenu(AssistanceMenu) +end) + +-- Request Assistance Event +RegisterNetEvent('qb-frontdesk:client:RequestAssistance',function(data) + QBCore.Functions.TriggerCallback('qb-frontdesk:server:CooldownCheck', function(alert) + if alert then + if Config.Dispatch == "default" then + if data.job == 'police' then + if CurrentCops >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + TriggerServerEvent('police:server:policeAlert', 'Assistance nødvendig') + elseif data.type == "weaponlicense" then + TriggerServerEvent('police:server:policeAlert', 'Våben licens anmodning') + elseif data.type == "interview" then + TriggerServerEvent('police:server:policeAlert', 'Interview anmodning') + elseif data.type == "supervisor" then + TriggerServerEvent('police:server:policeAlert', 'Leder anmodning') + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok betjente på arbejde!', 'error', 3000) + end + elseif data.job == 'ambulance' then + if doctorCount >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + TriggerServerEvent('hospital:server:ambulanceAlert', 'Assistance nødvendig') + elseif data.type == "interview" then + TriggerServerEvent('hospital:server:ambulanceAlert', 'Interview anmodning') + elseif data.type == "supervisor" then + TriggerServerEvent('hospital:server:ambulanceAlert', 'Leder anmodning') + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok læger på arbejde!', 'error', 3000) + end + end + elseif Config.Dispatch == "ps-dispatch" then + local PlayerData = QBCore.Functions.GetPlayerData() + local coords = GetEntityCoords(PlayerPedId()) + if data.job == 'police' then + if CurrentCops >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['police'].Zone.coords, job = { 'police' }, message = "Assistance anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Assistance anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + elseif data.type == "weaponlicense" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['police'].Zone.coords, job = { 'police' }, message = "Våben licens anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Våben licens anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + elseif data.type == "interview" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['police'].Zone.coords, job = { 'police' }, message = "Interview anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Interview anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + elseif data.type == "supervisor" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['police'].Zone.coords, job = { 'police' }, message = "Leder anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Leder anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok betjente på arbejde!', 'error', 3000) + end + elseif data.job == 'ambulance' then + if doctorCount >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['ambulance'].Zone.coords, job = { 'ambulance' }, message = "Assistance anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Assistance anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + elseif data.type == "interview" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['ambulance'].Zone.coords, job = { 'ambulance' }, message = "Interview anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Interview anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + elseif data.type == "supervisor" then + exports["ps-dispatch"]:CustomAlert({ coords = Config.Locations['ambulance'].Zone.coords, job = { 'ambulance' }, message = "Leder anmodet", dispatchCode = "10-60", firstStreet = coords, name = PlayerData.charinfo.firstname:sub(1,1):upper()..PlayerData.charinfo.firstname:sub(2).. " ".. PlayerData.charinfo.lastname:sub(1,1):upper()..PlayerData.charinfo.lastname:sub(2), description = "Leder anmodet", radius = 0, sprite = 205, color = 2, scale = 1.0, length = 3, }) + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok læger på arbejde!', 'error', 3000) + end + end + + elseif Config.Dispatch == "cd_dispatch" then + if data.job == 'police' then + if CurrentCops >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'police' }, coords = data.coords, title = '10-60 - Assistance anmodet', message = 'Assistance anmodet i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '114 - Assistance anmodet', time = (5 * 60 * 1000), sound = 1, }, }) + elseif data.type == "weaponlicense" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'police' }, coords = data.coords, title = '10-60 - Våben license anmodning', message = 'Våben license anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '114 - Våben licens anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + elseif data.type == "interview" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'police' }, coords = data.coords, title = '10-60 - Interview anmodning', message = 'Interview anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '114 - Interview anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + elseif data.type == "supervisor" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'police' }, coords = data.coords, title = '10-60 - Leder anmodning', message = 'Leder anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '114 - Leder anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok betjente på arbjede!', 'error', 3000) + end + + elseif data.job == 'ambulance' then + if doctorCount >= Config.Locations[data.job].Required then + QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + if data.type == "assistance" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'ambulance' }, coords = data.coords, title = '10-60 - Assistance anmodet', message = 'Assistance anmodet i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '112 - Assistance anmodet', time = (5 * 60 * 1000), sound = 1, }, }) + elseif data.type == "interview" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'ambulance' }, coords = data.coords, title = '10-60 - Interview anmodning', message = 'Interview anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '112 - Interview anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + elseif data.type == "supervisor" then + local data = exports['cd_dispatch']:GetPlayerInfo() + TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'ambulance' }, coords = data.coords, title = '10-60 - Leder anmodning', message = 'Leder anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '112 - Leder anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + end + TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + else + QBCore.Functions.Notify('Ikke nok læger på arbejde!', 'error', 3000) + end + end + + -- ADD MORE JOBS BELOW + -- DON'T FORGET TO ADD THEM TO YOUR CONFIG AS WELL + + -- elseif data.job == 'mechanic' then + -- if doctorCount >= Config.Locations[data.job].Required then + -- QBCore.Functions.Notify('Du vil få hjælp snarligt!', 'success') + -- if data.type == "assistance" then + -- local data = exports['cd_dispatch']:GetPlayerInfo() + -- TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'mechanic' }, coords = data.coords, title = 'Assitance Required', message = 'Assistance anmodet i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '112 - Assistance anmodet', time = (5 * 60 * 1000), sound = 1, }, }) + -- elseif data.type == "weaponlicense" then + -- local data = exports['cd_dispatch']:GetPlayerInfo() + -- TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'mechanic' }, coords = data.coords, title = 'Upgrade' Request', message = 'Sucker at the front desk', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = 'Someone wanna go fast', time = (5 * 60 * 1000), sound = 1, }, }) + -- elseif data.type == "interview" then + -- local data = exports['cd_dispatch']:GetPlayerInfo() + -- TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'mechanic' }, coords = data.coords, title = '10-60 - Interview Request', message = 'Interview anmodning i reception', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = '112 - Interview anmodning', time = (5 * 60 * 1000), sound = 1, }, }) + -- elseif data.type == "supervisor" then + -- local data = exports['cd_dispatch']:GetPlayerInfo() + -- TriggerServerEvent('cd_dispatch:AddNotification', { job_table = { 'mechanic' }, coords = data.coords, title = 'Karen Alert', message = 'Karen at the Front Desk', flash = 0, unique_id = tostring(math.random(0000000, 9999999)), blip = { sprite = 205, scale = 1.2, colour = 3, flashes = false, text = 'Supervisor Request', time = (5 * 60 * 1000), sound = 1, }, }) + -- end + -- TriggerServerEvent('qb-frontdesk:server:AlertCooldown', data.job, true) + -- else + -- QBCore.Functions.Notify('Not enough doctors on duty!', 'error', 3000) + -- end + -- end + end + else + QBCore.Functions.Notify('Alarm sendt for lidt siden, vent venligst!', 'error', 7500) + end + end, data.job) +end) + +RegisterNetEvent('police:SetCopCount', function(amount) + CurrentCops = amount +end) + +RegisterNetEvent('hospital:client:SetDoctorCount', function(amount) + doctorCount = amount +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + PlayerJob = JobInfo +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + PlayerData = QBCore.Functions.GetPlayerData() + PlayerJob = QBCore.Functions.GetPlayerData().job + FrontDeskZones() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + PlayerData = {} +end) + +AddEventHandler('onResourceStart', function(resource) + if resource == GetCurrentResourceName() then + PlayerData = QBCore.Functions.GetPlayerData() + PlayerJob = QBCore.Functions.GetPlayerData().job + FrontDeskZones() + end +end) + +AddEventHandler('onResourceStop', function(resource) + if resource == GetCurrentResourceName() then + for k, v in pairs(Config.Locations) do + exports['qb-target']:RemoveZone(v.Zone.name) + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-frontdesk/fxmanifest.lua new file mode 100644 index 0000000..03d4237 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/fxmanifest.lua @@ -0,0 +1,20 @@ +fx_version 'cerulean' +game 'gta5' + +version 'V1.0' + +shared_scripts { + '@ox_lib/init.lua', + 'shared/*.lua', +} + +client_script { + 'client/*.lua' +} + +server_scripts { + 'server/*.lua', +} + + +lua54 'yes' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/server/main.lua b/resources/[qb]/[qb_jobs]/qb-frontdesk/server/main.lua new file mode 100644 index 0000000..ee1d4f4 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/server/main.lua @@ -0,0 +1,22 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local serverCooldown = {} + +-- Coldown for each job -- +RegisterServerEvent('qb-frontdesk:server:AlertCooldown', function(job, bool) + if serverCooldown[job] == nil then serverCooldown[job] = false end + if bool then + serverCooldown[job] = true + + SetTimeout((Config.Cooldown * 60000), function() + serverCooldown[job] = false + end) + end +end) + +QBCore.Functions.CreateCallback('qb-frontdesk:server:CooldownCheck',function(source, cb, job) + local src = source + local callback = false + + if not serverCooldown[job] then callback = true end + cb(callback) +end) diff --git a/resources/[qb]/[qb_jobs]/qb-frontdesk/shared/sh_config.lua b/resources/[qb]/[qb_jobs]/qb-frontdesk/shared/sh_config.lua new file mode 100644 index 0000000..8b80ef7 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-frontdesk/shared/sh_config.lua @@ -0,0 +1,41 @@ +Config = {} +Config.Debug = false -- True / False for Debug System +Config.Dispatch = "ps-dispatch" -- 'default' / 'ps-dispatch' / 'cd_dispatch' +Config.PoliceRequired = 0 -- How many PD Officers Required to request +Config.Cooldown = 1 -- Server cooldown for alerts ( Set in minutes ) + +Config.Locations = { + ["police"] = { -- Set this to the name of the job + Required = 1, -- How many players with this job are required to be online to make a request/alert (You'll need to add events that track the amount of players online with that job. Police / Ambulance is setup by default) + Zone = { -- Polyzone Info + name = "MRPD Reception", -- Name of the menu title + coords = vector3(442.68, -984.55, 30.72), -- Boxzone Coords + length = 0.8, width = 0.6, -- Boxzone Length / Width + heading = 185.54, -- Boxzone Heading + minZ = 30.49, -- Boxzone MinZ + maxZ = 31.29 -- Boxzone MaxZ + }, + Menu = { -- Menu Info ( Set Header, Text, Icon, Event, and Event Type ) + [1] = { Header = 'Assistance', Txt = '', Icon = 'fas fa-hand', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'assistance' }, + [2] = { Header = 'Våben licens', Txt = '', Icon = 'fas fa-gun', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'weaponlicense' }, + [3] = { Header = 'Interview', Txt = '', Icon = 'fas fa-people-arrows-left-right', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'interview' }, + [4] = { Header = 'Leder', Txt = '', Icon = 'fas fa-crown', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'supervisor' }, + } + }, + ["ambulance"] = { + Required = 1, -- How many players with this job are required to be online to make a request/alert (You'll need to add events that track the amount of players online with that job. Police / Ambulance is setup by default) + Zone = { + name = "Pillbox Reception", + coords = vector3(311.74, -580.04, 44.18), + length = 0.8, width = 0.8, + heading = 57.47, + minZ = 42, + maxZ = 44 + }, + Menu = { + [1] = { Header = 'Assistance', Txt = '', Icon = 'fas fa-hand', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'assistance'}, + [2] = { Header = 'Interview', Txt = '', Icon = 'fas fa-people-arrows-left-right', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'interview' }, + [3] = { Header = 'Leder', Txt = '', Icon = 'fas fa-crown', Event = 'qb-frontdesk:client:RequestAssistance', Args = 'supervisor'}, + } + } +} diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/client/main.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/client/main.lua new file mode 100644 index 0000000..18dff70 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/client/main.lua @@ -0,0 +1,552 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local garbageVehicle = nil +local hasBag = false +local currentStop = 0 +local deliveryBlip = nil +local amountOfBags = 0 +local garbageObject = nil +local endBlip = nil +local garbageBlip = nil +local canTakeBag = true +local currentStopNum = 0 +local PZone = nil +local listen = false +local finished = false +local continueworking = false +local playerJob = {} +-- Handlers + +-- Functions + +local function setupClient() + garbageVehicle = nil + hasBag = false + currentStop = 0 + deliveryBlip = nil + amountOfBags = 0 + garbageObject = nil + endBlip = nil + currentStopNum = 0 + if playerJob.name == Config.Jobname then + garbageBlip = AddBlipForCoord(Config.Locations["main"].coords.x, Config.Locations["main"].coords.y, Config.Locations["main"].coords.z) + SetBlipSprite(garbageBlip, 318) + SetBlipDisplay(garbageBlip, 4) + SetBlipScale(garbageBlip, 1.0) + SetBlipAsShortRange(garbageBlip, true) + SetBlipColour(garbageBlip, 39) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Config.Locations["main"].label) + EndTextCommandSetBlipName(garbageBlip) + end +end + + + +local function LoadAnimation(dict) + RequestAnimDict(dict) + while not HasAnimDictLoaded(dict) do Wait(10) end +end + +local function BringBackCar() + DeleteVehicle(garbageVehicle) + if endBlip then + RemoveBlip(endBlip) + end + if deliveryBlip then + RemoveBlip(deliveryBlip) + end + garbageVehicle = nil + hasBag = false + currentStop = 0 + deliveryBlip = nil + amountOfBags = 0 + garbageObject = nil + endBlip = nil + currentStopNum = 0 +end + +local function DeleteZone() + listen = false + PZone:destroy() +end + +local function SetRouteBack() + local depot = Config.Locations["main"].coords + endBlip = AddBlipForCoord(depot.x, depot.y, depot.z) + SetBlipSprite(endBlip, 1) + SetBlipDisplay(endBlip, 2) + SetBlipScale(endBlip, 1.0) + SetBlipAsShortRange(endBlip, false) + SetBlipColour(endBlip, 3) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Config.Locations["vehicle"].label) + EndTextCommandSetBlipName(endBlip) + SetBlipRoute(endBlip, true) + DeleteZone() + finished = true +end + +local function AnimCheck() + CreateThread(function() + local ped = PlayerPedId() + while hasBag and not IsEntityPlayingAnim(ped, 'missfbi4prepp1', '_bag_throw_garbage_man',3) do + if not IsEntityPlayingAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 3) then + ClearPedTasksImmediately(ped) + LoadAnimation('missfbi4prepp1') + TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, 0, 0, 0) + end + Wait(1000) + end + end) +end + +local function DeliverAnim() + local ped = PlayerPedId() + LoadAnimation('missfbi4prepp1') + TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_throw_garbage_man', 8.0, 8.0, 1100, 48, 0.0, 0, 0, 0) + FreezeEntityPosition(ped, true) + SetEntityHeading(ped, GetEntityHeading(garbageVehicle)) + canTakeBag = false + SetTimeout(1250, function() + DetachEntity(garbageObject, 1, false) + DeleteObject(garbageObject) + TaskPlayAnim(ped, 'missfbi4prepp1', 'exit', 8.0, 8.0, 1100, 48, 0.0, 0, 0, 0) + FreezeEntityPosition(ped, false) + garbageObject = nil + canTakeBag = true + end) + if Config.UseTarget and hasBag then + local CL = Config.Locations["trashcan"][currentStop] + hasBag = false + local pos = GetEntityCoords(ped) + exports['qb-target']:RemoveTargetEntity(garbageVehicle) + if (amountOfBags - 1) <= 0 then + QBCore.Functions.TriggerCallback('garbagejob:server:NextStop', function(hasMoreStops, nextStop, newBagAmount) + if hasMoreStops and nextStop ~= 0 then + -- Here he puts your next location and you are not finished working yet. + currentStop = nextStop + currentStopNum = currentStopNum + 1 + amountOfBags = newBagAmount + SetGarbageRoute() + QBCore.Functions.Notify(Lang:t("info.all_bags")) + SetVehicleDoorShut(garbageVehicle, 5, false) + else + if hasMoreStops and nextStop == currentStop then + QBCore.Functions.Notify(Lang:t("info.depot_issue")) + amountOfBags = 0 + else + -- You are done with work here. + QBCore.Functions.Notify(Lang:t("info.done_working")) + SetVehicleDoorShut(garbageVehicle, 5, false) + RemoveBlip(deliveryBlip) + SetRouteBack() + amountOfBags = 0 + end + end + end, currentStop, currentStopNum, pos) + else + -- You haven't delivered all bags here + amountOfBags = amountOfBags - 1 + if amountOfBags > 1 then + QBCore.Functions.Notify(Lang:t("info.bags_left", { value = amountOfBags })) + else + QBCore.Functions.Notify(Lang:t("info.bags_still", { value = amountOfBags })) + end + exports['qb-target']:AddCircleZone('garbagebin', vector3(CL.coords.x, CL.coords.y, CL.coords.z), 2.0,{ + name = 'garbagebin', debugPoly = false, useZ=true}, { + options = {{label = Lang:t("target.grab_garbage"),icon = 'fa-solid fa-trash', action = function() TakeAnim() end}}, + distance = 2.0 + }) + end + end +end + +function TakeAnim() + local ped = PlayerPedId() + QBCore.Functions.Progressbar("bag_pickup", Lang:t("info.picking_bag"), math.random(3000, 5000), false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", + anim = "machinic_loop_mechandplayer", + flags = 16, + }, {}, {}, function() + LoadAnimation('missfbi4prepp1') + TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, 0, 0, 0) + garbageObject = CreateObject(`prop_cs_rub_binbag_01`, 0, 0, 0, true, true, true) + AttachEntityToEntity(garbageObject, ped, GetPedBoneIndex(ped, 57005), 0.12, 0.0, -0.05, 220.0, 120.0, 0.0, true, true, false, true, 1, true) + StopAnimTask(PlayerPedId(), "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", "machinic_loop_mechandplayer", 1.0) + AnimCheck() + if Config.UseTarget and not hasBag then + hasBag = true + exports['qb-target']:RemoveZone("garbagebin") + exports['qb-target']:AddTargetEntity(garbageVehicle, { + options = { + {label = Lang:t("target.dispose_garbage"),icon = 'fa-solid fa-truck',action = function() DeliverAnim() end,canInteract = function() if hasBag then return true end return false end, } + }, + distance = 2.0 + }) + end + end, function() + StopAnimTask(PlayerPedId(), "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", "machinic_loop_mechandplayer", 1.0) + QBCore.Functions.Notify(Lang:t("error.cancled"), "error") + end) +end + +local function RunWorkLoop() + CreateThread(function() + local GarbText = false + while listen do + local ped = PlayerPedId() + local pos = GetEntityCoords(ped) + local DeliveryData = Config.Locations["trashcan"][currentStop] + local Distance = #(pos - vector3(DeliveryData.coords.x, DeliveryData.coords.y, DeliveryData.coords.z)) + if Distance < 15 or hasBag then + + if not hasBag and canTakeBag then + if Distance < 1.5 then + if not GarbText then + GarbText = true + exports['qb-core']:DrawText(Lang:t("info.grab_garbage"), 'top') + end + if IsControlJustPressed(0, 51) then + hasBag = true + exports['qb-core']:HideText() + TakeAnim() + end + elseif Distance < 10 then + if GarbText then + GarbText = false + exports['qb-core']:HideText() + end + end + else + if DoesEntityExist(garbageVehicle) then + local Coords = GetOffsetFromEntityInWorldCoords(garbageVehicle, 0.0, -4.5, 0.0) + local TruckDist = #(pos - Coords) + local TrucText = false + + if TruckDist < 2 then + if not TrucText then + TrucText = true + exports['qb-core']:DrawText(Lang:t("info.dispose_garbage"), 'top') + end + if IsControlJustPressed(0, 51) and hasBag then + StopAnimTask(PlayerPedId(), 'missfbi4prepp1', '_bag_walk_garbage_man', 1.0) + DeliverAnim() + QBCore.Functions.Progressbar("deliverbag", Lang:t("info.progressbar"), 2000, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + hasBag = false + canTakeBag = false + DetachEntity(garbageObject, 1, false) + DeleteObject(garbageObject) + FreezeEntityPosition(ped, false) + garbageObject = nil + canTakeBag = true + -- Looks if you have delivered all bags + if (amountOfBags - 1) <= 0 then + QBCore.Functions.TriggerCallback('garbagejob:server:NextStop', function(hasMoreStops, nextStop, newBagAmount) + if hasMoreStops and nextStop ~= 0 then + -- Here he puts your next location and you are not finished working yet. + currentStop = nextStop + currentStopNum = currentStopNum + 1 + amountOfBags = newBagAmount + SetGarbageRoute() + QBCore.Functions.Notify(Lang:t("info.all_bags")) + listen = false + SetVehicleDoorShut(garbageVehicle, 5, false) + else + if hasMoreStops and nextStop == currentStop then + QBCore.Functions.Notify(Lang:t("info.depot_issue")) + amountOfBags = 0 + else + -- You are done with work here. + QBCore.Functions.Notify(Lang:t("info.done_working")) + SetVehicleDoorShut(garbageVehicle, 5, false) + RemoveBlip(deliveryBlip) + SetRouteBack() + amountOfBags = 0 + listen = false + end + end + end, currentStop, currentStopNum, pos) + hasBag = false + else + -- You haven't delivered all bags here + amountOfBags = amountOfBags - 1 + if amountOfBags > 1 then + QBCore.Functions.Notify(Lang:t("info.bags_left", { value = amountOfBags })) + else + QBCore.Functions.Notify(Lang:t("info.bags_still", { value = amountOfBags })) + end + hasBag = false + end + + Wait(1500) + if TrucText then + exports['qb-core']:HideText() + TrucText = false + end + end, function() -- Cancel + QBCore.Functions.Notify(Lang:t("error.cancled"), "error") + end) + + end + end + else + QBCore.Functions.Notify(Lang:t("error.no_truck"), "error") + hasBag = false + end + end + end + Wait(1) + end + end) +end + +local function CreateZone(x, y, z) + CreateThread(function() + PZone = CircleZone:Create(vector3(x, y, z), 15.0, { + name = "NewRouteWhoDis", + debugPoly = false, + }) + + PZone:onPlayerInOut(function(isPointInside) + if isPointInside then + if not Config.UseTarget then + listen = true + RunWorkLoop() + end + SetVehicleDoorOpen(garbageVehicle,5,false,false) + else + if not Config.UseTarget then + exports['qb-core']:HideText() + listen = false + end + SetVehicleDoorShut(garbageVehicle, 5, false) + end + end) + end) +end + +function SetGarbageRoute() + local CL = Config.Locations["trashcan"][currentStop] + if deliveryBlip then + RemoveBlip(deliveryBlip) + end + deliveryBlip = AddBlipForCoord(CL.coords.x, CL.coords.y, CL.coords.z) + SetBlipSprite(deliveryBlip, 1) + SetBlipDisplay(deliveryBlip, 2) + SetBlipScale(deliveryBlip, 1.0) + SetBlipAsShortRange(deliveryBlip, false) + SetBlipColour(deliveryBlip, 27) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Config.Locations["trashcan"][currentStop].name) + EndTextCommandSetBlipName(deliveryBlip) + SetBlipRoute(deliveryBlip, true) + finished = false + if Config.UseTarget and not hasBag then + exports['qb-target']:AddCircleZone('garbagebin', vector3(CL.coords.x, CL.coords.y, CL.coords.z), 2.0,{ + name = 'garbagebin', debugPoly = false, useZ=true }, { + options = {{label = Lang:t("target.grab_garbage"), icon = 'fa-solid fa-trash', action = function() TakeAnim() end }}, + distance = 2.0 + }) + end + if PZone then + DeleteZone() + Wait(500) + CreateZone(CL.coords.x, CL.coords.y, CL.coords.z) + else + CreateZone(CL.coords.x, CL.coords.y, CL.coords.z) + end +end + +local ControlListen = false +local function Listen4Control() + ControlListen = true + CreateThread(function() + while ControlListen do + if IsControlJustReleased(0, 38) then + TriggerEvent("qb-garbagejob:client:MainMenu") + end + Wait(1) + end + end) +end + +local pedsSpawned = false +local function spawnPeds() + if not Config.Peds or not next(Config.Peds) or pedsSpawned then return end + for i = 1, #Config.Peds do + local current = Config.Peds[i] + current.model = type(current.model) == 'string' and GetHashKey(current.model) or current.model + RequestModel(current.model) + while not HasModelLoaded(current.model) do + Wait(0) + end + local ped = CreatePed(0, current.model, current.coords, false, false) + FreezeEntityPosition(ped, true) + SetEntityInvincible(ped, true) + SetBlockingOfNonTemporaryEvents(ped, true) + current.pedHandle = ped + + if Config.UseTarget then + exports['qb-target']:AddTargetEntity(ped, { + options = {{type = "client", event = "qb-garbagejob:client:MainMenu", label = Lang:t("target.talk"), icon = 'fa-solid fa-recycle', job = "garbage",}}, + distance = 2.0 + }) + else + local options = current.zoneOptions + if options then + local zone = BoxZone:Create(current.coords.xyz, options.length, options.width, { + name = "zone_cityhall_" .. ped, + heading = current.coords.w, + debugPoly = false + }) + zone:onPlayerInOut(function(inside) + if LocalPlayer.state.isLoggedIn then + if inside then + exports['qb-core']:DrawText(Lang:t("info.talk"), 'top') + Listen4Control() + else + ControlListen = false + exports['qb-core']:HideText() + end + end + end) + end + end + end + pedsSpawned = true +end + +local function deletePeds() + if not Config.Peds or not next(Config.Peds) or not pedsSpawned then return end + for i = 1, #Config.Peds do + local current = Config.Peds[i] + if current.pedHandle then + DeletePed(current.pedHandle) + end + end +end + +-- Events + +RegisterNetEvent('garbagejob:client:SetWaypointHome', function() + SetNewWaypoint(Config.Locations["main"].coords.x, Config.Locations["main"].coords.y) +end) + +RegisterNetEvent('qb-garbagejob:client:RequestRoute', function() + if garbageVehicle then continueworking = true TriggerServerEvent('garbagejob:server:PayShift', continueworking) end + QBCore.Functions.TriggerCallback('garbagejob:server:NewShift', function(shouldContinue, firstStop, totalBags) + if shouldContinue then + if not garbageVehicle then + local occupied = false + for _,v in pairs(Config.Locations["vehicle"].coords) do + if not IsAnyVehicleNearPoint(vector3(v.x,v.y,v.z), 2.5) then + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleEngineOn(veh, false, true) + garbageVehicle = veh + SetVehicleNumberPlateText(veh, "QB-" .. tostring(math.random(1000, 9999))) + SetEntityHeading(veh, v.w) + exports['qb-fuel']:SetFuel(veh, 100.0) + SetVehicleFixed(veh) + SetEntityAsMissionEntity(veh, true, true) + SetVehicleDoorsLocked(veh, 2) + currentStop = firstStop + currentStopNum = 1 + amountOfBags = totalBags + SetGarbageRoute() + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + QBCore.Functions.Notify(Lang:t("info.deposit_paid", { value = Config.TruckPrice })) + QBCore.Functions.Notify(Lang:t("info.started")) + TriggerServerEvent("qb-garbagejob:server:payDeposit") + end, Config.Vehicle, v, false) + return + else + occupied = true + end + end + if occupied then + QBCore.Functions.Notify(Lang:t("error.all_occupied")) + end + end + currentStop = firstStop + currentStopNum = 1 + amountOfBags = totalBags + SetGarbageRoute() + else + QBCore.Functions.Notify(Lang:t("info.not_enough", { value = Config.TruckPrice })) + end + end, continueworking) +end) + +RegisterNetEvent('qb-garbagejob:client:RequestPaycheck', function() + if garbageVehicle then + BringBackCar() + QBCore.Functions.Notify(Lang:t("info.truck_returned")) + end + TriggerServerEvent('garbagejob:server:PayShift') +end) + +RegisterNetEvent('qb-garbagejob:client:MainMenu', function() + if playerJob.name == Config.Jobname then + local MainMenu = {} + MainMenu[#MainMenu+1] = {isMenuHeader = true,header = Lang:t("menu.header")} + MainMenu[#MainMenu+1] = { header = Lang:t("menu.collect"),txt = Lang:t("menu.return_collect"),params = { event = 'qb-garbagejob:client:RequestPaycheck',}} + if not garbageVehicle or finished then + MainMenu[#MainMenu+1] = { header = Lang:t("menu.route"), txt = Lang:t("menu.request_route"), params = { event = 'qb-garbagejob:client:RequestRoute',}} + end + exports['qb-menu']:openMenu(MainMenu) + else + QBCore.Functions.Notify(Lang:t("error.job")) + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + playerJob = QBCore.Functions.GetPlayerData().job + setupClient() + spawnPeds() +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + playerJob = JobInfo + if garbageBlip then + RemoveBlip(garbageBlip) + end + if endBlip then + RemoveBlip(endBlip) + end + if deliveryBlip then + RemoveBlip(deliveryBlip) + end + endBlip = nil + deliveryBlip = nil + setupClient() + spawnPeds() +end) + +AddEventHandler('onResourceStop', function(resource) + if GetCurrentResourceName() == resource then + if garbageObject then + DeleteEntity(garbageObject) + garbageObject = nil + end + deletePeds() + end +end) + +AddEventHandler('onResourceStart', function(resource) + if GetCurrentResourceName() == resource then + playerJob = QBCore.Functions.GetPlayerData().job + setupClient() + spawnPeds() + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/config.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/config.lua new file mode 100644 index 0000000..05b0238 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/config.lua @@ -0,0 +1,154 @@ +Config = {} + +Config.UseTarget = GetConvar('UseTarget', 'false') == 'true' +Config.Jobname = 'garbage' + +-- Price taken and given back when delivered a truck +Config.TruckPrice = 250 +-- Want to give out a cryptostick per stop? +Config.GiveCryptoStick = true +-- Has to roll this number or higher to receive a cryptostick +Config.CryptoStickChance = 75 +-- How many stops minimum should the job roll? +Config.MinStops = 5 +-- Upper worth per bag +Config.BagUpperWorth = 100 +-- Lower worth per bag +Config.BagLowerWorth = 50 +-- Minimum bags per stop +Config.MinBagsPerStop = 2 +-- Maximum bags per stop +Config.MaxBagsPerStop = 5 + +-- WIP: Do not use +-- If you want to use custom routes instead of random amount of stops stops set to true +Config.UsePreconfiguredRoutes = false + +Config.Peds = { + { + model = 's_m_y_garbage', + coords = vector4(-322.24, -1546.02, 30.02, 294.97), + zoneOptions = { -- Used for when UseTarget is false + length = 3.0, + width = 3.0 + } + } +} + +Config.Locations = { + ["main"] = { + label = "Lodseplads", + coords = vector3(-313.84, -1522.82, 27.56), + }, + ["vehicle"] = { + label = "Skraldebil Garage", + coords = { -- parking spot locations to spawn garbage + [1] = vector4(-333.84, -1527.28, 27.28, 1.97), + [2] = vector4(-327.55, -1527.69, 27.25, 359.43), + }, + }, + ["paycheck"] = { + label = "Lønkontor", + coords = vector3(-321.45, -1545.86, 31.02), + }, + ["trashcan"] ={ + [1] = { + name = "forumdrive", + coords = vector4(-168.07, -1662.8, 33.31, 137.5), + }, + [2] = { + name = "grovestreet", + coords = vector4(118.06, -1943.96, 20.43, 179.5), + }, + [3] = { + name = "jamestownstreet", + coords = vector4(297.94, -2018.26, 20.49, 119.5), + }, + [4] = { + name = "davisave", + coords = vector4(424.98, -1523.57, 29.28, 120.08), + }, + [5] = { + name = "littlebighornavenue", + coords = vector4(488.49, -1284.1, 29.24, 138.5), + }, + [6] = { + name = "vespucciblvd", + coords = vector4(307.47, -1033.6, 29.03, 46.5), + }, + [7] = { + name = "elginavenue", + coords = vector4(239.19, -681.5, 37.15, 178.5), + }, + [8] = { + name = "elginavenue2", + coords = vector4(543.51, -204.41, 54.16, 199.5), + }, + [9] = { + name = "powerstreet", + coords = vector4(268.72, -25.92, 73.36, 90.5), + }, + [10] = { + name = "altastreet", + coords = vector4(267.03, 276.01, 105.54, 332.5), + }, + [11] = { + name = "didiondrive", + coords = vector4(21.65, 375.44, 112.67, 323.5), + }, + [12] = { + name = "miltonroad", + coords = vector4(-546.9, 286.57, 82.85, 127.5), + }, + [13] = { + name = "eastbourneway", + coords = vector4(-683.23, -169.62, 37.74, 267.5), + }, + [14] = { + name = "eastbourneway2", + coords = vector4(-771.02, -218.06, 37.05, 277.5), + }, + [15] = { + name = "industrypassage", + coords = vector4(-1057.06, -515.45, 35.83, 61.5), + }, + [16] = { + name = "boulevarddelperro", + coords = vector4(-1558.64, -478.22, 35.18, 179.5), + }, + [17] = { + name = "sandcastleway", + coords = vector4(-1350.0, -895.64, 13.36, 17.5), + }, + [18] = { + name = "magellanavenue", + coords = vector4(-1243.73, -1359.72, 3.93, 287.5), + }, + [19] = { + name = "palominoavenue", + coords = vector4(-845.87, -1113.07, 6.91, 253.5), + }, + [20] = { + name = "southrockforddrive", + coords = vector4(-635.21, -1226.45, 11.8, 143.5), + }, + [21] = { + name = "southarsenalstreet", + coords = vector4(-587.74, -1739.13, 22.47, 339.5), + }, + }, + ["routes"] = { -- Custom routes (WIP Do not use) + [1] = {7, 6, 5, 15, 10}, + [2] = {11, 18, 7, 8, 15}, + [3] = {1, 7, 8, 17, 18}, + [4] = {16, 17, 4, 8, 21}, + [5] = {8, 2, 6, 17, 19}, + [6] = {3, 19, 1, 8, 11}, + [7] = {8, 19, 9, 6, 14}, + [8] = {14, 12, 20, 9, 11}, + [9] = {9, 18, 3, 6, 20}, + [10] = {9, 13, 7, 17, 16} + } +} + +Config.Vehicle = 'trash2' -- vehicle name used to spawn \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/fxmanifest.lua new file mode 100644 index 0000000..1518425 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/fxmanifest.lua @@ -0,0 +1,24 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-GarbageJob' +version '1.2.0' + +shared_scripts { + '@qb-core/shared/locale.lua', + 'locales/en.lua', + 'locales/*.lua', + 'config.lua' +} + +client_script { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/EntityZone.lua', + '@PolyZone/CircleZone.lua', + '@PolyZone/ComboZone.lua', + 'client/main.lua' +} +server_script 'server/main.lua' + +lua54 'yes' diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/da.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/da.lua new file mode 100644 index 0000000..370d866 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/da.lua @@ -0,0 +1,62 @@ +local Translations = { + error = { + ["cancled"] = "Annulleret", + ["no_truck"] = "Du har ingen lastbil!", + ["not_enough"] = "Ikke nok penge (%{value},- minimum)", + ["too_far"] = "Du er for langt væk fra drop-off punktet", + ["early_finish"] = "Grundet for tidlig fuldførsel (Færdiggjort: %{completed} | Total: %{total}), vil dit depositum gå tabt.", + ["never_clocked_on"] = "Du klokkede aldrig ind!", + ["all_occupied"] = "Alle parkeringspladser er optaget", + ["job"] = "Du kan få jobbet fra jobcentret", + }, + success = { + ["clear_routes"] = "Gennemførte bruger ruter. De havde %{value} ruter gemt", + ["pay_slip"] = "Du fik %{total},- DKK, din lønseddel på %{deposit} blev udbetalt til din bank!", + }, + target = { + ["talk"] = 'Snak med skraldemanden', + ["grab_garbage"] = "Tag skraldepose", + ["dispose_garbage"] = "Smid skraldepose ud", + }, + menu = { + ["header"] = "Skrald hovedmenu", + ["collect"] = "Hent lønseddel", + ["return_collect"] = "Returner lastbilen og hent din lønseddel her!", + ["route"] = "Anmod om rute", + ["request_route"] = "Anmod om en skralde-rute", + }, + info = { + ["payslip_collect"] = "[E] - Lønseddel", + ["payslip"] = "Lønseddel", + ["not_enough"] = "Du har ikke nok penge for depositum. Depositum er på %{value},- DKK", + ["deposit_paid"] = "Du betalte depositum på %{value},- DKK!", + ["no_deposit"] = "Du har ikke betalt depositum på dette køretøj..", + ["truck_returned"] = "Lastbil parkeret, hent din lønseddel for at få løn + depositum tilbage!", + ["bags_left"] = "Der er stadigvæk %{value} poser tilbage!", + ["bags_still"] = "Der er stadgivæk %{value} poser derovre!", + ["all_bags"] = "Alle poser samlet ind, kør til næste lokation!", + ["depot_issue"] = "Der er sket en fejl på depotet, kør tilbage øjeblikkeligt!", + ["done_working"] = "Du er færdig for nu! Kør tilbage til depotet.", + ["started"] = "Du startede med at arbejde, lokation markeret på GPS!", + ["grab_garbage"] = "[E] Tag skraldepose", + ["stand_grab_garbage"] = "Stp her for at tage skraldeposen.", + ["dispose_garbage"] = "[E] Smid skraldepose", + ["progressbar"] = "Smider pose i komprimator..", + ["garbage_in_truck"] = "Put posen i din skraldebil..", + ["stand_here"] = "Stå her..", + ["found_crypto"] = "Du fandt en CryptoStick!", + ["payout_deposit"] = "(+ %{value},- DKK depositum)", + ["store_truck"] = "[E] - Parker skraldebil", + ["get_truck"] = "[E] - Hent skraldebil", + ["picking_bag"] = "Tager skraldepose..", + ["talk"] = "[E] Snak med skraldemanden", + }, +} + +if GetConvar('qb_locale', 'en') == 'da' then + Lang = Locale:new({ + phrases = Translations, + warnOnMissing = true, + fallbackLang = Lang, + }) +end diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/en.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/en.lua new file mode 100644 index 0000000..1168be8 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/locales/en.lua @@ -0,0 +1,59 @@ +local Translations = { + error = { + ["cancled"] = "Canceled", + ["no_truck"] = "You have no truck!", + ["not_enough"] = "Not Enough Money (%{value} required)", + ["too_far"] = "You are too far away from the drop-off point", + ["early_finish"] = "Due to early finish (Completed: %{completed} Total: %{total}), your deposit will not be returned.", + ["never_clocked_on"] = "You never clocked on!", + ["all_occupied"] = "All parking spots are occupied", + ["job"] = "You must get the job from the job center", + }, + success = { + ["clear_routes"] = "Cleared users routes they had %{value} routes stored", + ["pay_slip"] = "You got $%{total}, your payslip %{deposit} got paid to your bank account!", + }, + target = { + ["talk"] = 'Talk to Garbageman', + ["grab_garbage"] = "Grab garbage bag", + ["dispose_garbage"] = "Dispose Garbage Bag", + }, + menu = { + ["header"] = "Garbage Main Menu", + ["collect"] = "Collect Paycheck", + ["return_collect"] = "Return truck and collect paycheck here!", + ["route"] = "Request Route", + ["request_route"] = "Request a garbage Route", + }, + info = { + ["payslip_collect"] = "[E] - Payslip", + ["payslip"] = "Payslip", + ["not_enough"] = "You have not enough money for the deposit.. Deposit costs are $%{value}", + ["deposit_paid"] = "You have paid $%{value} deposit!", + ["no_deposit"] = "You have no deposit paid on this vehicle..", + ["truck_returned"] = "Truck returned, collect your payslip to receive your pay and deposit back!", + ["bags_left"] = "There are still %{value} bags left!", + ["bags_still"] = "There is still %{value} bag over there!", + ["all_bags"] = "All garbage bags are done, proceed to the next location!", + ["depot_issue"] = "There was an issue at the depot, please return immediately!", + ["done_working"] = "You are done working! Go back to the depot.", + ["started"] = "You have started working, location marked on GPS!", + ["grab_garbage"] = "[E] Grab a garbage bag", + ["stand_grab_garbage"] = "Stand here to grab a garbage bag.", + ["dispose_garbage"] = "[E] Dispose of Garbage Bag", + ["progressbar"] = "Putting bag in trashmaster ..", + ["garbage_in_truck"] = "Put the bag in your truck..", + ["stand_here"] = "Stand here..", + ["found_crypto"] = "You found a cryptostick on the floor", + ["payout_deposit"] = "(+ $%{value} deposit)", + ["store_truck"] = "[E] - Store Garbage Truck", + ["get_truck"] = "[E] - Garbage Truck", + ["picking_bag"] = "Grabbing garbage bag..", + ["talk"] = "[E] Talk to Garbage Man", + }, +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +}) diff --git a/resources/[qb]/[qb_jobs]/qb-garbagejob/server/main.lua b/resources/[qb]/[qb_jobs]/qb-garbagejob/server/main.lua new file mode 100644 index 0000000..2fa92be --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-garbagejob/server/main.lua @@ -0,0 +1,148 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local Routes = {} + +local function CanPay(Player) + return Player.PlayerData.money['bank'] >= Config.TruckPrice +end + +QBCore.Functions.CreateCallback("garbagejob:server:NewShift", function(source, cb, continue) + local Player = QBCore.Functions.GetPlayer(source) + local CitizenId = Player.PlayerData.citizenid + local shouldContinue = false + local nextStop = 0 + local totalNumberOfStops = 0 + local bagNum = 0 + + if CanPay(Player) or continue then + math.randomseed(os.time()) + local MaxStops = math.random(Config.MinStops, #Config.Locations["trashcan"]) + local allStops = {} + + for _=1, MaxStops do + local stop = math.random(#Config.Locations["trashcan"]) + local newBagAmount = math.random(Config.MinBagsPerStop, Config.MaxBagsPerStop) + allStops[#allStops+1] = {stop = stop, bags = newBagAmount} + end + + Routes[CitizenId] = { + stops = allStops, + currentStop = 1, + started = true, + currentDistance = 0, + depositPay = Config.TruckPrice, + actualPay = 0, + stopsCompleted = 0, + totalNumberOfStops = #allStops + } + + nextStop = allStops[1].stop + shouldContinue = true + totalNumberOfStops = #allStops + bagNum = allStops[1].bags + TriggerClientEvent('qb-jobselector:addxp:client', 30) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t("error.not_enough", {value = Config.TruckPrice}), "error") + end + cb(shouldContinue, nextStop, bagNum, totalNumberOfStops) +end) + +RegisterNetEvent("qb-garbagejob:server:payDeposit", function() + local Player = QBCore.Functions.GetPlayer(source) + if not Player.Functions.RemoveMoney("bank", Config.TruckPrice, "garbage-deposit") then + TriggerClientEvent('QBCore:Notify', source, Lang:t("error.not_enough", {value = Config.TruckPrice}), "error") + end +end) + +QBCore.Functions.CreateCallback("garbagejob:server:NextStop", function(source, cb, currentStop, currentStopNum, currLocation) + local Player = QBCore.Functions.GetPlayer(source) + local CitizenId = Player.PlayerData.citizenid + + local currStopCoords = Config.Locations["trashcan"][currentStop].coords + currStopCoords = vector3(currStopCoords.x, currStopCoords.y, currStopCoords.z) + + local distance = #(currLocation - currStopCoords) + local newStop = 0 + local shouldContinue = false + local newBagAmount = 0 + + TriggerClientEvent('qb-jobselector:addxp:client', 20) -- 100 is amount of exp + + if(math.random(100) >= Config.CryptoStickChance) and Config.GiveCryptoStick then + Player.Functions.AddItem("cryptostick", 1, false) + TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items["cryptostick"], 'add') + TriggerClientEvent('QBCore:Notify', source, Lang:t("info.found_crypto")) + + end + + if distance <= 20 then + if currentStopNum >= #Routes[CitizenId].stops then + Routes[CitizenId].stopsCompleted = tonumber(Routes[CitizenId].stopsCompleted) + 1 + newStop = currentStop + else + newStop = Routes[CitizenId].stops[currentStopNum+1].stop + newBagAmount = Routes[CitizenId].stops[currentStopNum+1].bags + shouldContinue = true + local bagAmount = Routes[CitizenId].stops[currentStopNum].bags + local totalNewPay = 0 + + for _ = 1, bagAmount do + totalNewPay = totalNewPay + math.random(Config.BagLowerWorth, Config.BagUpperWorth) + end + + Routes[CitizenId].actualPay = math.ceil(Routes[CitizenId].actualPay + totalNewPay) + Routes[CitizenId].stopsCompleted = tonumber(Routes[CitizenId].stopsCompleted) + 1 + end + else + TriggerClientEvent('QBCore:Notify', source, Lang:t("error.too_far"), "error") + end + cb(shouldContinue,newStop,newBagAmount) +end) + +QBCore.Functions.CreateCallback('garbagejob:server:EndShift', function(source, cb) + local Player = QBCore.Functions.GetPlayer(source) + local CitizenId = Player.PlayerData.citizenid + local status = false + if Routes[CitizenId] ~= nil then status = true end + cb(status) +end) + +RegisterNetEvent('garbagejob:server:PayShift', function(continue) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local CitizenId = Player.PlayerData.citizenid + if Routes[CitizenId] ~= nil then + local depositPay = Routes[CitizenId].depositPay + if tonumber(Routes[CitizenId].stopsCompleted) < tonumber(Routes[CitizenId].totalNumberOfStops) then + depositPay = 0 + TriggerClientEvent('QBCore:Notify', src, Lang:t("error.early_finish", {completed = Routes[CitizenId].stopsCompleted, total = Routes[CitizenId].totalNumberOfStops}), "error") + end + if continue then + depositPay = 0 + end + local totalToPay = depositPay + Routes[CitizenId].actualPay + local payoutDeposit = Lang:t("info.payout_deposit", {value = depositPay}) + if depositPay == 0 then + payoutDeposit = "" + end + + Player.Functions.AddMoney("bank", totalToPay , 'garbage-payslip') + TriggerClientEvent('QBCore:Notify', src, Lang:t("success.pay_slip", {total = totalToPay, deposit = payoutDeposit}), "success") + Routes[CitizenId] = nil + else + TriggerClientEvent('QBCore:Notify', source, Lang:t("error.never_clocked_on"), "error") + end +end) + +QBCore.Commands.Add("cleargarbroutes", "Fjern skralde-ruter for bruger (Admin)", {{name="id", help="Spiller ID"}}, false, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + local CitizenId = Player.PlayerData.citizenid + local count = 0 + for k, _ in pairs(Routes) do + if k == CitizenId then + count = count + 1 + end + end + + TriggerClientEvent('QBCore:Notify', source, Lang:t("success.clear_routes", {value = count}), "success") + Routes[CitizenId] = nil +end, "admin") diff --git a/resources/[qb]/[qb_jobs]/qb-gardening/client/client.lua b/resources/[qb]/[qb_jobs]/qb-gardening/client/client.lua new file mode 100644 index 0000000..4984172 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-gardening/client/client.lua @@ -0,0 +1,305 @@ +QBCore = exports['qb-core']:GetCoreObject() +local canwork = false +local vezes = 0 +local amount = Config.paymentbybush +local total = 0 +local Blip = nil +local Ped = nil + + +AddEventHandler('onResourceStarting', function(resourceName) + if resourceName == 'qb-gardening' then + CancelEvent() + end +end) + +local function hasItem() + if QBCore.Functions.HasItem('shears') then + return true + else + return false + end +end + +local function ds() + if Ped ~= nil then + DeleteEntity(Ped) + exports['qb-target']:RemoveZone("Ped") + Ped = nil + end +end + +local function Startup() + --Blip + if Config.Coords['WantBlip'] == 'yes' then + Blip = AddBlipForCoord(Config.Coords['Blip']) + SetBlipSprite(Blip, 541) + SetBlipDisplay(Blip, 4) + SetBlipScale(Blip, 0.5) + SetBlipAsShortRange(Blip, true) + SetBlipColour(Blip, 2) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Config.Coords['BlipName']) + EndTextCommandSetBlipName(Blip) + elseif Config.Coords['WantBlip'] == 'no' then + RemoveBlip(Blip) + end + --Ped + RequestModel(Config.Coords['PedModel']) + while not HasModelLoaded(Config.Coords['PedModel']) do + Wait(1) + end + + Ped = CreatePed(2, Config.Coords['PedModel'], Config.Coords['Ped'], false, false) + SetPedFleeAttributes(Ped, 0, 0) + SetPedDiesWhenInjured(Ped, false) + SetPedKeepTask(Ped, true) + SetBlockingOfNonTemporaryEvents(Ped, true) + SetEntityInvincible(Ped, true) + FreezeEntityPosition(Ped, true) + -- TaskStartScenarioInPlace(Ped, 'WORLD_HUMAN_GARDENER_PLANT', 0, true) + + exports['qb-target']:AddBoxZone("Ped", GetEntityCoords(Ped), 1.5, 1.5, { + name = "Ped", + heading = GetEntityHeading(Ped), + minZ = Config.Coords['Ped']['z'], + maxZ = Config.Coords['Ped']['z'] + 2.0, + debugPoly = false + }, { + options = { + { + event = "nc-gardening:startwork", + icon = Lang.workicon, + label = Lang.getwork, + -- job = Config.job, + }, + { + event = 'nc-gardening:client:payment', + icon = Lang.paymenticon, + label = Lang.paymentlabel, + -- job = Config.job, + } + }, + distance = 2.5 + }) +end +Startup() + +local animDict = "rcmnigel1b" +local anim = "idle_gardener" + +local function Anim() + local playerPed = PlayerPedId() + if not HasAnimDictLoaded(animDict) then + RequestAnimDict(animDict) + while not HasAnimDictLoaded(animDict) do + Wait(100) + end + end + TaskPlayAnim(playerPed, animDict, anim, 8.0, 8.0, 5000, 0, 0, false, false, false) +end + +local function startingWork() + if canwork == false then + QBCore.Functions.Notify(Lang.givesomespots, 'info') + canwork = true + vezes = 0 + SetNewWaypoint(-510.19, -261.66) + loc1() + else + QBCore.Functions.Notify(Lang.alreadyhavework, 'error') + end +end + +RegisterNetEvent('nc-gardening:startwork', function() + QBCore.Functions.TriggerCallback("nc-gardening:cooldown", function(cooldown) + if cooldown then + QBCore.Functions.Notify(Lang.ontimeout, 'error') + return + end + startingWork() + end, 'lmao') +end) + +RegisterNetEvent('nc-gardening:workbushes1', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc1') + loc2() + vezes = vezes + 1 + QBCore.Functions.Notify(Lang.leftone, 'info') + end) +end) + +RegisterNetEvent('nc-gardening:workbushes2', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc2') + loc3() + vezes = vezes + 1 + QBCore.Functions.Notify(Lang.infrontofyou, 'info') + end) +end) + +RegisterNetEvent('nc-gardening:workbushes3', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc3') + loc4() + vezes = vezes + 1 + QBCore.Functions.Notify(Lang.therest, 'info') + end) +end) + +RegisterNetEvent('nc-gardening:workbushes4', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc4') + loc5() + vezes = vezes + 1 + end) +end) + +RegisterNetEvent('nc-gardening:workbushes5', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc5') + loc6() + vezes = vezes + 1 + end) +end) + +RegisterNetEvent('nc-gardening:workbushes6', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc6') + loc7() + vezes = vezes + 1 + end) +end) + +RegisterNetEvent('nc-gardening:workbushes7', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc7') + loc8() + vezes = vezes + 1 + end) +end) + +RegisterNetEvent('nc-gardening:workbushes8', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc8') + loc9() + vezes = vezes + 1 + end) +end) + +RegisterNetEvent('nc-gardening:workbushes9', function() + if not hasItem then return QBCore.Functions.Notify(Lang.donthaveitem, 'error') end + Anim() + QBCore.Functions.Progressbar('workbushes', Lang.workbushes, 5000, false, true, + { -- Name | Label | Time | useWhileDead | canCancel + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() + exports['qb-target']:RemoveZone('loc9') + vezes = vezes + 1 + QBCore.Functions.Notify(Lang.cometome, 'info') + SetNewWaypoint(Config.Coords['Ped']['x'], Config.Coords['Ped']['y']) + end) +end) + +RegisterNetEvent('nc-gardening:client:payment', function() + if vezes > 0 then + total = vezes * amount + TriggerServerEvent('nc-gardening:server:pagamento', total) + canwork = false + exports['qb-target']:RemoveZone('loc1') + exports['qb-target']:RemoveZone('loc2') + exports['qb-target']:RemoveZone('loc3') + exports['qb-target']:RemoveZone('loc4') + exports['qb-target']:RemoveZone('loc5') + exports['qb-target']:RemoveZone('loc6') + exports['qb-target']:RemoveZone('loc7') + exports['qb-target']:RemoveZone('loc8') + exports['qb-target']:RemoveZone('loc9') + else + QBCore.Functions.Notify(Lang.didntwork, 'error') + end +end) + +AddEventHandler('onResourceStop', function(resourceName) + if (GetCurrentResourceName() ~= resourceName) then + return + end + ds() +end) diff --git a/resources/[qb]/[qb_jobs]/qb-gardening/client/functions.lua b/resources/[qb]/[qb_jobs]/qb-gardening/client/functions.lua new file mode 100644 index 0000000..023cce6 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-gardening/client/functions.lua @@ -0,0 +1,249 @@ +QBCore = exports['qb-core']:GetCoreObject() + +local marker = false +local sleep = 1000 +local x = -529.02 +local y = -201.53 +local z = 37.65 + +CreateThread(function() + while true do + local pedCoords = GetEntityCoords(PlayerPedId()) + local markerCoords = vector3(x, y, z) + local dist = #(pedCoords - markerCoords) + if dist < 40 and marker then + DrawMarker(21, x, y, z + 1, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 1.3, 1.3, 1.3, 120, 10, 20, 50, false, true, 2, nil, nil, false) + sleep = 0 + else + sleep = 1000 + end + Wait(sleep) + end +end) + +function loc1() + x = -529.02 + y = -201.53 + z = 37.65 + marker = true + exports['qb-target']:AddBoxZone("loc1", vector3(-529.02, -201.53, 37.65), 0.6, 2.8, { + name = "loc1", + heading = 30, + minZ = 33.65, + maxZ = 37.65, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes1') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc2() + x = -527.45 + y = -202.06 + z = 37.65 + exports['qb-target']:AddBoxZone("loc2", vector3(-527.45, -202.06, 37.65), 0.6, 2.4, { + name = "loc2", + heading = 30, + minZ = 33.45, + maxZ = 37.45, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes2') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc3() + x = -528.22 + y = -205.03 + z = 38.18 + exports['qb-target']:AddBoxZone("loc3", vector3(-528.22, -205.03, 38.18), 4.0, 1, { + name = "loc3", + heading = 255, + minZ = 33.58, + maxZ = 37.58, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes3') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc4() + x = -522.46 + y = -210.7 + z = 37.65 + exports['qb-target']:AddBoxZone("loc4", vector3(-522.46, -210.7, 37.65), 0.6, 3.0, { + name = "loc4", + heading = 120, + minZ = 33.45, + maxZ = 37.45, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes4') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc5() + x = -523.07 + y = -212.23 + z = 37.7 + exports['qb-target']:AddBoxZone("loc5", vector3(-523.07, -212.23, 37.7), 0.6, 2.6, { + name = "loc5", + heading = 30, + minZ = 33.5, + maxZ = 37.5, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes5') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc6() + x = -525.27 + y = -210.11 + z = 37.7 + exports['qb-target']:AddBoxZone("loc6", vector3(-525.27, -210.11, 37.7), 4.2, 0.8, { + name = "loc6", + heading = 350, + minZ = 33.7, + maxZ = 37.7, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes6') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc7() + x = -530.36 + y = -213.53 + z = 37.68 + exports['qb-target']:AddBoxZone("loc7", vector3(-530.36, -213.53, 37.68), 3.2, 0.8, { + name = "loc7", + heading = 80, + minZ = 33.48, + maxZ = 37.48, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes7') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc8() + x = -530.2 + y = -216.53 + z = 37.6 + exports['qb-target']:AddBoxZone("loc8", vector3(-530.2, -216.53, 37.6), 0.6, 2.2, { + name = "loc8", + heading = 30, + minZ = 33.6, + maxZ = 37.6, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes8') + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end + +function loc9() + x = -531.9 + y = -215.97 + z = 37.65 + exports['qb-target']:AddBoxZone("loc9", vector3(-531.9, -215.97, 37.65), 2.4, 0.6, { + name = "loc9", + heading = 30, + minZ = 33.65, + maxZ = 37.65, + }, { + options = { + { + action = function(entity) + if IsPedAPlayer(entity) then return false end + TriggerEvent('nc-gardening:workbushes9') + marker = false + end, + icon = 'fa fa-scissors', + label = "Klip hæk", + item = "shears" + }, + }, + distance = 1.5 + }) +end diff --git a/resources/[qb]/[qb_jobs]/qb-gardening/config.lua b/resources/[qb]/[qb_jobs]/qb-gardening/config.lua new file mode 100644 index 0000000..152f39f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-gardening/config.lua @@ -0,0 +1,35 @@ +Config = { + ['Coords'] = { + ['WantBlip'] = 'yes', -- yes or no + ['Blip'] = vector3(962.96, -1010.04, 42.01), + ['Ped'] = vector4(962.96, -1010.04, 41.01, 277.24), + ['PedModel'] = 'a_m_m_farmer_01', + ['BlipName'] = 'Gartner' + }, + paymentbybush = math.random(35, 60), + paymentmethod = 'cash', + job = 'gardener' +} + +Lang = { + --Notification + ['donthaveitem'] = "Har du husket hækkesaksen fra bilen?", + ['haveitem'] = "Du kan starte arbejdet", + ['givesomespots'] = "Tag en vogn, husk hækkesaksen bag i, og kør hen hvor GPS'en viser", + ['checkspots'] = "Du burde lige kontrollere om du kan arbejde", + ['alreadyhavework'] = 'Jeg har allerede givet dig en opgave?', + ['leftone'] = "Du har en mere på din venstre", + ['infrontofyou'] = "Du har en mere foran dig", + ['therest'] = 'Gør det med resten af buskene', + ['cometome'] = 'Kom over til mig, hvis du vil have din kommission', + ['didntwork'] = 'Du har ikke arbejdet, og vil have kommission?', + ['ontimeout'] = 'Jeg har intet arbejde til dig lige nu', + ['notyourjob'] = 'Det ser ikke ud til at du arbejder her?', + --Progressbar + ['workbushes'] = 'Trimmer busken', + --Targer + ['paymentlabel'] = 'Kommissions-udbetaling', + ['paymenticon'] = 'fas fa-dollar-sign', + ['getwork'] = 'Få arbejde', + ['workicon'] = 'fa-solid fa-hands', +} \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-gardening/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-gardening/fxmanifest.lua new file mode 100644 index 0000000..aedea01 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-gardening/fxmanifest.lua @@ -0,0 +1,10 @@ +-- Generated automaticly by RB Generator. +fx_version('cerulean') +games { 'gta5' } + +shared_script 'config.lua' + +server_script 'server/server.lua' + +client_script 'client/functions.lua' +client_script 'client/client.lua' \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-gardening/server/server.lua b/resources/[qb]/[qb_jobs]/qb-gardening/server/server.lua new file mode 100644 index 0000000..a0b2823 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-gardening/server/server.lua @@ -0,0 +1,33 @@ +QBCore = exports['qb-core']:GetCoreObject() +local Cooldown = false + + +RegisterNetEvent('nc-gardening:server:pagamento', function(total) + local Player = QBCore.Functions.GetPlayer(source) + + if Player.PlayerData.job.name ~= Config.job then return end + + Player.Functions.AddMoney(Config.paymentmethod, total, "Gartner kommission") +end) + +--Cooldown +RegisterServerEvent('nc-gardening:Server:BeginCooldown') +AddEventHandler('nc-gardening:Server:BeginCooldown', function() + Cooldown = true + local timer = 60 * 1000 + while timer > 0 do + Wait(1000) + timer = timer - 1000 + if timer == 0 then + Cooldown = false + end + end +end) + +QBCore.Functions.CreateCallback('nc-gardening:cooldown', function(source, cb) + if Cooldown then + cb(true) + else + cb(false) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-impound/LICENSE b/resources/[qb]/[qb_jobs]/qb-impound/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-impound/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/qb-impound/README.md b/resources/[qb]/[qb_jobs]/qb-impound/README.md new file mode 100644 index 0000000..f2814f9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-impound/README.md @@ -0,0 +1,14 @@ +# qb-impound + +| Join my discord server [here](https://discord.gg/A4gVRjnvaE) | +| ------------------------------------------------------------ | + +## Preview: https://youtu.be/ABe_0ZXW_bY + +## How to Install +1. Drag qb-impound into your resources folder then ensure qb-impound in your cfg file. + + +## Dependencies +# QBCore - https://github.com/qbcore-framework/qb-core +# qb-target - https://github.com/qbcore-framework/qb-target diff --git a/resources/[qb]/[qb_jobs]/qb-impound/client/main.lua b/resources/[qb]/[qb_jobs]/qb-impound/client/main.lua new file mode 100644 index 0000000..34ddb26 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-impound/client/main.lua @@ -0,0 +1,74 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local bones = {'bonnet', 'boot'} + +CreateThread(function() + exports['qb-target']:AddTargetBone(bones, { + options = { + ["Impound"] = { + icon = "fas fa-lock", + label = "Bugserings anmodning", + event = "qb-impound:client:OpenImpoundMenu", + distance = 1.3 + } + } + }) +end) + + +RegisterNetEvent('qb-impound:client:OpenImpoundMenu', function() + exports['qb-menu']:openMenu({ + { + header = "Køretøj vraget", + txt = "Køretøj i en ikke-bugserbar tilstand.", + params = { + event = "qb-impound:client:VehicleScuff", + } + }, + { + header = "Parkerings overtrædelse", + txt = "Køretøj parkeret på et begrænset eller uautoriseret sted.", + params = { + event = "qb-impound:client:ParkingViolation", + } + }, + { + header = "Politiets opbevaring", + txt = "Sender køretøjet til politiets opbevaringsplads.", + params = { + event = "qb-impound:client:PDImpound", + } + }, + }) +end) + +RegisterNetEvent('qb-impound:client:VehicleScuff', function() + QBCore.Functions.Progressbar("random_task", "Anmoder om bugsering...", 7000, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() -- Done + TriggerServerEvent("qb-impound:server:VehicS") + QBCore.Functions.Notify("Bugsering godkendt", "success") + end, function() -- Cancel + end) +end) + +RegisterNetEvent('qb-impound:client:ParkingViolation', function() + QBCore.Functions.Progressbar("random_task", "Anmoder om bugsering...", 7000, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + }, {}, {}, function() -- Done + TriggerServerEvent("qb-impound:server:ParkingVio") + end, function() -- Cancel + end) +end) + +RegisterNetEvent('qb-impound:client:PDImpound', function() + TriggerServerEvent("qb-impound:server:PDIm") + QBCore.Functions.Notify("Bugsering godkendt", "success") +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-impound/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-impound/fxmanifest.lua new file mode 100644 index 0000000..fefebd4 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-impound/fxmanifest.lua @@ -0,0 +1,19 @@ +fx_version 'cerulean' +game 'gta5' + +version 'V1.0' + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + 'client/main.lua', +} + +server_scripts { + 'server/main.lua', +} + +dependencies { + 'PolyZone', + 'qb-target', +} diff --git a/resources/[qb]/[qb_jobs]/qb-impound/server/main.lua b/resources/[qb]/[qb_jobs]/qb-impound/server/main.lua new file mode 100644 index 0000000..3dda910 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-impound/server/main.lua @@ -0,0 +1,31 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +RegisterServerEvent('qb-impound:server:VehicS', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + TriggerClientEvent('QBCore:Command:DeleteVehicle', src) + TriggerEvent('qb-log:server:CreateLog', 'default', 'Skrot køretøj', "lightgreen", (Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname).. " har skrottet et køretøj.") +end) + +RegisterServerEvent('qb-impound:server:ParkingVio', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.job.name == "police" then + TriggerClientEvent('QBCore:Command:DeleteVehicle', src) + TriggerClientEvent('QBCore:Notify', src, 'Bugsering godkendt.', 'success') + TriggerEvent('qb-log:server:CreateLog', 'default', 'Parkingerings overtrædelse', "lightgreen", (Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname).. " har bugseret et køretøj for en parkerings overtrædelse.") + else + TriggerClientEvent('QBCore:Notify', src, 'Du er ikke en politibetjent.', 'error') + end +end) + +RegisterServerEvent('qb-impound:server:PDIm', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if Player.PlayerData.job.name == "police" then + TriggerClientEvent("police:client:ImpoundVehicle", src, true) + TriggerEvent('qb-log:server:CreateLog', 'default', 'Politiets opbevering', "lightgreen", (Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname).. " har sendt et køretøj til politiets opbevaring.") + else + TriggerClientEvent('QBCore:Notify', src, 'Du er ikke en politibetjent.', 'error') + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/bug_report.md b/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..62f702f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve or fix something +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. A stranger to qbcore should be able to read your bug report and understand how to reproduce it themselves and understand how the feature should work normally. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Use this item '....' (item's name from shared.lua if applicable) +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Questions (please complete the following information):** + - When you last updated: [e.g. last week] + - Are you using custom resource? which ones? [e.g. zdiscord, qb-target] + - Have you renamed `qb-` to something custom? [e.g. yes/no] + +**Additional context** +Add any other context about the problem here. diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/feature-request.md b/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..9e9bf3e --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: Suggest an idea for QBCore +title: "[SUGGESTION]" +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. + +**Describe the feature you'd like** +A clear and concise description of what you want to happen. and with as much detail as possible how it would function in your opinion. Please try to keep it unique. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered for people to have in mind just in case the main idea isn't liked but a derivative is. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/auto_assign.yml b/resources/[qb]/[qb_jobs]/qb-policejob/.github/auto_assign.yml new file mode 100644 index 0000000..2a80921 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/auto_assign.yml @@ -0,0 +1,17 @@ +# Set to true to add reviewers to pull requests +addReviewers: true + +# Set to true to add assignees to pull requests +addAssignees: author + +# A list of reviewers to be added to pull requests (GitHub user name) +reviewers: + - /maintenance + +# A list of keywords to be skipped the process that add reviewers if pull requests include it +skipKeywords: + - wip + +# A number of reviewers added to the pull request +# Set 0 to add all the reviewers (default: 0) +numberOfReviewers: 0 \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/contributing.md b/resources/[qb]/[qb_jobs]/qb-policejob/.github/contributing.md new file mode 100644 index 0000000..21fb806 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/contributing.md @@ -0,0 +1,201 @@ +# Contributing to QBCore + +First of all, thank you for taking the time to contribute! + +These guidelines will help you help us in the best way possible regardless of your skill level. We ask that you try to read everything related to the way you'd like to contribute and try and use your best judgement for anything not covered. + +### Table of Contents + +[Code of Conduct](#code-of-conduct) + +[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) + +[How Can I Contribute?](#how-can-i-contribute) + * [Reporting Bugs](#reporting-bugs) + * [Suggesting Features / Enhancements](#suggesting-features--enhancements) + * [Your First Code Contribution](#your-first-code-contribution) + * [Pull Requests](#pull-requests) + +[Styleguides](#styleguides) + * [Git Commit Messages](#git-commit-messages) + * [Lua Styleguide](#lua-styleguide) + * [JavaScript Styleguide](#javascript-styleguide) + + + +## Code of Conduct + +- Refrain from using languages other than English. +- Refrain from discussing any politically charged or inflammatory topics. +- Uphold mature conversations and respect each other; excessive profanity, hate speech or any kind of harassment will not be tolerated. +- No advertising of any kind. +- Follow these guidelines. +- Do not mention members of github unless a question is directed at them and can't be answered by anyone else. +- Do not mention any of the development team for any reason. We will read things as we get to them. + +## I don't want to read this whole thing I just have a question!!! + +> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below. + +* [QBCore Website](https://qbcore.org) +* [QBCore Discord](https://discord.gg/qbcore) +* [FiveM Discord - #qbcore channel](https://discord.gg/fivem) + + + + + + + + + + +## How Can I Contribute? + +### Reporting Bugs + +The easiest way to contribute for most people is just to report bugs you find cause if nobody reports it there's a chance we'll never know it exists and then we'll never fix it. + +Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out the bug-report template with the information it asks for helps us resolve issues faster. + +> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. + +#### Before Submitting A Bug Report + +* **Check the docs** There's a chance what you see as a bug might just work differently than you expect and if you think it could work better consider a feature enhancement report instead. +* **Search the [discord](https://discord.gg/qbcore)** to see if anyone else has run into the issue and see if it was solved through user error or code changes. (if the code change isn't pending a PR and you know what you're doing consider submitting one following [Pull Requests](#pull-requests) ) +* **Determine which resource the problem should be reported in**. If the bug is related to the inventory for example report this bug under qb-inventory rather than under qb-core or some other resource. +* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aqbcore-framework)** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Bug Report? + +Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined which resource your bug is related to, create an issue on that repository and provide the following information by filling in bug-report template. + +Explain the problem and include additional details to help maintainers reproduce the problem: + +* **Use a clear and descriptive title** for the issue to identify the problem. +* **Describe the exact steps which reproduce the problem** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. If something happened with only a specific group or single item but not others, specify that. +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +* **Explain which behavior you expected to see instead and why.** +* **Include screenshots** which show the specific bug in action or before and after. +* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. + +Provide more context by answering these questions if possible: + +* **Did the problem start happening recently** (e.g. after updating to a new version of QBCore?) or was this always a problem? +* If the problem started happening recently, **can you reproduce the problem in an older version of QBCore?** What's the most recent commit in which the problem doesn't happen? +* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. + +Include details about your setup: + +* **When was your QBCore last updated?** +* **What OS is the server running on**? +* **Which *extra* resources do you have installed?** + + +--- + + +### Suggesting Features / Enhancements + +This section guides you through submitting an enhancement suggestion for QBCore, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion. + +Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in feature request template, including the steps that you imagine you would take if the feature you're requesting existed. + +#### Before Submitting An Enhancement Suggestion + +* **Make sure it doesn't already exist.** Sounds silly, but there's a lot of features built in to qbcore that people don't realize so take a look through the docs and stuff to make sure it's not already there. +* **Check if there's already PR which provides that enhancement.** +* **Determine which resource the enhancement should be suggested in.** if it fits with another resource suggest it in that resource. if it would be it's own resource suggest it in the main qb-core repository. +* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aqbcore-framework)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined which resource your enhancement suggestion is related to, create an issue on that repository and provide the following information: + +* **Use a clear and descriptive title** for the issue to identify the suggestion. +* **Provide a step-by-step description of the suggested enhancement** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of QBCore which the suggestion is related to. +* **Explain why this enhancement would be useful.** +* **Be creative and unique.** Stealing ideas from popular servers 1:1 detail isn't going to get accepted. + + +--- + + + +### Your First Code Contribution + +Unsure where to begin contributing to QBCore? You can start by looking through these `beginner` and `help-wanted` issues. + + + +--- + + +### Pull Requests + +The process described here has several goals: + +- Maintain QBCore's quality. +- Fix problems that are important to users. +- Engage the community in working toward the best possible QBCore. +- Enable a sustainable system for QBCore's maintainers to review contributions. + +Please follow these steps to have your contribution considered by the maintainers: + +1. Follow all instructions in The Pull Request template. +2. Follow the [styleguides](#styleguides). +3. Await review by the reviewer(s). + +While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted. + + +--- + +## Styleguides + +### Git Commit Messages + +* Limit the first line to 72 characters or less. +* Reference issues and pull requests liberally after the first line. +* Consider starting the commit message with an applicable emoji: + * :art: `:art:` when improving the format/structure of the code + * :racehorse: `:racehorse:` when improving performance + * :memo: `:memo:` when writing docs + * :bug: `:bug:` when fixing a bug + * :fire: `:fire:` when removing code or files + * :white_check_mark: `:white_check_mark:` when adding tests + * :lock: `:lock:` when dealing with security + * :arrow_up: `:arrow_up:` when upgrading dependencies + * :arrow_down: `:arrow_down:` when downgrading dependencies + * :shirt: `:shirt:` when removing linter warnings + +### Lua Styleguide + +All lua code should be done using all the best practices of proper lua using the easiest to read yet fastest/most optimized methods of execution. + +- Use 4 Space indentation +- Aim for lua 5.4 (include `lua54 'yes'` in the fxmanifest.lua) +- Use `PlayerPedId()` instead of `GetPlayerPed(-1)` +- Use `#(vector3 - vector3)` instead of `GetDistanceBetweenCoords()` +- Don't create unnecessary threads. always try to find a better method of triggering events +- Don't repeat yourself.. if you're using the same operations in many different places convert them into a function with flexible variables +- For distance checking loops set longer waits if you're outside of a range +- Job specific loops should only run for players with that job, don't waste cycles +- When possible don't trust the client, esspecially with transactions +- Balance security and optimizations +- [Consider this Lua Performance guide](https://springrts.com/wiki/Lua_Performance) +- Use local varriables everywhere possible +- Make use of config options where it makes sense making features optional or customizable +- Instead of `table.insert(myTable, "Value")` use `myTable[#myTable + 1] = "Value"` +- Instead of `table.insert(ages, "bob", 30)` use `ages["bob"] = 30` + + +### JavaScript Styleguide + +- Use 4 Space indentation +- Don't repeat yourself.. if you're using the same operations in many different places convert them into a function with flexible variables. diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/pull_request_template.md b/resources/[qb]/[qb_jobs]/qb-policejob/.github/pull_request_template.md new file mode 100644 index 0000000..000f0f9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/pull_request_template.md @@ -0,0 +1,10 @@ +**Describe Pull request** +First, make sure you've read and are following the contribution guidelines and style guide and your code reflects that. +Write up a clear and concise description of what your pull request adds or fixes and if it's an added feature explain why you think it should be included in the core. + +If your PR is to fix an issue mention that issue here + +**Questions (please complete the following information):** +- Have you personally loaded this code into an updated qbcore project and checked all it's functionality? [yes/no] (Be honest) +- Does your code fit the style guidelines? [yes/no] +- Does your PR fit the contribution guidelines? [yes/no] diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/.github/workflows/lint.yml b/resources/[qb]/[qb_jobs]/qb-policejob/.github/workflows/lint.yml new file mode 100644 index 0000000..fb74fd6 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint +on: [push, pull_request_target] +jobs: + lint: + name: Lint Resource + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Lint + uses: iLLeniumStudios/fivem-lua-lint-action@v2 + with: + capture: "junit.xml" + args: "-t --formatter JUnit" + extra_libs: mysql+polyzone+qblocales + - name: Generate Lint Report + if: always() + uses: mikepenz/action-junit-report@v3 + with: + report_paths: "**/junit.xml" + check_name: Linting Report + fail_on_failure: false \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/LICENSE b/resources/[qb]/[qb_jobs]/qb-policejob/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/README.md b/resources/[qb]/[qb_jobs]/qb-policejob/README.md new file mode 100644 index 0000000..deae6f7 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/README.md @@ -0,0 +1,499 @@ +# qb-policejob +Police Job for QB-Core Framework :police_officer: + +# License + + QBCore Framework + Copyright (C) 2021 Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + +## Dependencies +- [qb-core](https://github.com/qbcore-framework/qb-core) +- [qb-bossmenu](https://github.com/qbcore-framework/qb-bossmenu) (Deprecated) - For the boss menu +- [qb-management](https://github.com/qbcore-framework/qb-management) (Replaces qb-bossmenu) - For the boss/gang menu +- [qb-garages](https://github.com/qbcore-framework/qb-garages) - For the vehicle spawner +- [qb-clothing](https://github.com/qbcore-framework/qb-clothing) - For the locker room +- [qb-phone](https://github.com/qbcore-framework/qb-phone) - For the MEOS app and notifications etc. +- [qb-log](https://github.com/qbcore-framework/qb-logs) - (Deprecated) - For logging certain events +- [qb-smallresources](https://github.com/qbcore-framework/qb-smallresources) (Replaces qb-log) - qb-log was added to qb-smallresources +- [qb-menu](https://github.com/qbcore-framework/qb-menu) - For the vehicle menus +- [qb-input](https://github.com/qbcore-framework/qb-input) - For accessing evidence stashes + + +## Screenshots +![On Duty / Off Duty](https://imgur.com/KO2ydlt.png) +![Whitelisted Police Armory](https://imgur.com/TQVIYFb.png) +![Whitelisted Police Stash](https://imgur.com/Hh2fbs4.png) +![Vehicle Spawner](https://imgur.com/plgZ9oD.png) +![Helicopter Spawner](https://imgur.com/jE2IoqK.png) +![Fingerprint Scan](https://imgur.com/btmurxh.png) +![Evidence Stash](https://imgur.com/KBOoUy5.png) +![Spike Placing](https://imgur.com/mTN6c0h.png) +![Object Placing](https://imgur.com/7Jate4f.png) +![Police Alert](https://imgur.com/rAIiWYH.png) +![Securty Cam](https://imgur.com/vFr8nWf.png) + +## Features +- Classical requirements like on duty/off duty, clothing, vehicle, stash etc. +- Citizen ID based armory (Whitelisted) +- Fingerprint test +- Evidence locker (stash) +- Whitelisted vehicles +- Speed radars across the map +- Stormram +- Impounding player vehicle (permanent / for an amount of money) +- Integrated jail system +- Bullet casings +- GSR +- Blood drop +- Evidence bag & Money bag +- Police radar +- Handcuff as an item (Can used via command too. Check Commands section.) +- Emergency services can see each other on map + +### Commands +- /spikestrip - Places spike strip on ground. +- /pobject [pion/barier/schotten/tent/light/delete] - Places or deletes an object on/from ground. +- /cuff - Cuffs/Uncuffs nearby player +- /escort - Escorts nearby plyer. +- /callsign [text] - Sets the player a callsign on database. +- /clearcasings - Clears nearby bullet casings. +- /jail [id] [time] - Sends a player to the jail. +- /unjail [id] - Takes the player out of jail. +- /clearblood - Clears nearby blood drops. +- /seizecash - Seizes nearby player's cash. (Puts in money bag) +- /sc - Puts soft cuff on nearby player. +- /cam [cam] - Shows the selected security cam display. +- /flagplate [plate] [reason] - Flags the vehicle. +- /unflagplate [plate] - Removes the flag of a vehicle. +- /plateinfo [plate] - Displays if a vehicle is marked or not. +- /depot [price] - Depots nearby vehicle. Player can take it after paying the cost. +- /impound - Impounds nearby vehicle permanently. +- /paytow [id] - Makes payment to the tow driver. +- /paylawyer [id] - Makes payment to the lawyer. +- /radar - Toggles the police radar. +- /911 [message] - Sends a report to emergency services. +- /911r [id] - Used to respond the emergency alerts. +- /911a [message] - Sends an anonymous report to emergency services (gives no location). +- /anklet - Places anklet (tracking device) on nearby player. +- /removeanklet [citizenid] - Removes the anklet from player. +- /ebutton - Used to respond an emergency alert. +- /takedrivinglicense - Takes the driving license from nearby player. +- /takedna [id] - Takes a DNA sample from the player. + +## Installation +### Manual +- Download the script and put it in the `[qb]` directory. +- Add the following code to your server.cfg/resouces.cfg +``` +ensure qb-core +ensure qb-policejob +``` + +## Configuration +``` +Config = {} + +Config.Objects = { -- Objects to be placed with /pobject [object] + ["cone"] = {model = `prop_roadcone02a`, freeze = false}, + ["barier"] = {model = `prop_barrier_work06a`, freeze = true}, + ["schotten"] = {model = `prop_snow_sign_road_06g`, freeze = true}, + ["tent"] = {model = `prop_gazebo_03`, freeze = true}, + ["light"] = {model = `prop_worklight_03b`, freeze = true}, +} + +Config.Locations = { + ["duty"] = { -- On Duty/Off Duty Marker + [1] = vector4(440.085, -974.924, 30.689, 90.654), + [2] = vector4(-449.811, 6012.909, 31.815, 90.654), + }, + ["vehicle"] = { -- Vehicle Spawner Marker + [1] = vector4(448.159, -1017.41, 28.562, 90.654), + [2] = vector4(471.13, -1024.05, 28.17, 274.5), + [3] = vector4(-455.39, 6002.02, 31.34, 87.93), + }, + ["stash"] = { -- Stash Marker + [1] = vector4(453.075, -980.124, 30.889, 90.654), + }, + ["impound"] = { -- Impounded Vehicles Marker + [1] = vector4(436.68, -1007.42, 27.32, 180.0), + [2] = vector4(-436.14, 5982.63, 31.34, 136.0), + }, + ["helicopter"] = { -- Helicopter Spawner Marker + [1] = vector4(449.168, -981.325, 43.691, 87.234), + [2] = vector4(-475.43, 5988.353, 31.716, 31.34), + }, + ["armory"] = { -- Armory Marker + [1] = vector4(462.23, -981.12, 30.68, 90.654), + }, + ["trash"] = { -- Trash Marker + [1] = vector4(439.0907, -976.746, 30.776, 93.03), + }, + ["fingerprint"] = { -- Fingerprint Scan Marker + [1] = vector4(460.9667, -989.180, 24.92, 358.5), + }, + ["evidence"] = { -- Evidence Closet 1 Marker + [1] = vector4(442.1722, -996.067, 30.689, 187.5), + }, + ["evidence2"] = { -- Evidence Closet 2 Marker + [1] = vector4(451.7031, -973.232, 30.689, 1.741), + }, + ["evidence3"] = { -- Evidence Closet 3 Marker + [1] = vector4(455.1456, -985.462, 30.689, 2.854), + }, + ["stations"] = { -- Police Stations Blips + [1] = {label = "Police Station", coords = vector4(428.23, -984.28, 29.76, 3.5)}, + [2] = {label = "Prison", coords = vector4(1845.903, 2585.873, 45.672, 272.249)}, + [3] = {label = "Police Station Paleto", coords = vector4(-451.55, 6014.25, 31.716, 223.81)}, + }, +} + +Config.ArmoryWhitelist = {} -- Citizen ID Based Armory Whitelist (With Export for Other Scripts) + + +Config.Helicopter = "POLMAV" -- Model of the Helicopter for Helicopter Spawner + +Config.SecurityCameras = { -- Security Cam Locations + hideradar = false, -- Don't change + cameras = { + [1] = {label = "Pacific Bank CAM#1", coords = vector3(257.45, 210.07, 109.08), r = {x = -25.0, y = 0.0, z = 28.05}, canRotate = false, isOnline = true}, + [2] = {label = "Pacific Bank CAM#2", coords = vector3(232.86, 221.46, 107.83), r = {x = -25.0, y = 0.0, z = -140.91}, canRotate = false, isOnline = true}, + [3] = {label = "Pacific Bank CAM#3", coords = vector3(252.27, 225.52, 103.99), r = {x = -35.0, y = 0.0, z = -74.87}, canRotate = false, isOnline = true}, + [4] = {label = "Limited Ltd Grove St. CAM#1", coords = vector3(-53.1433, -1746.714, 31.546), r = {x = -35.0, y = 0.0, z = -168.9182}, canRotate = false, isOnline = true}, + [5] = {label = "Rob's Liqour Prosperity St. CAM#1", coords = vector3(-1482.9, -380.463, 42.363), r = {x = -35.0, y = 0.0, z = 79.53281}, canRotate = false, isOnline = true}, + [6] = {label = "Rob's Liqour San Andreas Ave. CAM#1", coords = vector3(-1224.874, -911.094, 14.401), r = {x = -35.0, y = 0.0, z = -6.778894}, canRotate = false, isOnline = true}, + [7] = {label = "Limited Ltd Ginger St. CAM#1", coords = vector3(-718.153, -909.211, 21.49), r = {x = -35.0, y = 0.0, z = -137.1431}, canRotate = false, isOnline = true}, + [8] = {label = "24/7 Supermarkt Innocence Blvd. CAM#1", coords = vector3(23.885, -1342.441, 31.672), r = {x = -35.0, y = 0.0, z = -142.9191}, canRotate = false, isOnline = true}, + [9] = {label = "Rob's Liqour El Rancho Blvd. CAM#1", coords = vector3(1133.024, -978.712, 48.515), r = {x = -35.0, y = 0.0, z = -137.302}, canRotate = false, isOnline = true}, + [10] = {label = "Limited Ltd West Mirror Drive CAM#1", coords = vector3(1151.93, -320.389, 71.33), r = {x = -35.0, y = 0.0, z = -119.4468}, canRotate = false, isOnline = true}, + [11] = {label = "24/7 Supermarkt Clinton Ave CAM#1", coords = vector3(383.402, 328.915, 105.541), r = {x = -35.0, y = 0.0, z = 118.585}, canRotate = false, isOnline = true}, + [12] = {label = "Limited Ltd Banham Canyon Dr CAM#1", coords = vector3(-1832.057, 789.389, 140.436), r = {x = -35.0, y = 0.0, z = -91.481}, canRotate = false, isOnline = true}, + [13] = {label = "Rob's Liqour Great Ocean Hwy CAM#1", coords = vector3(-2966.15, 387.067, 17.393), r = {x = -35.0, y = 0.0, z = 32.92229}, canRotate = false, isOnline = true}, + [14] = {label = "24/7 Supermarkt Ineseno Road CAM#1", coords = vector3(-3046.749, 592.491, 9.808), r = {x = -35.0, y = 0.0, z = -116.673}, canRotate = false, isOnline = true}, + [15] = {label = "24/7 Supermarkt Barbareno Rd. CAM#1", coords = vector3(-3246.489, 1010.408, 14.705), r = {x = -35.0, y = 0.0, z = -135.2151}, canRotate = false, isOnline = true}, + [16] = {label = "24/7 Supermarkt Route 68 CAM#1", coords = vector3(539.773, 2664.904, 44.056), r = {x = -35.0, y = 0.0, z = -42.947}, canRotate = false, isOnline = true}, + [17] = {label = "Rob's Liqour Route 68 CAM#1", coords = vector3(1169.855, 2711.493, 40.432), r = {x = -35.0, y = 0.0, z = 127.17}, canRotate = false, isOnline = true}, + [18] = {label = "24/7 Supermarkt Senora Fwy CAM#1", coords = vector3(2673.579, 3281.265, 57.541), r = {x = -35.0, y = 0.0, z = -80.242}, canRotate = false, isOnline = true}, + [19] = {label = "24/7 Supermarkt Alhambra Dr. CAM#1", coords = vector3(1966.24, 3749.545, 34.143), r = {x = -35.0, y = 0.0, z = 163.065}, canRotate = false, isOnline = true}, + [20] = {label = "24/7 Supermarkt Senora Fwy CAM#2", coords = vector3(1729.522, 6419.87, 37.262), r = {x = -35.0, y = 0.0, z = -160.089}, canRotate = false, isOnline = true}, + [21] = {label = "Fleeca Bank Hawick Ave CAM#1", coords = vector3(309.341, -281.439, 55.88), r = {x = -35.0, y = 0.0, z = -146.1595}, canRotate = false, isOnline = true}, + [22] = {label = "Fleeca Bank Legion Square CAM#1", coords = vector3(144.871, -1043.044, 31.017), r = {x = -35.0, y = 0.0, z = -143.9796}, canRotate = false, isOnline = true}, + [23] = {label = "Fleeca Bank Hawick Ave CAM#2", coords = vector3(-355.7643, -52.506, 50.746), r = {x = -35.0, y = 0.0, z = -143.8711}, canRotate = false, isOnline = true}, + [24] = {label = "Fleeca Bank Del Perro Blvd CAM#1", coords = vector3(-1214.226, -335.86, 39.515), r = {x = -35.0, y = 0.0, z = -97.862}, canRotate = false, isOnline = true}, + [25] = {label = "Fleeca Bank Great Ocean Hwy CAM#1", coords = vector3(-2958.885, 478.983, 17.406), r = {x = -35.0, y = 0.0, z = -34.69595}, canRotate = false, isOnline = true}, + [26] = {label = "Paleto Bank CAM#1", coords = vector3(-102.939, 6467.668, 33.424), r = {x = -35.0, y = 0.0, z = 24.66}, canRotate = false, isOnline = true}, + [27] = {label = "Del Vecchio Liquor Paleto Bay", coords = vector3(-163.75, 6323.45, 33.424), r = {x = -35.0, y = 0.0, z = 260.00}, canRotate = false, isOnline = true}, + [28] = {label = "Don's Country Store Paleto Bay CAM#1", coords = vector3(166.42, 6634.4, 33.69), r = {x = -35.0, y = 0.0, z = 32.00}, canRotate = false, isOnline = true}, + [29] = {label = "Don's Country Store Paleto Bay CAM#2", coords = vector3(163.74, 6644.34, 33.69), r = {x = -35.0, y = 0.0, z = 168.00}, canRotate = false, isOnline = true}, + [30] = {label = "Don's Country Store Paleto Bay CAM#3", coords = vector3(169.54, 6640.89, 33.69), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = false, isOnline = true}, + [31] = {label = "Vangelico Jewelery CAM#1", coords = vector3(-627.54, -239.74, 40.33), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = true, isOnline = true}, + [32] = {label = "Vangelico Jewelery CAM#2", coords = vector3(-627.51, -229.51, 40.24), r = {x = -35.0, y = 0.0, z = -95.78}, canRotate = true, isOnline = true}, + [33] = {label = "Vangelico Jewelery CAM#3", coords = vector3(-620.3, -224.31, 40.23), r = {x = -35.0, y = 0.0, z = 165.78}, canRotate = true, isOnline = true}, + [34] = {label = "Vangelico Jewelery CAM#4", coords = vector3(-622.57, -236.3, 40.31), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = true, isOnline = true}, + }, +} + +Config.AuthorizedVehicles = { -- Police Vehicles and required grade + -- Grade 0 + [0] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 1 + [1] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + + }, + -- Grade 2 + [2] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 3 + [3] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 4 + [4] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + } +} + +Config.WhitelistedVehicles = {} + +Config.AmmoLabels = { -- Labels for Weapon Ammo + ["AMMO_PISTOL"] = "9x19mm parabellum bullet", + ["AMMO_SMG"] = "9x19mm parabellum bullet", + ["AMMO_RIFLE"] = "7.62x39mm bullet", + ["AMMO_MG"] = "7.92x57mm mauser bullet", + ["AMMO_SHOTGUN"] = "12-gauge bullet", + ["AMMO_SNIPER"] = "Large caliber bullet", +} + +Config.Radars = { -- Radar Locations + vector4(-623.44421386719, -823.08361816406, 25.25704574585, 145.0), + vector4(-652.44421386719, -854.08361816406, 24.55704574585, 325.0), + vector4(1623.0114746094, 1068.9924316406, 80.903594970703, 84.0), + vector4(-2604.8994140625, 2996.3391113281, 27.528566360474, 175.0), + vector4(2136.65234375, -591.81469726563, 94.272926330566, 318.0), + vector4(2117.5764160156, -558.51013183594, 95.683128356934, 158.0), + vector4(406.89505004883, -969.06286621094, 29.436267852783, 33.0), + vector4(657.315, -218.819, 44.06, 320.0), + vector4(2118.287, 6040.027, 50.928, 172.0), + vector4(-106.304, -1127.5530, 30.778, 230.0), + vector4(-823.3688, -1146.980, 8.0, 300.0), +} + +Config.CarItems = { -- Default Trunk Items for Police Vehicles + [1] = { + name = "heavyarmor", + amount = 2, + info = {}, + type = "item", + slot = 1, + }, + [2] = { + name = "empty_evidence_bag", + amount = 10, + info = {}, + type = "item", + slot = 2, + }, + [3] = { + name = "police_stormram", + amount = 1, + info = {}, + type = "item", + slot = 3, + }, +} + +Config.Items = { -- Items to be displayed on Armory + label = "Police Armory", + slots = 30, + items = { + [1] = { + name = "weapon_pistol", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_PI_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 1, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [2] = { + name = "weapon_stungun", + price = 0, + amount = 1, + info = { + serie = "", + }, + type = "weapon", + slot = 2, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [3] = { + name = "weapon_pumpshotgun", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 3, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [4] = { + name = "weapon_smg", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_SCOPE_MACRO_02", label = "1x Scope"}, + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 4, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [5] = { + name = "weapon_carbinerifle", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + {component = "COMPONENT_AT_SCOPE_MEDIUM", label = "3x Scope"}, + } + }, + type = "weapon", + slot = 5, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [6] = { + name = "weapon_nightstick", + price = 0, + amount = 1, + info = {}, + type = "weapon", + slot = 6, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [7] = { + name = "pistol_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 7, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [8] = { + name = "smg_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 8, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [9] = { + name = "shotgun_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 9, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [10] = { + name = "rifle_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 10, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [11] = { + name = "handcuffs", + price = 0, + amount = 1, + info = {}, + type = "item", + slot = 11, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [12] = { + name = "weapon_flashlight", + price = 0, + amount = 1, + info = {}, + type = "weapon", + slot = 12, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [13] = { + name = "empty_evidence_bag", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 13, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [14] = { + name = "police_stormram", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 14, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [15] = { + name = "armor", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 15, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [16] = { + name = "radio", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 16, + authorizedJobGrades = {0, 1, 2, 3, 4} + }, + [17] = { + name = "heavyarmor", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 17, + authorizedJobGrades = {0, 1, 2, 3, 4} + } + } +} +``` diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/anpr.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/anpr.lua new file mode 100644 index 0000000..49e6641 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/anpr.lua @@ -0,0 +1,62 @@ +local lastRadar = nil +local HasAlreadyEnteredMarker = false +-- Determines if player is close enough to trigger cam +function HandlespeedCam(speedCam, hasBeenBusted) + local myPed = PlayerPedId() + local playerPos = GetEntityCoords(myPed) + local isInMarker = false + if #(playerPos - vector3(speedCam.x, speedCam.y, speedCam.z)) < 20.0 then + isInMarker = true + end + + if isInMarker and not HasAlreadyEnteredMarker and lastRadar == nil then + HasAlreadyEnteredMarker = true + lastRadar = hasBeenBusted + + local vehicle = GetPlayersLastVehicle() -- gets the current vehicle the player is in. + if IsPedInAnyVehicle(myPed, false) then + if GetPedInVehicleSeat(vehicle, -1) == myPed then + if GetVehicleClass(vehicle) ~= 18 then + local plate = QBCore.Functions.GetPlate(vehicle) + QBCore.Functions.TriggerCallback('police:IsPlateFlagged', function(result) + if result then + local coords = GetEntityCoords(PlayerPedId()) + local blipsettings = { + x = coords.x, + y = coords.y, + z = coords.z, + sprite = 488, + color = 1, + scale = 0.9, + text = "Speed camera #"..hasBeenBusted.." - Marked vehicle" + } + local s1, s2 = GetStreetNameAtCoord(coords.x, coords.y, coords.z) + local street1 = GetStreetNameFromHashKey(s1) + local street2 = GetStreetNameFromHashKey(s2) + TriggerServerEvent("police:server:FlaggedPlateTriggered", hasBeenBusted, plate, street1, street2, blipsettings) + end + end, plate) + end + end + end + end + + if not isInMarker and HasAlreadyEnteredMarker and lastRadar == hasBeenBusted then + HasAlreadyEnteredMarker = false + lastRadar = nil + end +end + +CreateThread(function() + while true do + Wait(1) + if IsPedInAnyVehicle(PlayerPedId(), false) then + for key, value in pairs(Config.Radars) do + HandlespeedCam(value, key) + end + Wait(200) + else + Wait(2500) + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/camera.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/camera.lua new file mode 100644 index 0000000..e1f3ef3 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/camera.lua @@ -0,0 +1,205 @@ +local currentCameraIndex = 0 +local createdCamera = 0 + +local function GetCurrentTime() + local hours = GetClockHours() + local minutes = GetClockMinutes() + if hours < 10 then + hours = tostring(0 .. GetClockHours()) + end + if minutes < 10 then + minutes = tostring(0 .. GetClockMinutes()) + end + return tostring(hours .. ":" .. minutes) +end + +local function ChangeSecurityCamera(x, y, z, r) + if createdCamera ~= 0 then + DestroyCam(createdCamera, 0) + createdCamera = 0 + end + + local cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", 1) + SetCamCoord(cam, x, y, z) + SetCamRot(cam, r.x, r.y, r.z, 2) + RenderScriptCams(1, 0, 0, 1, 1) + Wait(250) + createdCamera = cam +end + +local function CloseSecurityCamera() + DestroyCam(createdCamera, 0) + RenderScriptCams(0, 0, 1, 1, 1) + createdCamera = 0 + ClearTimecycleModifier("scanline_cam_cheap") + SetFocusEntity(GetPlayerPed(PlayerId())) + if Config.SecurityCameras.hideradar then + DisplayRadar(true) + end + FreezeEntityPosition(GetPlayerPed(PlayerId()), false) +end + +local function InstructionButton(ControlButton) + ScaleformMovieMethodAddParamPlayerNameString(ControlButton) +end + +local function InstructionButtonMessage(text) + BeginTextCommandScaleformString("STRING") + AddTextComponentScaleform(text) + EndTextCommandScaleformString() +end + +local function CreateInstuctionScaleform(scaleform) + scaleform = RequestScaleformMovie(scaleform) + while not HasScaleformMovieLoaded(scaleform) do + Wait(0) + end + PushScaleformMovieFunction(scaleform, "CLEAR_ALL") + PopScaleformMovieFunctionVoid() + + PushScaleformMovieFunction(scaleform, "SET_CLEAR_SPACE") + PushScaleformMovieFunctionParameterInt(200) + PopScaleformMovieFunctionVoid() + + PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") + PushScaleformMovieFunctionParameterInt(1) + InstructionButton(GetControlInstructionalButton(1, 194, true)) + InstructionButtonMessage(Lang:t('info.close_camera')) + PopScaleformMovieFunctionVoid() + + PushScaleformMovieFunction(scaleform, "DRAW_INSTRUCTIONAL_BUTTONS") + PopScaleformMovieFunctionVoid() + + PushScaleformMovieFunction(scaleform, "SET_BACKGROUND_COLOUR") + PushScaleformMovieFunctionParameterInt(0) + PushScaleformMovieFunctionParameterInt(0) + PushScaleformMovieFunctionParameterInt(0) + PushScaleformMovieFunctionParameterInt(80) + PopScaleformMovieFunctionVoid() + + return scaleform +end + +-- Events +RegisterNetEvent('police:client:ActiveCamera', function(cameraId) + if Config.SecurityCameras.cameras[cameraId] then + DoScreenFadeOut(250) + while not IsScreenFadedOut() do + Wait(0) + end + SendNUIMessage({ + type = "enablecam", + label = Config.SecurityCameras.cameras[cameraId].label, + id = cameraId, + connected = Config.SecurityCameras.cameras[cameraId].isOnline, + time = GetCurrentTime(), + }) + local firstCamx = Config.SecurityCameras.cameras[cameraId].coords.x + local firstCamy = Config.SecurityCameras.cameras[cameraId].coords.y + local firstCamz = Config.SecurityCameras.cameras[cameraId].coords.z + local firstCamr = Config.SecurityCameras.cameras[cameraId].r + SetFocusArea(firstCamx, firstCamy, firstCamz, firstCamx, firstCamy, firstCamz) + ChangeSecurityCamera(firstCamx, firstCamy, firstCamz, firstCamr) + currentCameraIndex = cameraId + DoScreenFadeIn(250) + elseif cameraId == 0 then + DoScreenFadeOut(250) + while not IsScreenFadedOut() do + Wait(0) + end + CloseSecurityCamera() + SendNUIMessage({ + type = "disablecam", + }) + DoScreenFadeIn(250) + else + QBCore.Functions.Notify(Lang:t("error.no_camera"), "error") + end +end) + +RegisterNetEvent('police:client:DisableAllCameras', function() + for k, _ in pairs(Config.SecurityCameras.cameras) do + Config.SecurityCameras.cameras[k].isOnline = false + end +end) + +RegisterNetEvent('police:client:EnableAllCameras', function() + for k, _ in pairs(Config.SecurityCameras.cameras) do + Config.SecurityCameras.cameras[k].isOnline = true + end +end) + +RegisterNetEvent('police:client:SetCamera', function(key, isOnline) + if type(key) == 'table' and table.type(key) == 'array' then + for _, v in pairs(key) do + Config.SecurityCameras.cameras[v].isOnline = isOnline + end + elseif type(key) == 'number' then + Config.SecurityCameras.cameras[key].isOnline = isOnline + else + error('police:client:SetCamera did not receive the right type of key\nreceived type: ' .. type(key) .. '\nreceived value: ' .. key) + end +end) + +-- Threads +CreateThread(function() + while true do + local sleep = 2000 + if createdCamera ~= 0 then + sleep = 5 + local instructions = CreateInstuctionScaleform("instructional_buttons") + DrawScaleformMovieFullscreen(instructions, 255, 255, 255, 255, 0) + SetTimecycleModifier("scanline_cam_cheap") + SetTimecycleModifierStrength(1.0) + + if Config.SecurityCameras.hideradar then + DisplayRadar(false) + end + + -- CLOSE CAMERAS + if IsControlJustPressed(1, 177) then + DoScreenFadeOut(250) + while not IsScreenFadedOut() do + Wait(0) + end + CloseSecurityCamera() + SendNUIMessage({ + type = "disablecam", + }) + DoScreenFadeIn(250) + end + + --------------------------------------------------------------------------- + -- CAMERA ROTATION CONTROLS + --------------------------------------------------------------------------- + if Config.SecurityCameras.cameras[currentCameraIndex].canRotate then + local getCameraRot = GetCamRot(createdCamera, 2) + + -- ROTATE UP + if IsControlPressed(0, 32) then + if getCameraRot.x <= 0.0 then + SetCamRot(createdCamera, getCameraRot.x + 0.7, 0.0, getCameraRot.z, 2) + end + end + + -- ROTATE DOWN + if IsControlPressed(0, 8) then + if getCameraRot.x >= -50.0 then + SetCamRot(createdCamera, getCameraRot.x - 0.7, 0.0, getCameraRot.z, 2) + end + end + + -- ROTATE LEFT + if IsControlPressed(0, 34) then + SetCamRot(createdCamera, getCameraRot.x, 0.0, getCameraRot.z + 0.7, 2) + end + + -- ROTATE RIGHT + if IsControlPressed(0, 9) then + SetCamRot(createdCamera, getCameraRot.x, 0.0, getCameraRot.z - 0.7, 2) + end + end + end + Wait(sleep) + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/evidence.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/evidence.lua new file mode 100644 index 0000000..a21d3d9 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/evidence.lua @@ -0,0 +1,355 @@ +-- Variables +local CurrentStatusList = {} +local Casings = {} +local CurrentCasing = nil +local Blooddrops = {} +local CurrentBlooddrop = nil +local Fingerprints = {} +local CurrentFingerprint = 0 +local shotAmount = 0 + +local StatusList = { + ['fight'] = Lang:t('evidence.red_hands'), + ['widepupils'] = Lang:t('evidence.wide_pupils'), + ['redeyes'] = Lang:t('evidence.red_eyes'), + ['weedsmell'] = Lang:t('evidence.weed_smell'), + ['gunpowder'] = Lang:t('evidence.gunpowder'), + ['chemicals'] = Lang:t('evidence.chemicals'), + ['heavybreath'] = Lang:t('evidence.heavy_breathing'), + ['sweat'] = Lang:t('evidence.sweat'), + ['handbleed'] = Lang:t('evidence.handbleed'), + ['confused'] = Lang:t('evidence.confused'), + ['alcohol'] = Lang:t('evidence.alcohol'), + ["heavyalcohol"] = Lang:t('evidence.heavy_alcohol'), + ["agitated"] = Lang:t('evidence.agitated') +} + +local WhitelistedWeapons = { + `weapon_unarmed`, + `weapon_snowball`, + `weapon_stungun`, + `weapon_petrolcan`, + `weapon_hazardcan`, + `weapon_fireextinguisher` +} + +-- Functions +local function DrawText3D(x, y, z, text) + SetTextScale(0.35, 0.35) + SetTextFont(4) + SetTextProportional(1) + SetTextColour(255, 255, 255, 215) + SetTextEntry('STRING') + SetTextCentre(true) + AddTextComponentString(text) + SetDrawOrigin(x,y,z, 0) + DrawText(0.0, 0.0) + local factor = (string.len(text)) / 370 + DrawRect(0.0, 0.0+0.0125, 0.017+ factor, 0.03, 0, 0, 0, 75) + ClearDrawOrigin() +end + +local function WhitelistedWeapon(weapon) + for i=1, #WhitelistedWeapons do + if WhitelistedWeapons[i] == weapon then + return true + end + end + return false +end + +local function DropBulletCasing(weapon, ped) + local randX = math.random() + math.random(-1, 1) + local randY = math.random() + math.random(-1, 1) + local coords = GetOffsetFromEntityInWorldCoords(ped, randX, randY, 0) + TriggerServerEvent('evidence:server:CreateCasing', weapon, coords) + Wait(300) +end + +local function DnaHash(s) + local h = string.gsub(s, '.', function(c) + return string.format('%02x', string.byte(c)) + end) + return h +end + +-- Events +RegisterNetEvent('evidence:client:SetStatus', function(statusId, time) + if time > 0 and StatusList[statusId] then + if (CurrentStatusList == nil or CurrentStatusList[statusId] == nil) or + (CurrentStatusList[statusId] and CurrentStatusList[statusId].time < 20) then + CurrentStatusList[statusId] = { + text = StatusList[statusId], + time = time + } + QBCore.Functions.Notify(CurrentStatusList[statusId].text, 'error') + end + elseif StatusList[statusId] then + CurrentStatusList[statusId] = nil + end + TriggerServerEvent('evidence:server:UpdateStatus', CurrentStatusList) +end) + +RegisterNetEvent('evidence:client:AddBlooddrop', function(bloodId, citizenid, bloodtype, coords) + Blooddrops[bloodId] = { + citizenid = citizenid, + bloodtype = bloodtype, + coords = { + x = coords.x, + y = coords.y, + z = coords.z - 0.9 + } + } +end) + +RegisterNetEvent('evidence:client:RemoveBlooddrop', function(bloodId) + Blooddrops[bloodId] = nil + CurrentBlooddrop = 0 +end) + +RegisterNetEvent('evidence:client:AddFingerPrint', function(fingerId, fingerprint, coords) + Fingerprints[fingerId] = { + fingerprint = fingerprint, + coords = { + x = coords.x, + y = coords.y, + z = coords.z - 0.9 + } + } +end) + +RegisterNetEvent('evidence:client:RemoveFingerprint', function(fingerId) + Fingerprints[fingerId] = nil + CurrentFingerprint = 0 +end) + +RegisterNetEvent('evidence:client:ClearBlooddropsInArea', function() + local pos = GetEntityCoords(PlayerPedId()) + local blooddropList = {} + QBCore.Functions.Progressbar('clear_blooddrops', Lang:t("progressbar.blood_clear"), 5000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true + }, {}, {}, {}, function() -- Done + if Blooddrops and next(Blooddrops) then + for bloodId, _ in pairs(Blooddrops) do + if #(pos - + vector3(Blooddrops[bloodId].coords.x, Blooddrops[bloodId].coords.y, Blooddrops[bloodId].coords.z)) < + 10.0 then + blooddropList[#blooddropList+1] = bloodId + end + end + TriggerServerEvent('evidence:server:ClearBlooddrops', blooddropList) + QBCore.Functions.Notify(Lang:t("success.blood_clear"), "success") + end + end, function() -- Cancel + QBCore.Functions.Notify(Lang:t("error.blood_not_cleared"), "error") + end) +end) + +RegisterNetEvent('evidence:client:AddCasing', function(casingId, weapon, coords, serie) + Casings[casingId] = { + type = weapon, + serie = serie and serie or Lang:t('evidence.serial_not_visible'), + coords = { + x = coords.x, + y = coords.y, + z = coords.z - 0.9 + } + } +end) + +RegisterNetEvent('evidence:client:RemoveCasing', function(casingId) + Casings[casingId] = nil + CurrentCasing = 0 +end) + +RegisterNetEvent('evidence:client:ClearCasingsInArea', function() + local pos = GetEntityCoords(PlayerPedId()) + local casingList = {} + QBCore.Functions.Progressbar('clear_casings', Lang:t("progressbar.bullet_casing"), 5000, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true + }, {}, {}, {}, function() -- Done + if Casings and next(Casings) then + for casingId, _ in pairs(Casings) do + if #(pos - vector3(Casings[casingId].coords.x, Casings[casingId].coords.y, Casings[casingId].coords.z)) < + 10.0 then + casingList[#casingList+1] = casingId + end + end + TriggerServerEvent('evidence:server:ClearCasings', casingList) + QBCore.Functions.Notify(Lang:t("success.bullet_casing_removed"), "success") + + end + end, function() -- Cancel + QBCore.Functions.Notify(Lang:t("error.bullet_casing_not_removed"), "error") + end) +end) + +-- Threads + +CreateThread(function() + while true do + Wait(10000) + if LocalPlayer.state.isLoggedIn then + if CurrentStatusList and next(CurrentStatusList) then + for k, _ in pairs(CurrentStatusList) do + if CurrentStatusList[k].time > 0 then + CurrentStatusList[k].time = CurrentStatusList[k].time - 10 + else + CurrentStatusList[k].time = 0 + end + end + TriggerServerEvent('evidence:server:UpdateStatus', CurrentStatusList) + end + if shotAmount > 0 then + shotAmount = 0 + end + end + end +end) + +CreateThread(function() -- Gunpowder Status when shooting + while true do + Wait(1) + local ped = PlayerPedId() + if IsPedShooting(ped) then + local weapon = GetSelectedPedWeapon(ped) + if not WhitelistedWeapon(weapon) then + shotAmount = shotAmount + 1 + if shotAmount > 5 and (CurrentStatusList == nil or CurrentStatusList['gunpowder'] == nil) then + if math.random(1, 10) <= 7 then + TriggerEvent('evidence:client:SetStatus', 'gunpowder', 200) + end + end + DropBulletCasing(weapon, ped) + end + end + end +end) + +CreateThread(function() + while true do + Wait(1) + if CurrentCasing and CurrentCasing ~= 0 then + local pos = GetEntityCoords(PlayerPedId()) + if #(pos -vector3(Casings[CurrentCasing].coords.x, Casings[CurrentCasing].coords.y, Casings[CurrentCasing].coords.z)) < 1.5 then + DrawText3D(Casings[CurrentCasing].coords.x, Casings[CurrentCasing].coords.y, Casings[CurrentCasing].coords.z, Lang:t('info.bullet_casing', {value = Casings[CurrentCasing].type})) + if IsControlJustReleased(0, 47) then + local s1, s2 = GetStreetNameAtCoord(Casings[CurrentCasing].coords.x, Casings[CurrentCasing].coords.y, Casings[CurrentCasing].coords.z) + local street1 = GetStreetNameFromHashKey(s1) + local street2 = GetStreetNameFromHashKey(s2) + local streetLabel = street1 + if street2 then + streetLabel = streetLabel .. ' | ' .. street2 + end + local info = { + label = Lang:t('info.casing'), + type = 'casing', + street = streetLabel:gsub("%'", ""), + ammolabel = Config.AmmoLabels[QBCore.Shared.Weapons[Casings[CurrentCasing].type]['ammotype']], + ammotype = Casings[CurrentCasing].type, + serie = Casings[CurrentCasing].serie + } + TriggerServerEvent('evidence:server:AddCasingToInventory', CurrentCasing, info) + end + end + end + + if CurrentBlooddrop and CurrentBlooddrop ~= 0 then + local pos = GetEntityCoords(PlayerPedId()) + if #(pos - vector3(Blooddrops[CurrentBlooddrop].coords.x, Blooddrops[CurrentBlooddrop].coords.y, + Blooddrops[CurrentBlooddrop].coords.z)) < 1.5 then + DrawText3D(Blooddrops[CurrentBlooddrop].coords.x, Blooddrops[CurrentBlooddrop].coords.y, Blooddrops[CurrentBlooddrop].coords.z, Lang:t('info.blood_text', {value = DnaHash(Blooddrops[CurrentBlooddrop].citizenid)})) + if IsControlJustReleased(0, 47) then + local s1, s2 = GetStreetNameAtCoord(Blooddrops[CurrentBlooddrop].coords.x, Blooddrops[CurrentBlooddrop].coords.y, Blooddrops[CurrentBlooddrop].coords.z) + local street1 = GetStreetNameFromHashKey(s1) + local street2 = GetStreetNameFromHashKey(s2) + local streetLabel = street1 + if street2 then + streetLabel = streetLabel .. ' | ' .. street2 + end + local info = { + label = Lang:t('info.blood'), + type = 'blood', + street = streetLabel:gsub("%'", ""), + dnalabel = DnaHash(Blooddrops[CurrentBlooddrop].citizenid), + bloodtype = Blooddrops[CurrentBlooddrop].bloodtype + } + TriggerServerEvent('evidence:server:AddBlooddropToInventory', CurrentBlooddrop, info) + end + end + end + + if CurrentFingerprint and CurrentFingerprint ~= 0 then + local pos = GetEntityCoords(PlayerPedId()) + if #(pos - vector3(Fingerprints[CurrentFingerprint].coords.x, Fingerprints[CurrentFingerprint].coords.y, + Fingerprints[CurrentFingerprint].coords.z)) < 1.5 then + DrawText3D(Fingerprints[CurrentFingerprint].coords.x, Fingerprints[CurrentFingerprint].coords.y, Fingerprints[CurrentFingerprint].coords.z, Lang:t('info.fingerprint_text')) + if IsControlJustReleased(0, 47) then + local s1, s2 = GetStreetNameAtCoord(Fingerprints[CurrentFingerprint].coords.x,Fingerprints[CurrentFingerprint].coords.y, Fingerprints[CurrentFingerprint].coords.z) + local street1 = GetStreetNameFromHashKey(s1) + local street2 = GetStreetNameFromHashKey(s2) + local streetLabel = street1 + if street2 then + streetLabel = streetLabel .. ' | ' .. street2 + end + local info = { + label = Lang:t('info.fingerprint'), + type = 'fingerprint', + street = streetLabel:gsub("%'", ""), + fingerprint = Fingerprints[CurrentFingerprint].fingerprint + } + TriggerServerEvent('evidence:server:AddFingerprintToInventory', CurrentFingerprint, info) + end + end + end + end +end) + +CreateThread(function() + while true do + Wait(10) + if LocalPlayer.state.isLoggedIn then + if PlayerJob.name == 'police' and PlayerJob.onduty then + if IsPlayerFreeAiming(PlayerId()) and GetSelectedPedWeapon(PlayerPedId()) == `WEAPON_FLASHLIGHT` then + if next(Casings) then + local pos = GetEntityCoords(PlayerPedId(), true) + for k, v in pairs(Casings) do + local dist = #(pos - vector3(v.coords.x, v.coords.y, v.coords.z)) + if dist < 1.5 then + CurrentCasing = k + end + end + end + if next(Blooddrops) then + local pos = GetEntityCoords(PlayerPedId(), true) + for k, v in pairs(Blooddrops) do + local dist = #(pos - vector3(v.coords.x, v.coords.y, v.coords.z)) + if dist < 1.5 then + CurrentBlooddrop = k + end + end + end + if next(Fingerprints) then + local pos = GetEntityCoords(PlayerPedId(), true) + for k, v in pairs(Fingerprints) do + local dist = #(pos - vector3(v.coords.x, v.coords.y, v.coords.z)) + if dist < 1.5 then + CurrentFingerprint = k + end + end + end + else + Wait(1000) + end + else + Wait(5000) + end + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/heli.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/heli.lua new file mode 100644 index 0000000..1821cf1 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/heli.lua @@ -0,0 +1,304 @@ +local fov_max = 80.0 +local fov_min = 10.0 -- max zoom level (smaller fov is more zoom) +local zoomspeed = 2.0 -- camera zoom speed +local speed_lr = 3.0 -- speed by which the camera pans left-right +local speed_ud = 3.0 -- speed by which the camera pans up-down +local toggle_helicam = 51 -- control id of the button by which to toggle the helicam mode. Default: INPUT_CONTEXT (E) +local toggle_vision = 25 -- control id to toggle vision mode. Default: INPUT_AIM (Right mouse btn) +local toggle_rappel = 154 -- control id to rappel out of the heli. Default: INPUT_DUCK (X) +local toggle_spotlight = 74 -- control id to toggle the front spotlight Default: INPUT_VEH_HEADLIGHT (H) +local toggle_lock_on = 22 -- control id to lock onto a vehicle with the camera. Default is INPUT_SPRINT (spacebar) +local spotlight_state = false + +-- Script starts here +local helicam = false +local fov = (fov_max+fov_min)*0.5 +local vision_state = 0 -- 0 is normal, 1 is nightmode, 2 is thermal vision + +local isScanning = false +local isScanned = false +local scanValue = 0 + +local vehicle_detected = nil +local locked_on_vehicle = nil + +-- Functions +local function IsPlayerInPolmav() + local lPed = PlayerPedId() + local vehicle = GetVehiclePedIsIn(lPed) + return IsVehicleModel(vehicle, GetHashKey(Config.PoliceHelicopter)) +end + +local function IsHeliHighEnough(heli) + return GetEntityHeightAboveGround(heli) > 1.5 +end + +local function ChangeVision() + if vision_state == 0 then + SetNightvision(true) + vision_state = 1 + elseif vision_state == 1 then + SetNightvision(false) + SetSeethrough(true) + vision_state = 2 + else + SetSeethrough(false) + vision_state = 0 + end +end + +local function HideHUDThisFrame() + HideHelpTextThisFrame() + HideHudAndRadarThisFrame() + HideHudComponentThisFrame(19) -- weapon wheel + HideHudComponentThisFrame(1) -- Wanted Stars + HideHudComponentThisFrame(2) -- Weapon icon + HideHudComponentThisFrame(3) -- Cash + HideHudComponentThisFrame(4) -- MP CASH + HideHudComponentThisFrame(13) -- Cash Change + HideHudComponentThisFrame(11) -- Floating Help Text + HideHudComponentThisFrame(12) -- more floating help text + HideHudComponentThisFrame(15) -- Subtitle Text + HideHudComponentThisFrame(18) -- Game Stream +end + +local function CheckInputRotation(cam, zoomvalue) + local rightAxisX = GetDisabledControlNormal(0, 220) + local rightAxisY = GetDisabledControlNormal(0, 221) + local rotation = GetCamRot(cam, 2) + if rightAxisX ~= 0.0 or rightAxisY ~= 0.0 then + local new_z = rotation.z + rightAxisX*-1.0*(speed_ud)*(zoomvalue+0.1) + local new_x = math.max(math.min(20.0, rotation.x + rightAxisY*-1.0*(speed_lr)*(zoomvalue+0.1)), -89.5) -- Clamping at top (cant see top of heli) and at bottom (doesn't glitch out in -90deg) + SetCamRot(cam, new_x, 0.0, new_z, 2) + end +end + +local function HandleZoom(cam) + if IsControlJustPressed(0,241) then -- Scrollup + fov = math.max(fov - zoomspeed, fov_min) + end + if IsControlJustPressed(0,242) then + fov = math.min(fov + zoomspeed, fov_max) -- ScrollDown + end + local current_fov = GetCamFov(cam) + if math.abs(fov-current_fov) < 0.1 then -- the difference is too small, just set the value directly to avoid unneeded updates to FOV of order 10^-5 + fov = current_fov + end + SetCamFov(cam, current_fov + (fov - current_fov)*0.05) -- Smoothing of camera zoom +end + +local function RotAnglesToVec(rot) -- input vector3 + local z = math.rad(rot.z) + local x = math.rad(rot.x) + local num = math.abs(math.cos(x)) + return vector3(-math.sin(z)*num, math.cos(z)*num, math.sin(x)) +end + +local function GetVehicleInView(cam) + local coords = GetCamCoord(cam) + local forward_vector = RotAnglesToVec(GetCamRot(cam, 2)) + --DrawLine(coords, coords+(forward_vector*100.0), 255,0,0,255) -- debug line to show LOS of cam + local rayhandle = CastRayPointToPoint(coords, coords+(forward_vector*400.0), 10, GetVehiclePedIsIn(PlayerPedId()), 0) + local _, _, _, _, entityHit = GetRaycastResult(rayhandle) + if entityHit>0 and IsEntityAVehicle(entityHit) then + return entityHit + else + return nil + end +end + +local function RenderVehicleInfo(vehicle) + local pos = GetEntityCoords(vehicle) + local model = GetEntityModel(vehicle) + local vehname = GetLabelText(GetDisplayNameFromVehicleModel(model)) + local licenseplate = QBCore.Functions.GetPlate(vehicle) + local speed = math.ceil(GetEntitySpeed(vehicle) * 3.6) + local street1, street2 = GetStreetNameAtCoord(pos.x, pos.y, pos.z) + local streetLabel = GetStreetNameFromHashKey(street1) + if street2 ~= 0 then + streetLabel = streetLabel .. " | " .. GetStreetNameFromHashKey(street2) + end + SendNUIMessage({ + type = "heliupdateinfo", + model = vehname, + plate = licenseplate, + speed = speed, + street = streetLabel, + }) +end + +-- Events +RegisterNetEvent('heli:spotlight', function(serverID, state) + local heli = GetVehiclePedIsIn(GetPlayerPed(GetPlayerFromServerId(serverID)), false) + SetVehicleSearchlight(heli, state, false) +end) + +-- Threads +CreateThread(function() + while true do + Wait(0) + if LocalPlayer.state.isLoggedIn then + if PlayerJob.name == 'police' and PlayerJob.onduty then + if IsPlayerInPolmav() then + local lPed = PlayerPedId() + local heli = GetVehiclePedIsIn(lPed) + + if IsHeliHighEnough(heli) then + if IsControlJustPressed(0, toggle_helicam) then -- Toggle Helicam + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + helicam = true + SendNUIMessage({ + type = "heliopen", + }) + end + + if IsControlJustPressed(0, toggle_rappel) then -- Initiate rappel + if GetPedInVehicleSeat(heli, 1) == lPed or GetPedInVehicleSeat(heli, 2) == lPed then + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + TaskRappelFromHeli(PlayerPedId(), 1) + end + end + end + + if IsControlJustPressed(0, toggle_spotlight) and (GetPedInVehicleSeat(heli, -1) == lPed or GetPedInVehicleSeat(heli, 0) == lPed) then + spotlight_state = not spotlight_state + TriggerServerEvent("heli:spotlight", spotlight_state) + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + end + + if helicam then + SetTimecycleModifier("heliGunCam") + SetTimecycleModifierStrength(0.3) + local scaleform = RequestScaleformMovie("HELI_CAM") + while not HasScaleformMovieLoaded(scaleform) do + Wait(0) + end + local cam = CreateCam("DEFAULT_SCRIPTED_FLY_CAMERA", true) + AttachCamToEntity(cam, heli, 0.0,0.0,-1.5, true) + SetCamRot(cam, 0.0,0.0,GetEntityHeading(heli)) + SetCamFov(cam, fov) + RenderScriptCams(true, false, 0, 1, 0) + PushScaleformMovieFunction(scaleform, "SET_CAM_LOGO") + PushScaleformMovieFunctionParameterInt(0) -- 0 for nothing, 1 for LSPD logo + PopScaleformMovieFunctionVoid() + locked_on_vehicle = nil + while helicam and not IsEntityDead(lPed) and (GetVehiclePedIsIn(lPed) == heli) and IsHeliHighEnough(heli) do + if IsControlJustPressed(0, toggle_helicam) then -- Toggle Helicam + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + helicam = false + isScanned = false + scanValue = 0 + SendNUIMessage({ + type = "disablescan", + }) + SendNUIMessage({ + type = "heliclose", + }) + end + if IsControlJustPressed(0, toggle_vision) then + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + ChangeVision() + end + local zoomvalue = 0 + if locked_on_vehicle then + if DoesEntityExist(locked_on_vehicle) then + PointCamAtEntity(cam, locked_on_vehicle, 0.0, 0.0, 0.0, true) + if IsControlJustPressed(0, toggle_lock_on) then + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + locked_on_vehicle = nil + local rot = GetCamRot(cam, 2) -- All this because I can't seem to get the camera unlocked from the entity + fov = GetCamFov(cam) + local old_cam = cam + DestroyCam(old_cam, false) + cam = CreateCam("DEFAULT_SCRIPTED_FLY_CAMERA", true) + AttachCamToEntity(cam, heli, 0.0,0.0,-1.5, true) + SetCamRot(cam, rot, 2) + SetCamFov(cam, fov) + RenderScriptCams(true, false, 0, 1, 0) + isScanned = false + scanValue = 0 + SendNUIMessage({ + type = "disablescan", + }) + end + else + isScanned = false + SendNUIMessage({ + type = "disablescan", + }) + locked_on_vehicle = nil -- Cam will auto unlock when entity doesn't exist anyway + end + else + zoomvalue = (1.0/(fov_max-fov_min))*(fov-fov_min) + CheckInputRotation(cam, zoomvalue) + vehicle_detected = GetVehicleInView(cam) + if DoesEntityExist(vehicle_detected) then + isScanning = true + else + isScanning = false + end + end + HandleZoom(cam) + HideHUDThisFrame() + PushScaleformMovieFunction(scaleform, "SET_ALT_FOV_HEADING") + PushScaleformMovieFunctionParameterFloat(GetEntityCoords(heli).z) + PushScaleformMovieFunctionParameterFloat(zoomvalue) + PushScaleformMovieFunctionParameterFloat(GetCamRot(cam, 2).z) + PopScaleformMovieFunctionVoid() + DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255) + Wait(0) + end + helicam = false + ClearTimecycleModifier() + fov = (fov_max+fov_min)*0.5 -- reset to starting zoom level + RenderScriptCams(false, false, 0, 1, 0) -- Return to gameplay camera + SetScaleformMovieAsNoLongerNeeded(scaleform) -- Cleanly release the scaleform + DestroyCam(cam, false) + SetNightvision(false) + SetSeethrough(false) + end + else + Wait(2000) + end + else + Wait(2000) + end + else + Wait(2000) + end + end +end) + +CreateThread(function() + while true do + Wait(1) + if helicam then + if isScanning and not isScanned then + if scanValue < 100 then + scanValue = scanValue + 1 + SendNUIMessage({ + type = "heliscan", + scanvalue = scanValue, + }) + if scanValue == 100 then + PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + locked_on_vehicle = vehicle_detected + isScanning = false + isScanned = true + end + Wait(10) + end + elseif isScanned and not isScanning and locked_on_vehicle then + scanValue = 100 + RenderVehicleInfo(locked_on_vehicle) + isScanning = false + Wait(100) + else + scanValue = 0 + Wait(500) + end + else + Wait(1000) + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/interactions.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/interactions.lua new file mode 100644 index 0000000..c5f6841 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/interactions.lua @@ -0,0 +1,567 @@ +-- Variables +local isEscorting = false + +-- Functions +exports('IsHandcuffed', function() + return isHandcuffed +end) + +local function loadAnimDict(dict) -- interactions, job, + while (not HasAnimDictLoaded(dict)) do + RequestAnimDict(dict) + Wait(10) + end +end + +local function IsTargetDead(playerId) + local retval = false + local hasReturned = false + QBCore.Functions.TriggerCallback('police:server:isPlayerDead', function(result) + retval = result + hasReturned = true + end, playerId) + while not hasReturned do + Wait(10) + end + return retval +end + +local function HandCuffAnimation() + local ped = PlayerPedId() + if isHandcuffed == true then + TriggerServerEvent("InteractSound_SV:PlayOnSource", "Cuff", 0.2) + else + TriggerServerEvent("InteractSound_SV:PlayOnSource", "Uncuff", 0.2) + end + + loadAnimDict("mp_arrest_paired") + Wait(100) + TaskPlayAnim(ped, "mp_arrest_paired", "cop_p2_back_right", 3.0, 3.0, -1, 48, 0, 0, 0, 0) + TriggerServerEvent("InteractSound_SV:PlayOnSource", "Cuff", 0.2) + Wait(3500) + TaskPlayAnim(ped, "mp_arrest_paired", "exit", 3.0, 3.0, -1, 48, 0, 0, 0, 0) +end + +local function GetCuffedAnimation(playerId) + local ped = PlayerPedId() + local cuffer = GetPlayerPed(GetPlayerFromServerId(playerId)) + local heading = GetEntityHeading(cuffer) + TriggerServerEvent("InteractSound_SV:PlayOnSource", "Cuff", 0.2) + loadAnimDict("mp_arrest_paired") + SetEntityCoords(ped, GetOffsetFromEntityInWorldCoords(cuffer, 0.0, 0.45, 0.0)) + + Wait(100) + SetEntityHeading(ped, heading) + TaskPlayAnim(ped, "mp_arrest_paired", "crook_p2_back_right", 3.0, 3.0, -1, 32, 0, 0, 0, 0 ,true, true, true) + Wait(2500) +end + +-- Events +RegisterNetEvent('police:client:SetOutVehicle', function() + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped, false) then + local vehicle = GetVehiclePedIsIn(ped, false) + TaskLeaveVehicle(ped, vehicle, 16) + end +end) + +RegisterNetEvent('police:client:PutInVehicle', function() + local ped = PlayerPedId() + if isHandcuffed or isEscorted then + local vehicle = QBCore.Functions.GetClosestVehicle() + if DoesEntityExist(vehicle) then + for i = GetVehicleMaxNumberOfPassengers(vehicle), 0, -1 do + if IsVehicleSeatFree(vehicle, i) then + isEscorted = false + TriggerEvent('hospital:client:isEscorted', isEscorted) + ClearPedTasks(ped) + DetachEntity(ped, true, false) + + Wait(100) + SetPedIntoVehicle(ped, vehicle, i) + return + end + end + end + end +end) + + +RegisterNetEvent('police:client:SearchPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent("inventory:server:OpenInventory", "otherplayer", playerId) + TriggerServerEvent("police:server:SearchPlayer", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:SeizeCash', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent("police:server:SeizeCash", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:SeizeDriverLicense', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent("police:server:SeizeDriverLicense", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + + +RegisterNetEvent('police:client:RobPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + local ped = PlayerPedId() + if player ~= -1 and distance < 2.5 then + local playerPed = GetPlayerPed(player) + local playerId = GetPlayerServerId(player) + if IsEntityPlayingAnim(playerPed, "missminuteman_1ig_2", "handsup_base", 3) or IsEntityPlayingAnim(playerPed, "mp_arresting", "idle", 3) or IsTargetDead(playerId) then + QBCore.Functions.Progressbar("robbing_player", Lang:t("progressbar.robbing"), math.random(5000, 7000), false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "random@shop_robbery", + anim = "robbery_action_b", + flags = 16, + }, {}, {}, function() -- Done + local plyCoords = GetEntityCoords(playerPed) + local pos = GetEntityCoords(ped) + if #(pos - plyCoords) < 2.5 then + StopAnimTask(ped, "random@shop_robbery", "robbery_action_b", 1.0) + TriggerServerEvent("inventory:server:OpenInventory", "otherplayer", playerId) + TriggerEvent("inventory:server:RobPlayer", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end + end, function() -- Cancel + StopAnimTask(ped, "random@shop_robbery", "robbery_action_b", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:JailPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + local dialog = exports['qb-input']:ShowInput({ + header = Lang:t('info.jail_time_input'), + submitText = Lang:t('info.submit'), + inputs = { + { + text = Lang:t('info.time_months'), + name = "jailtime", + type = "number", + isRequired = true + } + } + }) + if tonumber(dialog['jailtime']) > 0 then + TriggerServerEvent("police:server:JailPlayer", playerId, tonumber(dialog['jailtime'])) + else + QBCore.Functions.Notify(Lang:t("error.time_higher"), "error") + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:BillPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + local dialog = exports['qb-input']:ShowInput({ + header = Lang:t('info.bill'), + submitText = Lang:t('info.submit'), + inputs = { + { + text = Lang:t('info.amount'), + name = "bill", + type = "number", + isRequired = true + } + } + }) + if tonumber(dialog['bill']) > 0 then + TriggerServerEvent("police:server:BillPlayer", playerId, tonumber(dialog['bill'])) + else + QBCore.Functions.Notify(Lang:t("error.amount_higher"), "error") + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +-- RegisterNetEvent('police:client:PutPlayerInVehicle', function() +-- local player, distance = QBCore.Functions.GetClosestPlayer() +-- if player ~= -1 and distance < 2.5 then +-- local playerId = GetPlayerServerId(player) +-- if not isHandcuffed and not isEscorted then +-- TriggerServerEvent("police:server:PutPlayerInVehicle", playerId) +-- end +-- else +-- QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") +-- end +-- end) + +-- RegisterNetEvent('police:client:SetPlayerOutVehicle', function() +-- local player, distance = QBCore.Functions.GetClosestPlayer() +-- if player ~= -1 and distance < 2.5 then +-- local playerId = GetPlayerServerId(player) +-- if not isHandcuffed and not isEscorted then +-- TriggerServerEvent("police:server:SetPlayerOutVehicle", playerId) +-- end +-- else +-- QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") +-- end +-- end) + +RegisterNetEvent('police:client:PutPlayerInVehicle', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + if not isHandcuffed and not isEscorted then + QBCore.Functions.Progressbar("putincar", "Putting in Vehicle!", 2500, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerServerEvent("police:server:PutPlayerInVehicle", playerId) + end) + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:SetPlayerOutVehicle', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + if not isHandcuffed and not isEscorted then + QBCore.Functions.Progressbar("takeoutofcar", "Taking out of Vehicle!", 2500, false, true, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerServerEvent("police:server:SetPlayerOutVehicle", playerId) + TriggerEvent("police:client:EscortPlayer") + end) + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:EscortPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + if not isHandcuffed and not isEscorted then + TriggerServerEvent("police:server:EscortPlayer", playerId) + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:KidnapPlayer', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + if not IsPedInAnyVehicle(GetPlayerPed(player)) then + if not isHandcuffed and not isEscorted then + TriggerServerEvent("police:server:KidnapPlayer", playerId) + end + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:CuffPlayerSoft', function() + if not isHandcuffed then + if not cantCuff then + if not IsPedRagdoll(PlayerPedId()) and not exports["qb-policejob"]:IsHandcuffed() then + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 1.5 then + local playerId = GetPlayerServerId(player) + if not IsPedInAnyVehicle(GetPlayerPed(player)) and not IsPedInAnyVehicle(PlayerPedId()) and not cantCuff and not isHandcuffed then + QBCore.Functions.Progressbar("cuffing_player", "Cuffing Player...", 3500, false, false, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = false, + }, {}, {}, {}, function() -- Done + cantCuff = false + end) + cantCuff = true + TriggerServerEvent("police:server:CuffPlayer", playerId, true) + HandCuffAnimation() + else + QBCore.Functions.Notify(Lang:t("error.vehicle_cuff"), "error") + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end + else + QBCore.Functions.Notify("Cuff Cooldown", "error") + end +else + QBCore.Functions.Notify("You are on Cuff Cooldown", "error") +end + else + Wait(2000) + end +end) + +RegisterNetEvent('police:client:CuffPlayer', function() +if not isHandcuffed then + if not cantCuff then + if not IsPedRagdoll(PlayerPedId()) then + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 1.5 then + local result = QBCore.Functions.Hasitem(Config.HandCuffItem) + if result then + local playerId = GetPlayerServerId(player) + if not IsPedInAnyVehicle(GetPlayerPed(player)) and not IsPedInAnyVehicle(PlayerPedId()) and not cantCuff and not isHandcuffed then + QBCore.Functions.Progressbar("cuffing_player", "Cuffing Player..", 3500, false, false, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = false, + }, {}, {}, {}, function() -- Done + cantCuff = false + end) + cantCuff = true + TriggerServerEvent("police:server:CuffPlayer", playerId, false) + HandCuffAnimation() + else + QBCore.Functions.Notify(Lang:t("error.vehicle_cuff"), "error") + end + else + QBCore.Functions.Notify(Lang:t("error.no_cuff"), "error") + end + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end + else + QBCore.Functions.Notify("Cuff Cooldown", "error") + end +else + QBCore.Functions.Notify("You are on Cuff Cooldown", "error") +end + else + Wait(2000) + end +end) + +-- RegisterNetEvent('police:client:GetEscorted', function(playerId) +-- local ped = PlayerPedId() +-- QBCore.Functions.GetPlayerData(function(PlayerData) +-- if PlayerData.metadata["isdead"] or isHandcuffed or PlayerData.metadata["inlaststand"] then +-- if not isEscorted then +-- isEscorted = true +-- local dragger = GetPlayerPed(GetPlayerFromServerId(playerId)) +-- SetEntityCoords(ped, GetOffsetFromEntityInWorldCoords(dragger, 0.0, 0.45, 0.0)) +-- AttachEntityToEntity(ped, dragger, 11816, 0.45, 0.45, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) +-- else +-- isEscorted = false +-- DetachEntity(ped, true, false) +-- end +-- TriggerEvent('hospital:client:isEscorted', isEscorted) +-- end +-- end) +-- end) + +RegisterNetEvent('police:client:GetEscorted', function(playerId) + local ped = PlayerPedId() + QBCore.Functions.GetPlayerData(function(PlayerData) + if PlayerData.metadata["isdead"] or isHandcuffed or PlayerData.metadata["inlaststand"] or PlayerData.metadata['ishandcuffed'] then + if not isEscorted then + isEscorted = true + local dragger = GetPlayerPed(GetPlayerFromServerId(playerId)) + SetEntityCoords(ped, GetOffsetFromEntityInWorldCoords(dragger, 0.0, 0.45, 0.0)) + AttachEntityToEntity(ped, dragger, 11816, 0.45, 0.45, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) + else + isEscorted = false + DetachEntity(ped, true, false) + end + TriggerEvent('hospital:client:isEscorted', isEscorted) + end + end) +end) + +RegisterNetEvent('police:client:DeEscort', function() + isEscorted = false + TriggerEvent('hospital:client:isEscorted', isEscorted) + DetachEntity(PlayerPedId(), true, false) +end) + +RegisterNetEvent('police:client:GetKidnappedTarget', function(playerId) + local ped = PlayerPedId() + QBCore.Functions.GetPlayerData(function(PlayerData) + if PlayerData.metadata["isdead"] or PlayerData.metadata["inlaststand"] or isHandcuffed then + if not isEscorted then + isEscorted = true + local dragger = GetPlayerPed(GetPlayerFromServerId(playerId)) + RequestAnimDict("nm") + + while not HasAnimDictLoaded("nm") do + Wait(10) + end + AttachEntityToEntity(ped, dragger, 0, 0.27, 0.15, 0.63, 0.5, 0.5, 0.0, false, false, false, false, 2, false) + TaskPlayAnim(ped, "nm", "firemans_carry", 8.0, -8.0, 100000, 33, 0, false, false, false) + else + isEscorted = false + DetachEntity(ped, true, false) + ClearPedTasksImmediately(ped) + end + TriggerEvent('hospital:client:isEscorted', isEscorted) + end + end) +end) + +RegisterNetEvent('police:client:GetKidnappedDragger', function() + QBCore.Functions.GetPlayerData(function(_) + if not isEscorting then + local dragger = PlayerPedId() + RequestAnimDict("missfinale_c2mcs_1") + + while not HasAnimDictLoaded("missfinale_c2mcs_1") do + Wait(10) + end + TaskPlayAnim(dragger, "missfinale_c2mcs_1", "fin_c2_mcs_1_camman", 8.0, -8.0, 100000, 49, 0, false, false, false) + isEscorting = true + else + local dragger = PlayerPedId() + ClearPedSecondaryTask(dragger) + ClearPedTasksImmediately(dragger) + isEscorting = false + end + TriggerEvent('hospital:client:SetEscortingState', isEscorting) + TriggerEvent('qb-kidnapping:client:SetKidnapping', isEscorting) + end) +end) + +RegisterNetEvent('police:client:GetCuffed', function(playerId, isSoftcuff) + local ped = PlayerPedId() + if not isHandcuffed then + local seconds = math.random(5,7) + exports['ps-ui']:Circle(function(success) + if success then + GetCuffedAnimation(playerId) + QBCore.Functions.Notify("You managed to break free", "success") + TriggerServerEvent("police:server:SetHandcuffStatus", false) + else + isHandcuffed = true + TriggerServerEvent("police:server:SetHandcuffStatus", true) + ClearPedTasksImmediately(ped) + if GetSelectedPedWeapon(ped) ~= WEAPON_UNARMED then + SetCurrentPedWeapon(ped, WEAPON_UNARMED, true) + end + if not isSoftcuff then + cuffType = 16 + GetCuffedAnimation(playerId) + QBCore.Functions.Notify(Lang:t("info.cuff"), 'primary') + else + cuffType = 49 + GetCuffedAnimation(playerId) + QBCore.Functions.Notify(Lang:t("info.cuffed_walk"), 'primary') + end + print("fail") + end + end, 1, seconds) -- NumberOfCircles, MS + else + isHandcuffed = false + isEscorted = false + TriggerEvent('hospital:client:isEscorted', isEscorted) + DetachEntity(ped, true, false) + TriggerServerEvent("police:server:SetHandcuffStatus", false) + ClearPedTasksImmediately(ped) + TriggerServerEvent("InteractSound_SV:PlayOnSource", "Uncuff", 0.2) + QBCore.Functions.Notify(Lang:t("success.uncuffed"),"success") + end +end) + + +-- Threads +CreateThread(function() + while true do + Wait(1) + if isEscorted then + DisableAllControlActions(0) + EnableControlAction(0, 1, true) + EnableControlAction(0, 2, true) + EnableControlAction(0, 245, true) + EnableControlAction(0, 38, true) + EnableControlAction(0, 322, true) + EnableControlAction(0, 249, true) + EnableControlAction(0, 46, true) + end + + if isHandcuffed then + DisableControlAction(0, 24, true) -- Attack + DisableControlAction(0, 257, true) -- Attack 2 + DisableControlAction(0, 25, true) -- Aim + DisableControlAction(0, 263, true) -- Melee Attack 1 + + DisableControlAction(0, 45, true) -- Reload + DisableControlAction(0, 22, true) -- Jump + DisableControlAction(0, 44, true) -- Cover + DisableControlAction(0, 37, true) -- Select Weapon + DisableControlAction(0, 23, true) -- Also 'enter'? + + DisableControlAction(0, 288, true) -- Disable phone + DisableControlAction(0, 289, true) -- Inventory + DisableControlAction(0, 170, true) -- Animations + DisableControlAction(0, 167, true) -- Job + + DisableControlAction(0, 26, true) -- Disable looking behind + DisableControlAction(0, 73, true) -- Disable clearing animation + DisableControlAction(2, 199, true) -- Disable pause screen + + DisableControlAction(0, 59, true) -- Disable steering in vehicle + DisableControlAction(0, 71, true) -- Disable driving forward in vehicle + DisableControlAction(0, 72, true) -- Disable reversing in vehicle + + DisableControlAction(2, 36, true) -- Disable going stealth + + DisableControlAction(0, 264, true) -- Disable melee + DisableControlAction(0, 257, true) -- Disable melee + DisableControlAction(0, 140, true) -- Disable melee + DisableControlAction(0, 141, true) -- Disable melee + DisableControlAction(0, 142, true) -- Disable melee + DisableControlAction(0, 143, true) -- Disable melee + DisableControlAction(0, 75, true) -- Disable exit vehicle + DisableControlAction(27, 75, true) -- Disable exit vehicle + EnableControlAction(0, 249, true) -- Added for talking while cuffed + EnableControlAction(0, 46, true) -- Added for talking while cuffed + + if (not IsEntityPlayingAnim(PlayerPedId(), "mp_arresting", "idle", 3) and not IsEntityPlayingAnim(PlayerPedId(), "mp_arrest_paired", "crook_p2_back_right", 3)) and not QBCore.Functions.GetPlayerData().metadata["isdead"] then + loadAnimDict("mp_arresting") + TaskPlayAnim(PlayerPedId(), "mp_arresting", "idle", 8.0, -8, -1, cuffType, 0, 0, 0, 0) + end + end + if not isHandcuffed and not isEscorted then + Wait(2000) + end + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/job.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/job.lua new file mode 100644 index 0000000..8a126e6 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/job.lua @@ -0,0 +1,1275 @@ +-- Variables +local currentGarage = 0 +local onDuty = false +local inFingerprint = false +local FingerPrintSessionId = nil +local inStash = false +local inTrash = false +local inAmoury = false +local inHelicopter = false +local inImpound = false +local inGarage = false +local ownedHeli = false + +local function loadAnimDict(dict) -- interactions, job, + while (not HasAnimDictLoaded(dict)) do + RequestAnimDict(dict) + Wait(10) + end +end + +local function GetClosestPlayer() -- interactions, job, tracker + local closestPlayers = QBCore.Functions.GetPlayersFromCoords() + local closestDistance = -1 + local closestPlayer = -1 + local coords = GetEntityCoords(PlayerPedId()) + + for i = 1, #closestPlayers, 1 do + if closestPlayers[i] ~= PlayerId() then + local pos = GetEntityCoords(GetPlayerPed(closestPlayers[i])) + local distance = #(pos - coords) + + if closestDistance == -1 or closestDistance > distance then + closestPlayer = closestPlayers[i] + closestDistance = distance + end + end + end + + return closestPlayer, closestDistance +end + +local function openFingerprintUI() + SendNUIMessage({ + type = "fingerprintOpen" + }) + inFingerprint = true + SetNuiFocus(true, true) +end + +local function SetCarItemsInfo() + local items = {} + for _, item in pairs(Config.CarItems) do + local itemInfo = QBCore.Shared.Items[item.name:lower()] + items[item.slot] = { + name = itemInfo["name"], + amount = tonumber(item.amount), + info = item.info, + label = itemInfo["label"], + description = itemInfo["description"] and itemInfo["description"] or "", + weight = itemInfo["weight"], + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = item.slot, + } + end + Config.CarItems = items +end + +local function doCarDamage(currentVehicle, veh) + local smash = false + local damageOutside = false + local damageOutside2 = false + local engine = veh.engine + 0.0 + local body = veh.body + 0.0 + + if engine < 200.0 then engine = 200.0 end + if engine > 1000.0 then engine = 950.0 end + if body < 150.0 then body = 150.0 end + if body < 950.0 then smash = true end + if body < 920.0 then damageOutside = true end + if body < 920.0 then damageOutside2 = true end + + Wait(100) + SetVehicleEngineHealth(currentVehicle, engine) + + if smash then + SmashVehicleWindow(currentVehicle, 0) + SmashVehicleWindow(currentVehicle, 1) + SmashVehicleWindow(currentVehicle, 2) + SmashVehicleWindow(currentVehicle, 3) + SmashVehicleWindow(currentVehicle, 4) + end + + if damageOutside then + SetVehicleDoorBroken(currentVehicle, 1, true) + SetVehicleDoorBroken(currentVehicle, 6, true) + SetVehicleDoorBroken(currentVehicle, 4, true) + end + + if damageOutside2 then + SetVehicleTyreBurst(currentVehicle, 1, false, 990.0) + SetVehicleTyreBurst(currentVehicle, 2, false, 990.0) + SetVehicleTyreBurst(currentVehicle, 3, false, 990.0) + SetVehicleTyreBurst(currentVehicle, 4, false, 990.0) + end + + if body < 1000 then + SetVehicleBodyHealth(currentVehicle, 985.1) + end +end + +function TakeOutImpound(vehicle) + local coords = Config.Locations["impound"][currentGarage] + if coords then + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + QBCore.Functions.TriggerCallback('qb-garage:server:GetVehicleProperties', function(properties) + QBCore.Functions.SetVehicleProperties(veh, properties) + SetVehicleNumberPlateText(veh, vehicle.plate) + SetVehicleDirtLevel(veh, 0.0) + SetEntityHeading(veh, coords.w) + exports['qb-fuel']:SetFuel(veh, vehicle.fuel) + doCarDamage(veh, vehicle) + TriggerServerEvent('police:server:TakeOutImpound', vehicle.plate, currentGarage) + closeMenuFull() + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + SetVehicleEngineOn(veh, true, true) + end, vehicle.plate) + end, vehicle.vehicle, coords, true) + end +end + +function TakeOutVehicle(vehicleInfo) + local coords = Config.Locations["vehicle"][currentGarage] + if coords then + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetCarItemsInfo() + SetVehicleNumberPlateText(veh, Lang:t('info.police_plate')..tostring(math.random(1000, 9999))) + SetEntityHeading(veh, coords.w) + exports['qb-fuel']:SetFuel(veh, 100.0) + closeMenuFull() + if Config.VehicleSettings[vehicleInfo] ~= nil then + if Config.VehicleSettings[vehicleInfo].extras ~= nil then + QBCore.Shared.SetDefaultVehicleExtras(veh, Config.VehicleSettings[vehicleInfo].extras) + end + if Config.VehicleSettings[vehicleInfo].livery ~= nil then + SetVehicleLivery(veh, Config.VehicleSettings[vehicleInfo].livery) + end + end + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + TriggerServerEvent("police:server:addTrunkItems", QBCore.Functions.GetPlate(veh), Config.CarItems) + SetVehicleEngineOn(veh, true, true) + end, vehicleInfo, coords, true) + end +end + +local function IsArmoryWhitelist() -- being removed + local retval = false + + if QBCore.Functions.GetPlayerData().job.name == 'police' then + retval = true + end + return retval +end + +local function SetWeaponSeries() + for k, _ in pairs(Config.Items.items) do + if k < 6 then + Config.Items.items[k].info.serie = tostring(QBCore.Shared.RandomInt(2) .. QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(1) .. QBCore.Shared.RandomStr(2) .. QBCore.Shared.RandomInt(3) .. QBCore.Shared.RandomStr(4)) + end + end +end + +function MenuGarage(currentSelection) + local vehicleMenu = { + { + header = Lang:t('menu.garage_title'), + isMenuHeader = true + } + } + + local authorizedVehicles = Config.AuthorizedVehicles[QBCore.Functions.GetPlayerData().job.grade.level] + for veh, label in pairs(authorizedVehicles) do + vehicleMenu[#vehicleMenu+1] = { + header = label, + txt = "", + params = { + event = "police:client:TakeOutVehicle", + args = { + vehicle = veh, + currentSelection = currentSelection + } + } + } + end + + if IsArmoryWhitelist() then + for veh, label in pairs(Config.WhitelistedVehicles) do + vehicleMenu[#vehicleMenu+1] = { + header = label, + txt = "", + params = { + event = "police:client:TakeOutVehicle", + args = { + vehicle = veh, + currentSelection = currentSelection + } + } + } + end + end + + vehicleMenu[#vehicleMenu+1] = { + header = Lang:t('menu.close'), + txt = "", + params = { + event = "qb-menu:client:closeMenu" + } + + } + exports['qb-menu']:openMenu(vehicleMenu) +end + + +function MenuImpound(currentSelection) + local impoundMenu = { + { + header = Lang:t('menu.impound'), + isMenuHeader = true + } + } + QBCore.Functions.TriggerCallback("police:GetImpoundedVehicles", function(result) + local shouldContinue = false + if result == nil then + QBCore.Functions.Notify(Lang:t("error.no_impound"), "error", 5000) + else + shouldContinue = true + for _ , v in pairs(result) do + local enginePercent = QBCore.Shared.Round(v.engine / 10, 0) + local currentFuel = v.fuel + local vname = QBCore.Shared.Vehicles[v.vehicle].name + + impoundMenu[#impoundMenu+1] = { + header = vname.." ["..v.plate.."]", + txt = Lang:t('info.vehicle_info', {value = enginePercent, value2 = currentFuel}), + params = { + event = "police:client:TakeOutImpound", + args = { + vehicle = v, + currentSelection = currentSelection + } + } + } + end + end + + + if shouldContinue then + impoundMenu[#impoundMenu+1] = { + header = Lang:t('menu.close'), + txt = "", + params = { + event = "qb-menu:client:closeMenu" + } + } + exports['qb-menu']:openMenu(impoundMenu) + end + end) + +end + +function closeMenuFull() + exports['qb-menu']:closeMenu() +end + +--NUI Callbacks +RegisterNUICallback('closeFingerprint', function(_, cb) + SetNuiFocus(false, false) + inFingerprint = false + cb('ok') +end) + +--Events +RegisterNetEvent('police:client:showFingerprint', function(playerId) + openFingerprintUI() + FingerPrintSessionId = playerId +end) + +-- RegisterNetEvent('police:client:showFingerprintId', function(fid) +-- SendNUIMessage({ +-- type = "updateFingerprintId", +-- fingerprintId = fid +-- }) +-- PlaySound(-1, "Event_Start_Text", "GTAO_FM_Events_Soundset", 0, 0, 1) +-- end) + +RegisterNetEvent('police:client:showFingerprintId', function(fid, flname) + SendNUIMessage({ + type = "updateFingerprintId", + fingerprintId = fid, + lastname = flname + }) + PlaySound(-1, "Event_Start_Text", "GTAO_FM_Events_Soundset", 0, 0, 1) +end) + +RegisterNUICallback('doFingerScan', function(_, cb) + TriggerServerEvent('police:server:showFingerprintId', FingerPrintSessionId) + cb("ok") +end) + +RegisterNetEvent('police:client:SendEmergencyMessage', function(coords, message) + TriggerServerEvent("police:server:SendEmergencyMessage", coords, message) + TriggerEvent("police:client:CallAnim") +end) + +RegisterNetEvent('police:client:EmergencySound', function() + PlaySound(-1, "Event_Start_Text", "GTAO_FM_Events_Soundset", 0, 0, 1) +end) + +RegisterNetEvent('police:client:CallAnim', function() + local isCalling = true + local callCount = 5 + loadAnimDict("cellphone@") + TaskPlayAnim(PlayerPedId(), 'cellphone@', 'cellphone_call_listen_base', 3.0, -1, -1, 49, 0, false, false, false) + Wait(1000) + CreateThread(function() + while isCalling do + Wait(1000) + callCount = callCount - 1 + if callCount <= 0 then + isCalling = false + StopAnimTask(PlayerPedId(), 'cellphone@', 'cellphone_call_listen_base', 1.0) + end + end + end) +end) + +RegisterNetEvent('police:client:ImpoundVehicle', function(fullImpound, price) + local vehicle = QBCore.Functions.GetClosestVehicle() + local bodyDamage = math.ceil(GetVehicleBodyHealth(vehicle)) + local engineDamage = math.ceil(GetVehicleEngineHealth(vehicle)) + local totalFuel = exports['qb-fuel']:GetFuel(vehicle) + if vehicle ~= 0 and vehicle then + local ped = PlayerPedId() + local pos = GetEntityCoords(ped) + local vehpos = GetEntityCoords(vehicle) + if #(pos - vehpos) < 5.0 and not IsPedInAnyVehicle(ped) then + QBCore.Functions.Progressbar('impound', Lang:t('progressbar.impound'), 5000, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = 'missheistdockssetup1clipboard@base', + anim = 'base', + flags = 1, + }, { + model = 'prop_notepad_01', + bone = 18905, + coords = { x = 0.1, y = 0.02, z = 0.05 }, + rotation = { x = 10.0, y = 0.0, z = 0.0 }, + },{ + model = 'prop_pencil_01', + bone = 58866, + coords = { x = 0.11, y = -0.02, z = 0.001 }, + rotation = { x = -120.0, y = 0.0, z = 0.0 }, + }, function() -- Play When Done + local plate = QBCore.Functions.GetPlate(vehicle) + TriggerServerEvent("police:server:Impound", plate, fullImpound, price, bodyDamage, engineDamage, totalFuel) + while NetworkGetEntityOwner(vehicle) ~= 128 do -- Ensure we have entity ownership to prevent inconsistent vehicle deletion + NetworkRequestControlOfEntity(vehicle) + Wait(100) + end + QBCore.Functions.DeleteVehicle(vehicle) + TriggerEvent('QBCore:Notify', Lang:t('success.impounded'), 'success') + ClearPedTasks(ped) + end, function() -- Play When Cancel + ClearPedTasks(ped) + TriggerEvent('QBCore:Notify', Lang:t('error.canceled'), 'error') + end) + end + end +end) + +RegisterNetEvent('police:client:CheckStatus', function() + QBCore.Functions.GetPlayerData(function(PlayerData) + if PlayerData.job.name == "police" then + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 5.0 then + local playerId = GetPlayerServerId(player) + QBCore.Functions.TriggerCallback('police:GetPlayerStatus', function(result) + if result then + for _, v in pairs(result) do + QBCore.Functions.Notify(''..v..'') + end + end + end, playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end + end + end) +end) + +RegisterNetEvent("police:client:VehicleMenuHeader", function (data) + MenuGarage(data.currentSelection) + currentGarage = data.currentSelection +end) + +RegisterNetEvent("police:client:ImpoundMenuHeader", function (data) + MenuImpound(data.currentSelection) + currentGarage = data.currentSelection +end) + +RegisterNetEvent('police:client:TakeOutImpound', function(data) + if inImpound then + local vehicle = data.vehicle + TakeOutImpound(vehicle) + end +end) + +RegisterNetEvent('police:client:TakeOutVehicle', function(data) + if inGarage then + local vehicle = data.vehicle + TakeOutVehicle(vehicle) + end +end) + +RegisterNetEvent('qb-policejob:elevator_basement', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["main"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["basement"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('qb-policejob:elevator_roof', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["roof"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["main"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('qb-policejob:elevator_main', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["main"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["roof"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('qb-policejob:elevator_basement-main', function() + local ped = PlayerPedId() + for k, _ in pairs(Config.Locations["basement"]) do + DoScreenFadeOut(500) + while not IsScreenFadedOut() do + Wait(10) + end + + currentHospital = k + + local coords = Config.Locations["main"][currentHospital] + SetEntityCoords(ped, coords.x, coords.y, coords.z, 0, 0, 0, false) + SetEntityHeading(ped, coords.w) + + Wait(100) + + DoScreenFadeIn(1000) + end +end) + +RegisterNetEvent('police:client:EvidenceStashDrawer', function(data) + local currentEvidence = data.currentEvidence + local pos = GetEntityCoords(PlayerPedId()) + local takeLoc = Config.Locations["evidence"][currentEvidence] + + if not takeLoc then return end + + if #(pos - takeLoc) <= 1.0 then + local drawer = exports['qb-input']:ShowInput({ + header = Lang:t('info.evidence_stash', {value = currentEvidence}), + submitText = "open", + inputs = { + { + type = 'number', + isRequired = true, + name = 'slot', + text = Lang:t('info.slot') + } + } + }) + if drawer then + if not drawer.slot then return end + TriggerServerEvent("inventory:server:OpenInventory", "stash", Lang:t('info.current_evidence', {value = currentEvidence, value2 = drawer.slot}), { + maxweight = 4000000, + slots = 500, + }) + TriggerEvent("inventory:client:SetCurrentStash", Lang:t('info.current_evidence', {value = currentEvidence, value2 = drawer.slot})) + end + else + exports['qb-menu']:closeMenu() + end +end) + +RegisterNetEvent('qb-policejob:ToggleDuty', function() + TriggerServerEvent("QBCore:ToggleDuty") + TriggerServerEvent("police:server:UpdateCurrentCops") + TriggerServerEvent("police:server:UpdateBlips") +end) + +RegisterNetEvent('qb-police:client:scanFingerPrint', function() + local player, distance = GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent("police:server:showFingerprint", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('qb-police:client:openArmoury', function() + local authorizedItems = { + label = Lang:t('menu.pol_armory'), + slots = 30, + items = {} + } + local index = 1 + for _, armoryItem in pairs(Config.Items.items) do + for i=1, #armoryItem.authorizedJobGrades do + if armoryItem.authorizedJobGrades[i] == PlayerJob.grade.level then + authorizedItems.items[index] = armoryItem + authorizedItems.items[index].slot = index + index = index + 1 + end + end + end + SetWeaponSeries() + TriggerServerEvent("inventory:server:OpenInventory", "shop", "police", authorizedItems) +end) + +RegisterNetEvent('qb-police:client:spawnHelicopter', function(k) + if IsPedInAnyVehicle(PlayerPedId(), false) then + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) + ownedHeli = false + else + local coords = Config.Locations["helicopter"][k] + if not coords then coords = GetEntityCoords(PlayerPedId()) end + if ownedHeli then QBCore.Functions.Notify(Lang:t("error.has_heli"), "error") return end + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + ownedHeli = true + SetVehicleLivery(veh , 0) + SetVehicleMod(veh, 0, 48) + SetVehicleNumberPlateText(veh, "ZULU"..tostring(math.random(1000, 9999))) + SetEntityHeading(veh, coords.w) + exports['qb-fuel']:SetFuel(veh, 100.0) + closeMenuFull() + SetVehicleDirtLevel(veh, 0.0) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + SetVehicleEngineOn(veh, true, true) + end, Config.PoliceHelicopter, coords, true) + end +end) + + +RegisterNetEvent("qb-police:client:openStash", function() + TriggerServerEvent("inventory:server:OpenInventory", "stash", "policestash_"..QBCore.Functions.GetPlayerData().citizenid) + TriggerEvent("inventory:client:SetCurrentStash", "policestash_"..QBCore.Functions.GetPlayerData().citizenid) +end) + +RegisterNetEvent('qb-police:client:openTrash', function() + TriggerServerEvent("inventory:server:OpenInventory", "stash", "policetrash", { + maxweight = 4000000, + slots = 300, + }) + TriggerEvent("inventory:client:SetCurrentStash", "policetrash") +end) + +--##### Threads #####-- + +local dutylisten = false +local function dutylistener() + dutylisten = true + CreateThread(function() + while dutylisten do + if PlayerJob.name == "police" then + if IsControlJustReleased(0, 38) then + TriggerServerEvent("QBCore:ToggleDuty") + TriggerServerEvent("police:server:UpdateCurrentCops") + TriggerServerEvent("police:server:UpdateBlips") + dutylisten = false + break + end + else + break + end + Wait(0) + end + end) +end + +-- Personal Stash Thread +local function stash() + CreateThread(function() + while true do + Wait(0) + if inStash and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsControlJustReleased(0, 38) then + TriggerServerEvent("inventory:server:OpenInventory", "stash", "policestash_"..QBCore.Functions.GetPlayerData().citizenid) + TriggerEvent("inventory:client:SetCurrentStash", "policestash_"..QBCore.Functions.GetPlayerData().citizenid) + break + end + else + break + end + end + end) +end + +-- Police Trash Thread +local function trash() + CreateThread(function() + while true do + Wait(0) + if inTrash and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsControlJustReleased(0, 38) then + TriggerServerEvent("inventory:server:OpenInventory", "stash", "policetrash", { + maxweight = 4000000, + slots = 300, + }) + TriggerEvent("inventory:client:SetCurrentStash", "policetrash") + break + end + else + break + end + end + end) +end + +-- Fingerprint Thread +local function fingerprint() + CreateThread(function() + while true do + Wait(0) + if inFingerprint and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsControlJustReleased(0, 38) then + TriggerEvent("qb-police:client:scanFingerPrint") + break + end + else + break + end + end + end) +end + +-- Armoury Thread +local function armoury() + CreateThread(function() + while true do + Wait(0) + if inAmoury and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsControlJustReleased(0, 38) then + TriggerEvent("qb-police:client:openArmoury") + break + end + else + break + end + end + end) +end + +-- Helicopter Thread +local function heli() + CreateThread(function() + while true do + Wait(0) + if inHelicopter and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsControlJustReleased(0, 38) then + TriggerEvent("qb-police:client:spawnHelicopter") + break + end + else + break + end + end + end) +end + +-- Police Impound Thread +local function impound() + CreateThread(function() + while true do + Wait(0) + if inImpound and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsPedInAnyVehicle(PlayerPedId(), false) then + if IsControlJustReleased(0, 38) then + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) + break + end + end + else + break + end + end + end) +end + +-- Police Garage Thread +local function garage() + CreateThread(function() + while true do + Wait(0) + if inGarage and PlayerJob.name == "police" then + if PlayerJob.onduty then sleep = 5 end + if IsPedInAnyVehicle(PlayerPedId(), false) then + if IsControlJustReleased(0, 38) then + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) + break + end + end + else + break + end + end + end) +end + +if Config.UseTarget then + CreateThread(function() + -- Toggle Duty + for k, v in pairs(Config.Locations["duty"]) do + exports['qb-target']:AddBoxZone("PoliceDuty_"..k, vector3(v.x, v.y, v.z), 1, 1, { + name = "PoliceDuty_"..k, + heading = 11, + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }, { + options = { + { + type = "client", + event = "qb-policejob:ToggleDuty", + icon = "fas fa-sign-in-alt", + label = "Gå på arbejde", + job = "police", + }, + }, + distance = 1.5 + }) + end + + -- Personal Stash + for k, v in pairs(Config.Locations["stash"]) do + exports['qb-target']:AddBoxZone("PoliceStash_"..k, vector3(v.x, v.y, v.z), 1.5, 1.5, { + name = "PoliceStash_"..k, + heading = 11, + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }, { + options = { + { + type = "client", + event = "qb-police:client:openStash", + icon = "fas fa-dungeon", + label = "Åben personligt stash", + job = "police", + }, + }, + distance = 1.5 + }) + end + + -- Police Trash + for k, v in pairs(Config.Locations["trash"]) do + exports['qb-target']:AddBoxZone("PoliceTrash_"..k, vector3(v.x, v.y, v.z), 1, 1.75, { + name = "PoliceTrash_"..k, + heading = 11, + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }, { + options = { + { + type = "client", + event = "qb-police:client:openTrash", + icon = "fas fa-trash", + label = "Åben skraldespand", + job = "police", + }, + }, + distance = 1.5 + }) + end + + -- Fingerprint + for k, v in pairs(Config.Locations["fingerprint"]) do + exports['qb-target']:AddBoxZone("PoliceFingerprint_"..k, vector3(v.x, v.y, v.z), 2, 1, { + name = "PoliceFingerprint_"..k, + heading = 11, + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }, { + options = { + { + type = "client", + event = "qb-police:client:scanFingerPrint", + icon = "fas fa-fingerprint", + label = "Åben fingeraftryk", + job = "police", + }, + }, + distance = 1.5 + }) + end + + -- Armoury + for k, v in pairs(Config.Locations["armory"]) do + exports['qb-target']:AddBoxZone("PoliceArmory_"..k, vector3(v.x, v.y, v.z), 5, 1, { + name = "PoliceArmory_"..k, + heading = 11, + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }, { + options = { + { + type = "client", + event = "qb-police:client:openArmoury", + icon = "fas fa-box", + label = "Åben Armory", + job = "police", + }, + }, + distance = 1.5 + }) + end + + --Tag elevator + for k, v in pairs(Config.Locations["roof"]) do + exports['qb-target']:AddBoxZone("roof" .. k, vector3(v.x, v.y, v.z), 2, 2, { + name = "roof" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-policejob:elevator_roof", + icon = "fas fa-hand-point-up", + label = "Tag elevator ned", + job = "police" + }, + }, + distance = 8 + }) + end + + --Main elevator + for k, v in pairs(Config.Locations["main"]) do + exports['qb-target']:AddBoxZone("main" .. k, vector3(v.x, v.y, v.z), 1.5, 1.5, { + name = "main" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-policejob:elevator_main", + icon = "fas fa-hand-point-up", + label = "Tag elevator op", + job = "police" + }, + { + type = "client", + event = "qb-policejob:elevator_basement", + icon = "fas fa-hand-point-down", + label = "Tag elevator ned", + job = "police" + } + }, + distance = 8 + }) + end + + --Ground floor + for k, v in pairs(Config.Locations["basement"]) do + exports['qb-target']:AddBoxZone("basement" .. k, vector3(v.x, v.y, v.z), 1.5, 1.5, { + name = "basement" .. k, + debugPoly = Config.Debug, + heading = -20, + minZ = v.z - 2, + maxZ = v.z + 2, + }, { + options = { + { + type = "client", + event = "qb-policejob:elevator_basement-main", + icon = "fas fa-hand-point-up", + label = "Tag elevator op", + job = "police" + }, + }, + distance = 8 + }) + end + + end) + +else + + -- Toggle Duty + local dutyZones = {} + for _, v in pairs(Config.Locations["duty"]) do + dutyZones[#dutyZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 1.75, 1, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local dutyCombo = ComboZone:Create(dutyZones, {name = "dutyCombo", debugPoly = false}) + dutyCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + dutylisten = true + if not PlayerJob.onduty then + exports['qb-core']:DrawText(Lang:t('info.on_duty'), 'top') + dutylistener() + else + exports['qb-core']:DrawText(Lang:t('info.off_duty'), 'top') + dutylistener() + end + else + dutylisten = false + exports['qb-core']:HideText() + end + end) + + -- Personal Stash + local stashZones = {} + for _, v in pairs(Config.Locations["stash"]) do + stashZones[#stashZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 1.5, 1.5, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local stashCombo = ComboZone:Create(stashZones, {name = "stashCombo", debugPoly = false}) + stashCombo:onPlayerInOut(function(isPointInside, _, _) + if isPointInside then + inStash = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + exports['qb-core']:DrawText(Lang:t('info.stash_enter'), 'top') + stash() + end + else + inStash = false + exports['qb-core']:HideText() + end + end) + + -- Police Trash + local trashZones = {} + for _, v in pairs(Config.Locations["trash"]) do + trashZones[#trashZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 1, 1.75, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local trashCombo = ComboZone:Create(trashZones, {name = "trashCombo", debugPoly = false}) + trashCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + inTrash = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + exports['qb-core']:DrawText(Lang:t('info.trash_enter'), 'top') + trash() + end + else + inTrash = false + exports['qb-core']:HideText() + end + end) + + -- Fingerprints + local fingerprintZones = {} + for _, v in pairs(Config.Locations["fingerprint"]) do + fingerprintZones[#fingerprintZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 2, 1, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local fingerprintCombo = ComboZone:Create(fingerprintZones, {name = "fingerprintCombo", debugPoly = false}) + fingerprintCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + inFingerprint = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + exports['qb-core']:DrawText(Lang:t('info.scan_fingerprint'), 'top') + fingerprint() + end + else + inFingerprint = false + exports['qb-core']:HideText() + end + end) + + -- Armoury + local armouryZones = {} + for _, v in pairs(Config.Locations["armory"]) do + armouryZones[#armouryZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 5, 1, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local armouryCombo = ComboZone:Create(armouryZones, {name = "armouryCombo", debugPoly = false}) + armouryCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + inAmoury = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + exports['qb-core']:DrawText(Lang:t('info.enter_armory'), 'top') + armoury() + end + else + inAmoury = false + exports['qb-core']:HideText() + end + end) + +end + +CreateThread(function() + -- Evidence Storage + local evidenceZones = {} + for _, v in pairs(Config.Locations["evidence"]) do + evidenceZones[#evidenceZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 2, 1, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local evidenceCombo = ComboZone:Create(evidenceZones, {name = "evidenceCombo", debugPoly = false}) + evidenceCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + if PlayerJob.name == "police" and PlayerJob.onduty then + local currentEvidence = 0 + local pos = GetEntityCoords(PlayerPedId()) + + for k, v in pairs(Config.Locations["evidence"]) do + if #(pos - v) < 2 then + currentEvidence = k + end + end + exports['qb-menu']:showHeader({ + { + header = Lang:t('info.evidence_stash', {value = currentEvidence}), + params = { + event = 'police:client:EvidenceStashDrawer', + args = { + currentEvidence = currentEvidence + } + } + } + }) + end + else + exports['qb-menu']:closeMenu() + end + end) + + -- Helicopter + local helicopterZones = {} + for _, v in pairs(Config.Locations["helicopter"]) do + helicopterZones[#helicopterZones+1] = BoxZone:Create( + vector3(vector3(v.x, v.y, v.z)), 10, 10, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local helicopterCombo = ComboZone:Create(helicopterZones, {name = "helicopterCombo", debugPoly = false}) + helicopterCombo:onPlayerInOut(function(isPointInside) + if isPointInside then + inHelicopter = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + if IsPedInAnyVehicle(PlayerPedId(), false) then + exports['qb-core']:HideText() + exports['qb-core']:DrawText(Lang:t('info.store_heli'), 'top') + heli() + else + if not ownedHeli then return end + exports['qb-core']:DrawText(Lang:t('info.take_heli'), 'top') + heli() + end + end + else + inHelicopter = false + exports['qb-core']:HideText() + end + end) + + -- Police Impound + local impoundZones = {} + for _, v in pairs(Config.Locations["impound"]) do + impoundZones[#impoundZones+1] = BoxZone:Create( + vector3(v.x, v.y, v.z), 1, 1, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + heading = 180, + }) + end + + local impoundCombo = ComboZone:Create(impoundZones, {name = "impoundCombo", debugPoly = false}) + impoundCombo:onPlayerInOut(function(isPointInside, point) + if isPointInside then + inImpound = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + if IsPedInAnyVehicle(PlayerPedId(), false) then + exports['qb-core']:DrawText(Lang:t('info.impound_veh'), 'top') + impound() + else + local currentSelection = 0 + + for k, v in pairs(Config.Locations["impound"]) do + if #(point - vector3(v.x, v.y, v.z)) < 4 then + currentSelection = k + end + end + exports['qb-menu']:showHeader({ + { + header = Lang:t('menu.pol_impound'), + params = { + event = 'police:client:ImpoundMenuHeader', + args = { + currentSelection = currentSelection, + } + } + } + }) + end + end + else + inImpound = false + exports['qb-menu']:closeMenu() + exports['qb-core']:HideText() + end + end) + + -- Police Garage + local garageZones = {} + for _, v in pairs(Config.Locations["vehicle"]) do + garageZones[#garageZones+1] = BoxZone:Create( + vector3(v.x, v.y, v.z), 3, 3, { + name="box_zone", + debugPoly = false, + minZ = v.z - 1, + maxZ = v.z + 1, + }) + end + + local garageCombo = ComboZone:Create(garageZones, {name = "garageCombo", debugPoly = false}) + garageCombo:onPlayerInOut(function(isPointInside, point) + if isPointInside then + inGarage = true + if PlayerJob.name == 'police' and PlayerJob.onduty then + if IsPedInAnyVehicle(PlayerPedId(), false) then + exports['qb-core']:DrawText(Lang:t('info.store_veh'), 'top') + garage() + else + local currentSelection = 0 + + for k, v in pairs(Config.Locations["vehicle"]) do + if #(point - vector3(v.x, v.y, v.z)) < 4 then + currentSelection = k + end + end + exports['qb-menu']:showHeader({ + { + header = Lang:t('menu.pol_garage'), + params = { + event = 'police:client:VehicleMenuHeader', + args = { + currentSelection = currentSelection, + } + } + } + }) + end + end + else + inGarage = false + exports['qb-menu']:closeMenu() + exports['qb-core']:HideText() + end + end) +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/main.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/main.lua new file mode 100644 index 0000000..736d1ce --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/main.lua @@ -0,0 +1,223 @@ +-- Variables +QBCore = exports['qb-core']:GetCoreObject() +isHandcuffed = false +cuffType = 1 +isEscorted = false +PlayerJob = {} +local DutyBlips = {} + +-- Functions +local function CreateDutyBlips(playerId, playerLabel, playerJob, playerLocation) + local ped = GetPlayerPed(playerId) + local blip = GetBlipFromEntity(ped) + local pedinvehicle = IsPedInAnyVehicle(ped) + if not DoesBlipExist(blip) then + if NetworkIsPlayerActive(playerId) then + blip = AddBlipForEntity(ped) + else + blip = AddBlipForCoord(playerLocation.x, playerLocation.y, playerLocation.z) + end + if pedinvehicle then + SetBlipSprite(blip, 812) + ShowHeadingIndicatorOnBlip(blip, false) + else + SetBlipSprite(blip, 409) + ShowHeadingIndicatorOnBlip(blip, true) + end + SetBlipRotation(blip, math.ceil(playerLocation.w)) + SetBlipScale(blip, 1.0) + if playerJob == "police" then + SetBlipColour(blip, 38) + else + SetBlipColour(blip, 5) + end + SetBlipAsShortRange(blip, true) + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(playerLabel) + EndTextCommandSetBlipName(blip) + DutyBlips[#DutyBlips+1] = blip + end + + if GetBlipFromEntity(PlayerPedId()) == blip then + -- Ensure we remove our own blip. + RemoveBlip(blip) + end +end + +-- Events +AddEventHandler('QBCore:Client:OnPlayerLoaded', function() + local player = QBCore.Functions.GetPlayerData() + PlayerJob = player.job + isHandcuffed = false + TriggerServerEvent("police:server:SetHandcuffStatus", false) + TriggerServerEvent("police:server:UpdateBlips") + TriggerServerEvent("police:server:UpdateCurrentCops") + + if player.metadata.tracker then + local trackerClothingData = { + outfitData = { + ["accessory"] = { + item = 13, + texture = 0 + } + } + } + TriggerEvent('qb-clothing:client:loadOutfit', trackerClothingData) + else + local trackerClothingData = { + outfitData = { + ["accessory"] = { + item = -1, + texture = 0 + } + } + } + TriggerEvent('qb-clothing:client:loadOutfit', trackerClothingData) + end + + if PlayerJob and PlayerJob.name ~= "police" then + if DutyBlips then + for _, v in pairs(DutyBlips) do + RemoveBlip(v) + end + end + DutyBlips = {} + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + TriggerServerEvent('police:server:UpdateBlips') + TriggerServerEvent("police:server:SetHandcuffStatus", false) + TriggerServerEvent("police:server:UpdateCurrentCops") + isHandcuffed = false + isEscorted = false + PlayerJob = {} + ClearPedTasks(PlayerPedId()) + DetachEntity(PlayerPedId(), true, false) + if DutyBlips then + for _, v in pairs(DutyBlips) do + RemoveBlip(v) + end + DutyBlips = {} + end +end) + +RegisterNetEvent("QBCore:Client:SetDuty", function(newDuty) + PlayerJob.onduty = newDuty +end) + +RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) + if JobInfo.name ~= "police" then + if DutyBlips then + for _, v in pairs(DutyBlips) do + RemoveBlip(v) + end + end + DutyBlips = {} + end + PlayerJob = JobInfo + TriggerServerEvent("police:server:UpdateBlips") +end) + +RegisterNetEvent('police:client:sendBillingMail', function(amount) + SetTimeout(math.random(2500, 4000), function() + local gender = Lang:t('info.mr') + if QBCore.Functions.GetPlayerData().charinfo.gender == 1 then + gender = Lang:t('info.mrs') + end + local charinfo = QBCore.Functions.GetPlayerData().charinfo + TriggerServerEvent('qb-phone:server:sendNewMail', { + sender = Lang:t('email.sender'), + subject = Lang:t('email.subject'), + message = Lang:t('email.message', {value = gender, value2 = charinfo.lastname, value3 = amount}), + button = {} + }) + end) +end) + +RegisterNetEvent('police:client:UpdateBlips', function(players) + if PlayerJob and (PlayerJob.name == 'police' or PlayerJob.name == 'ambulance') and + PlayerJob.onduty then + if DutyBlips then + for _, v in pairs(DutyBlips) do + RemoveBlip(v) + end + end + DutyBlips = {} + if players then + for _, data in pairs(players) do + local id = GetPlayerFromServerId(data.source) + CreateDutyBlips(id, data.label, data.job, data.location) + + end + end + end +end) + +RegisterNetEvent('police:client:policeAlert', function(coords, text) + local street1, street2 = GetStreetNameAtCoord(coords.x, coords.y, coords.z) + local street1name = GetStreetNameFromHashKey(street1) + local street2name = GetStreetNameFromHashKey(street2) + local newText = text .. ' ' .. street1name .. ' ' .. street2name + QBCore.Functions.Notify(newText, 'info') + PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1) + local transG = 250 + local blip = AddBlipForCoord(coords.x, coords.y, coords.z) + local blip2 = AddBlipForCoord(coords.x, coords.y, coords.z) + local blipText = Lang:t('info.blip_text', {value = text}) + SetBlipSprite(blip, 60) + SetBlipSprite(blip2, 161) + SetBlipColour(blip, 1) + SetBlipColour(blip2, 1) + SetBlipDisplay(blip, 4) + SetBlipDisplay(blip2, 8) + SetBlipAlpha(blip, transG) + SetBlipAlpha(blip2, transG) + SetBlipScale(blip, 0.8) + SetBlipScale(blip2, 2.0) + SetBlipAsShortRange(blip, false) + SetBlipAsShortRange(blip2, false) + PulseBlip(blip2) + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(blipText) + EndTextCommandSetBlipName(blip) + while transG ~= 0 do + Wait(180 * 4) + transG = transG - 1 + SetBlipAlpha(blip, transG) + SetBlipAlpha(blip2, transG) + if transG == 0 then + RemoveBlip(blip) + return + end + end +end) + +RegisterNetEvent('police:client:SendToJail', function(time) + TriggerServerEvent("police:server:SetHandcuffStatus", false) + isHandcuffed = false + isEscorted = false + ClearPedTasks(PlayerPedId()) + DetachEntity(PlayerPedId(), true, false) + TriggerEvent("prison:client:Enter", time) +end) + +RegisterNetEvent('police:client:SendPoliceEmergencyAlert', function() + local Player = QBCore.Functions.GetPlayerData() + TriggerServerEvent('police:server:policeAlert', Lang:t('info.officer_down', {lastname = Player.charinfo.lastname, callsign = Player.metadata.callsign})) + TriggerServerEvent('hospital:server:ambulanceAlert', Lang:t('info.officer_down', {lastname = Player.charinfo.lastname, callsign = Player.metadata.callsign})) +end) + +-- Threads +CreateThread(function() + for _, station in pairs(Config.Locations["stations"]) do + local blip = AddBlipForCoord(station.coords.x, station.coords.y, station.coords.z) + SetBlipSprite(blip, 60) + SetBlipAsShortRange(blip, true) + SetBlipScale(blip, 0.8) + SetBlipColour(blip, 29) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(station.label) + EndTextCommandSetBlipName(blip) + end +end) diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/objects.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/objects.lua new file mode 100644 index 0000000..c01ee08 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/objects.lua @@ -0,0 +1,301 @@ +-- Variables +local ObjectList = {} +local SpawnedSpikes = {} +local spikemodel = `P_ld_stinger_s` +local ClosestSpike = nil + +-- Functions +local function GetClosestPoliceObject() + local pos = GetEntityCoords(PlayerPedId(), true) + local current = nil + local dist = nil + + for id, _ in pairs(ObjectList) do + local dist2 = #(pos - ObjectList[id].coords) + if current then + if dist2 < dist then + current = id + dist = dist2 + end + else + dist = dist2 + current = id + end + end + return current, dist +end + +function GetClosestSpike() + local pos = GetEntityCoords(PlayerPedId(), true) + local current = nil + local dist = nil + + for id, _ in pairs(SpawnedSpikes) do + if current then + if #(pos - vector3(SpawnedSpikes[id].coords.x, SpawnedSpikes[id].coords.y, SpawnedSpikes[id].coords.z)) < dist then + current = id + end + else + dist = #(pos - vector3(SpawnedSpikes[id].coords.x, SpawnedSpikes[id].coords.y, SpawnedSpikes[id].coords.z)) + current = id + end + end + ClosestSpike = current +end + +local function DrawText3D(x, y, z, text) + SetTextScale(0.35, 0.35) + SetTextFont(4) + SetTextProportional(1) + SetTextColour(255, 255, 255, 215) + SetTextEntry("STRING") + SetTextCentre(true) + AddTextComponentString(text) + SetDrawOrigin(x,y,z, 0) + DrawText(0.0, 0.0) + local factor = (string.len(text)) / 370 + DrawRect(0.0, 0.0+0.0125, 0.017+ factor, 0.03, 0, 0, 0, 75) + ClearDrawOrigin() +end + +-- Events +RegisterNetEvent('police:client:spawnCone', function() + QBCore.Functions.Progressbar("spawn_object", Lang:t("progressbar.place_object"), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@narcotics@trash", + anim = "drop_front", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + TriggerServerEvent("police:server:spawnObject", "cone") + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) +end) + +RegisterNetEvent('police:client:spawnBarrier', function() + QBCore.Functions.Progressbar("spawn_object", Lang:t("progressbar.place_object"), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@narcotics@trash", + anim = "drop_front", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + TriggerServerEvent("police:server:spawnObject", "barrier") + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) +end) + +RegisterNetEvent('police:client:spawnRoadSign', function() + QBCore.Functions.Progressbar("spawn_object", Lang:t("progressbar.place_object"), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@narcotics@trash", + anim = "drop_front", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + TriggerServerEvent("police:server:spawnObject", "roadsign") + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) +end) + +RegisterNetEvent('police:client:spawnTent', function() + QBCore.Functions.Progressbar("spawn_object", Lang:t("progressbar.place_object"), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@narcotics@trash", + anim = "drop_front", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + TriggerServerEvent("police:server:spawnObject", "tent") + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) +end) + +RegisterNetEvent('police:client:spawnLight', function() + QBCore.Functions.Progressbar("spawn_object", Lang:t("progressbar.place_object"), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "anim@narcotics@trash", + anim = "drop_front", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + TriggerServerEvent("police:server:spawnObject", "light") + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "anim@narcotics@trash", "drop_front", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) +end) + +RegisterNetEvent('police:client:deleteObject', function() + local objectId, dist = GetClosestPoliceObject() + if dist < 5.0 then + QBCore.Functions.Progressbar("remove_object", Lang:t('progressbar.remove_object'), 2500, false, true, { + disableMovement = true, + disableCarMovement = true, + disableMouse = false, + disableCombat = true, + }, { + animDict = "weapons@first_person@aim_rng@generic@projectile@thermal_charge@", + anim = "plant_floor", + flags = 16, + }, {}, {}, function() -- Done + StopAnimTask(PlayerPedId(), "weapons@first_person@aim_rng@generic@projectile@thermal_charge@", "plant_floor", 1.0) + TriggerServerEvent("police:server:deleteObject", objectId) + end, function() -- Cancel + StopAnimTask(PlayerPedId(), "weapons@first_person@aim_rng@generic@projectile@thermal_charge@", "plant_floor", 1.0) + QBCore.Functions.Notify(Lang:t("error.canceled"), "error") + end) + end +end) + +RegisterNetEvent('police:client:removeObject', function(objectId) + NetworkRequestControlOfEntity(ObjectList[objectId].object) + DeleteObject(ObjectList[objectId].object) + ObjectList[objectId] = nil +end) + +RegisterNetEvent('police:client:spawnObject', function(objectId, type, player) + local coords = GetEntityCoords(GetPlayerPed(GetPlayerFromServerId(player))) + local heading = GetEntityHeading(GetPlayerPed(GetPlayerFromServerId(player))) + local forward = GetEntityForwardVector(PlayerPedId()) + local x, y, z = table.unpack(coords + forward * 0.5) + local spawnedObj = CreateObject(Config.Objects[type].model, x, y, z, true, false, false) + PlaceObjectOnGroundProperly(spawnedObj) + SetEntityHeading(spawnedObj, heading) + FreezeEntityPosition(spawnedObj, Config.Objects[type].freeze) + ObjectList[objectId] = { + id = objectId, + object = spawnedObj, + coords = vector3(x, y, z - 0.3), + } +end) + +RegisterNetEvent('police:client:SpawnSpikeStrip', function() + if #SpawnedSpikes + 1 < Config.MaxSpikes then + if PlayerJob.name == "police" and PlayerJob.onduty then + local spawnCoords = GetOffsetFromEntityInWorldCoords(PlayerPedId(), 0.0, 2.0, 0.0) + local spike = CreateObject(spikemodel, spawnCoords.x, spawnCoords.y, spawnCoords.z, 1, 1, 1) + local netid = NetworkGetNetworkIdFromEntity(spike) + SetNetworkIdExistsOnAllMachines(netid, true) + SetNetworkIdCanMigrate(netid, false) + SetEntityHeading(spike, GetEntityHeading(PlayerPedId())) + PlaceObjectOnGroundProperly(spike) + SpawnedSpikes[#SpawnedSpikes+1] = { + coords = vector3(spawnCoords.x, spawnCoords.y, spawnCoords.z), + netid = netid, + object = spike, + } + TriggerServerEvent('police:server:SyncSpikes', SpawnedSpikes) + end + else + QBCore.Functions.Notify(Lang:t("error.no_spikestripe"), 'error') + end +end) + +RegisterNetEvent('police:client:SyncSpikes', function(table) + SpawnedSpikes = table +end) + +-- Threads +CreateThread(function() + while true do + if LocalPlayer.state.isLoggedIn then + GetClosestSpike() + end + Wait(500) + end +end) + +CreateThread(function() + while true do + if LocalPlayer.state.isLoggedIn then + if ClosestSpike then + local tires = { + {bone = "wheel_lf", index = 0}, + {bone = "wheel_rf", index = 1}, + {bone = "wheel_lm", index = 2}, + {bone = "wheel_rm", index = 3}, + {bone = "wheel_lr", index = 4}, + {bone = "wheel_rr", index = 5} + } + + for a = 1, #tires do + local vehicle = GetVehiclePedIsIn(PlayerPedId(), false) + local tirePos = GetWorldPositionOfEntityBone(vehicle, GetEntityBoneIndexByName(vehicle, tires[a].bone)) + local spike = GetClosestObjectOfType(tirePos.x, tirePos.y, tirePos.z, 15.0, spikemodel, 1, 1, 1) + local spikePos = GetEntityCoords(spike, false) + local distance = #(tirePos - spikePos) + + if distance < 1.8 then + if not IsVehicleTyreBurst(vehicle, tires[a].index, true) or IsVehicleTyreBurst(vehicle, tires[a].index, false) then + SetVehicleTyreBurst(vehicle, tires[a].index, false, 1000.0) + end + end + end + end + end + + Wait(3) + end +end) + +CreateThread(function() + while true do + local sleep = 1000 + if LocalPlayer.state.isLoggedIn then + if ClosestSpike then + local ped = PlayerPedId() + local pos = GetEntityCoords(ped) + local dist = #(pos - SpawnedSpikes[ClosestSpike].coords) + if dist < 4 then + if not IsPedInAnyVehicle(PlayerPedId()) then + if PlayerJob.name == "police" and PlayerJob.onduty then + sleep = 0 + DrawText3D(pos.x, pos.y, pos.z, Lang:t('info.delete_spike')) + if IsControlJustPressed(0, 38) then + local spike = NetToEnt(SpawnedSpikes[ClosestSpike].netid) + NetworkRegisterEntityAsNetworked(spike) + NetworkRequestControlOfEntity(spike) + SetEntityAsMissionEntity(spike) + Wait(500) + DeleteEntity(spike) + SpawnedSpikes[ClosestSpike] = nil + ClosestSpike = nil + TriggerServerEvent('police:server:SyncSpikes', SpawnedSpikes) + end + end + end + end + end + end + Wait(sleep) + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/client/tracker.lua b/resources/[qb]/[qb_jobs]/qb-policejob/client/tracker.lua new file mode 100644 index 0000000..1cbd70c --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/client/tracker.lua @@ -0,0 +1,59 @@ +RegisterNetEvent('police:client:CheckDistance', function() + local player, distance = QBCore.Functions.GetClosestPlayer() + if player ~= -1 and distance < 2.5 then + local playerId = GetPlayerServerId(player) + TriggerServerEvent("police:server:SetTracker", playerId) + else + QBCore.Functions.Notify(Lang:t("error.none_nearby"), "error") + end +end) + +RegisterNetEvent('police:client:SetTracker', function(bool) + local trackerClothingData = { + outfitData = { + ["accessory"] = { item = -1, texture = 0}, -- Nek / Das + } + } + + if bool then + trackerClothingData.outfitData = { + ["accessory"] = { item = 13, texture = 0} + } + + TriggerEvent('qb-clothing:client:loadOutfit', trackerClothingData) + else + TriggerEvent('qb-clothing:client:loadOutfit', trackerClothingData) + end +end) + +RegisterNetEvent('police:client:SendTrackerLocation', function(requestId) + local ped = PlayerPedId() + local coords = GetEntityCoords(ped) + + TriggerServerEvent('police:server:SendTrackerLocation', coords, requestId) +end) + +RegisterNetEvent('police:client:TrackerMessage', function(msg, coords) + PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1) + QBCore.Functions.Notify(msg, 'police') + local transG = 250 + local blip = AddBlipForCoord(coords.x, coords.y, coords.z) + SetBlipSprite(blip, 458) + SetBlipColour(blip, 1) + SetBlipDisplay(blip, 4) + SetBlipAlpha(blip, transG) + SetBlipScale(blip, 1.0) + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(Lang:t('info.ankle_location')) + EndTextCommandSetBlipName(blip) + while transG ~= 0 do + Wait(180 * 4) + transG = transG - 1 + SetBlipAlpha(blip, transG) + if transG == 0 then + SetBlipSprite(blip, 2) + RemoveBlip(blip) + return + end + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/config.lua b/resources/[qb]/[qb_jobs]/qb-policejob/config.lua new file mode 100644 index 0000000..c4ebcc3 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/config.lua @@ -0,0 +1,488 @@ +Config = {} + +Config.Objects = { + ["cone"] = {model = `prop_roadcone02a`, freeze = false}, + ["barrier"] = {model = `prop_barrier_work06a`, freeze = true}, + ["roadsign"] = {model = `prop_snow_sign_road_06g`, freeze = true}, + ["tent"] = {model = `prop_gazebo_03`, freeze = true}, + ["light"] = {model = `prop_worklight_03b`, freeze = true}, +} + +Config.MaxSpikes = 5 + +Config.HandCuffItem = 'handcuffs' + + + +Config.LicenseRank = 1 + +Config.UseTarget = GetConvar('UseTarget', 'false') == 'true' +Config.Locations = { + ["duty"] = { + [1] = vector3(439.72, -988.88, 31.94), + [2] = vector3(439.78, -987.04, 31.94), + }, + ["vehicle"] = { + [1] = vector4(0, 0, 0, 0), + [2] = vector4(0, 0, 0, 0), + [3] = vector4(0, 0, 0, 0), + }, + ["stash"] = { + [1] = vector3(467.48, -990.59, 35.06), + [2] = vector3(469.75, -991.95, 35.06), + [3] = vector3(470.69, -990.58, 35.06), + + }, + ["impound"] = { + [1] = vector4(471.84, -1001.63, 25.14, 102.65), + [2] = vector4(471.94, -997.67, 25.14, 92.65), + }, + ["helicopter"] = { + [1] = vector4(449.168, -981.325, 43.691, 87.234), + [2] = vector4(-475.43, 5988.353, 31.716, 31.34), + }, + ["armory"] = { + [1] = vector3(458.56, -996.99, 35.06), + [2] = vector3(454.63, -1000.29, 35.06), + [3] = vector3(456.01, -996.8, 36.18), + }, + ["trash"] = { + [1] = vector3(467.04, -1003.22, 30.46), + }, + ["fingerprint"] = { + [1] = vector3(484.45, -996.35, 26.38), + }, + ["evidence"] = { + [1] = vector3(462.3, -999.84, 30.87), + [2] = vector3(464.31, -1001.32, 30.46), + [3] = vector3(455.1456, -985.462, 30.689), + }, + ["stations"] = { + [1] = {label = "Politi Station", coords = vector4(429.2, -974.25, 30.71, 100.72)}, + [2] = {label = "Fængsel", coords = vector4(1845.903, 2585.873, 45.672, 272.249)}, + [3] = {label = "Politi Station", coords = vector4(-451.55, 6014.25, 31.716, 223.81)}, + }, -- Elevator points + ["roof"] = { + [1] = vector4(338.5, -583.85, 74.16, 245.5), + }, + ["main"] = { + [1] = vector3(334.2776, -588.3298, 43.2676), + [2] = vector3(333.1056, -591.6954, 43.2676), + }, + ["basement"] = { + [1] = vector3(325.4, -583.96, 28.85), + [2] = vector3(324.5142, -587.2818, 28.8474), + }, +} + +Config.ArmoryWhitelist = {} + + +Config.PoliceHelicopter = "POLMAV" + +Config.SecurityCameras = { + hideradar = false, + cameras = { + [1] = {label = "Pacific Bank CAM#1", coords = vector3(257.45, 210.07, 109.08), r = {x = -25.0, y = 0.0, z = 28.05}, canRotate = false, isOnline = true}, + [2] = {label = "Pacific Bank CAM#2", coords = vector3(232.86, 221.46, 107.83), r = {x = -25.0, y = 0.0, z = -140.91}, canRotate = false, isOnline = true}, + [3] = {label = "Pacific Bank CAM#3", coords = vector3(252.27, 225.52, 103.99), r = {x = -35.0, y = 0.0, z = -74.87}, canRotate = false, isOnline = true}, + [4] = {label = "Limited Ltd Grove St. CAM#1", coords = vector3(-53.1433, -1746.714, 31.546), r = {x = -35.0, y = 0.0, z = -168.9182}, canRotate = false, isOnline = true}, + [5] = {label = "Rob's Liqour Prosperity St. CAM#1", coords = vector3(-1482.9, -380.463, 42.363), r = {x = -35.0, y = 0.0, z = 79.53281}, canRotate = false, isOnline = true}, + [6] = {label = "Rob's Liqour San Andreas Ave. CAM#1", coords = vector3(-1224.874, -911.094, 14.401), r = {x = -35.0, y = 0.0, z = -6.778894}, canRotate = false, isOnline = true}, + [7] = {label = "Limited Ltd Ginger St. CAM#1", coords = vector3(-718.153, -909.211, 21.49), r = {x = -35.0, y = 0.0, z = -137.1431}, canRotate = false, isOnline = true}, + [8] = {label = "24/7 Supermarkt Innocence Blvd. CAM#1", coords = vector3(23.885, -1342.441, 31.672), r = {x = -35.0, y = 0.0, z = -142.9191}, canRotate = false, isOnline = true}, + [9] = {label = "Rob's Liqour El Rancho Blvd. CAM#1", coords = vector3(1133.024, -978.712, 48.515), r = {x = -35.0, y = 0.0, z = -137.302}, canRotate = false, isOnline = true}, + [10] = {label = "Limited Ltd West Mirror Drive CAM#1", coords = vector3(1151.93, -320.389, 71.33), r = {x = -35.0, y = 0.0, z = -119.4468}, canRotate = false, isOnline = true}, + [11] = {label = "24/7 Supermarkt Clinton Ave CAM#1", coords = vector3(383.402, 328.915, 105.541), r = {x = -35.0, y = 0.0, z = 118.585}, canRotate = false, isOnline = true}, + [12] = {label = "Limited Ltd Banham Canyon Dr CAM#1", coords = vector3(-1832.057, 789.389, 140.436), r = {x = -35.0, y = 0.0, z = -91.481}, canRotate = false, isOnline = true}, + [13] = {label = "Rob's Liqour Great Ocean Hwy CAM#1", coords = vector3(-2966.15, 387.067, 17.393), r = {x = -35.0, y = 0.0, z = 32.92229}, canRotate = false, isOnline = true}, + [14] = {label = "24/7 Supermarkt Ineseno Road CAM#1", coords = vector3(-3046.749, 592.491, 9.808), r = {x = -35.0, y = 0.0, z = -116.673}, canRotate = false, isOnline = true}, + [15] = {label = "24/7 Supermarkt Barbareno Rd. CAM#1", coords = vector3(-3246.489, 1010.408, 14.705), r = {x = -35.0, y = 0.0, z = -135.2151}, canRotate = false, isOnline = true}, + [16] = {label = "24/7 Supermarkt Route 68 CAM#1", coords = vector3(539.773, 2664.904, 44.056), r = {x = -35.0, y = 0.0, z = -42.947}, canRotate = false, isOnline = true}, + [17] = {label = "Rob's Liqour Route 68 CAM#1", coords = vector3(1169.855, 2711.493, 40.432), r = {x = -35.0, y = 0.0, z = 127.17}, canRotate = false, isOnline = true}, + [18] = {label = "24/7 Supermarkt Senora Fwy CAM#1", coords = vector3(2673.579, 3281.265, 57.541), r = {x = -35.0, y = 0.0, z = -80.242}, canRotate = false, isOnline = true}, + [19] = {label = "24/7 Supermarkt Alhambra Dr. CAM#1", coords = vector3(1966.24, 3749.545, 34.143), r = {x = -35.0, y = 0.0, z = 163.065}, canRotate = false, isOnline = true}, + [20] = {label = "24/7 Supermarkt Senora Fwy CAM#2", coords = vector3(1729.522, 6419.87, 37.262), r = {x = -35.0, y = 0.0, z = -160.089}, canRotate = false, isOnline = true}, + [21] = {label = "Fleeca Bank Hawick Ave CAM#1", coords = vector3(309.341, -281.439, 55.88), r = {x = -35.0, y = 0.0, z = -146.1595}, canRotate = false, isOnline = true}, + [22] = {label = "Fleeca Bank Legion Square CAM#1", coords = vector3(144.871, -1043.044, 31.017), r = {x = -35.0, y = 0.0, z = -143.9796}, canRotate = false, isOnline = true}, + [23] = {label = "Fleeca Bank Hawick Ave CAM#2", coords = vector3(-355.7643, -52.506, 50.746), r = {x = -35.0, y = 0.0, z = -143.8711}, canRotate = false, isOnline = true}, + [24] = {label = "Fleeca Bank Del Perro Blvd CAM#1", coords = vector3(-1214.226, -335.86, 39.515), r = {x = -35.0, y = 0.0, z = -97.862}, canRotate = false, isOnline = true}, + [25] = {label = "Fleeca Bank Great Ocean Hwy CAM#1", coords = vector3(-2958.885, 478.983, 17.406), r = {x = -35.0, y = 0.0, z = -34.69595}, canRotate = false, isOnline = true}, + [26] = {label = "Paleto Bank CAM#1", coords = vector3(-102.939, 6467.668, 33.424), r = {x = -35.0, y = 0.0, z = 24.66}, canRotate = false, isOnline = true}, + [27] = {label = "Del Vecchio Liquor Paleto Bay", coords = vector3(-163.75, 6323.45, 33.424), r = {x = -35.0, y = 0.0, z = 260.00}, canRotate = false, isOnline = true}, + [28] = {label = "Don's Country Store Paleto Bay CAM#1", coords = vector3(166.42, 6634.4, 33.69), r = {x = -35.0, y = 0.0, z = 32.00}, canRotate = false, isOnline = true}, + [29] = {label = "Don's Country Store Paleto Bay CAM#2", coords = vector3(163.74, 6644.34, 33.69), r = {x = -35.0, y = 0.0, z = 168.00}, canRotate = false, isOnline = true}, + [30] = {label = "Don's Country Store Paleto Bay CAM#3", coords = vector3(169.54, 6640.89, 33.69), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = false, isOnline = true}, + [31] = {label = "Vangelico Jewelery CAM#1", coords = vector3(-627.54, -239.74, 40.33), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = true, isOnline = true}, + [32] = {label = "Vangelico Jewelery CAM#2", coords = vector3(-627.51, -229.51, 40.24), r = {x = -35.0, y = 0.0, z = -95.78}, canRotate = true, isOnline = true}, + [33] = {label = "Vangelico Jewelery CAM#3", coords = vector3(-620.3, -224.31, 40.23), r = {x = -35.0, y = 0.0, z = 165.78}, canRotate = true, isOnline = true}, + [34] = {label = "Vangelico Jewelery CAM#4", coords = vector3(-622.57, -236.3, 40.31), r = {x = -35.0, y = 0.0, z = 5.78}, canRotate = true, isOnline = true}, + }, +} + +Config.AuthorizedVehicles = { + -- Grade 0 + [0] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 1 + [1] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + + }, + -- Grade 2 + [2] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 3 + [3] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + }, + -- Grade 4 + [4] = { + ["police"] = "Police Car 1", + ["police2"] = "Police Car 2", + ["police3"] = "Police Car 3", + ["police4"] = "Police Car 4", + ["policeb"] = "Police Car 5", + ["policet"] = "Police Car 6", + ["sheriff"] = "Sheriff Car 1", + ["sheriff2"] = "Sheriff Car 2", + } +} + +Config.WhitelistedVehicles = {} + +Config.AmmoLabels = { + ["AMMO_PISTOL"] = "9x19mm parabellum bullet", + ["AMMO_SMG"] = "9x19mm parabellum bullet", + ["AMMO_RIFLE"] = "7.62x39mm bullet", + ["AMMO_MG"] = "7.92x57mm mauser bullet", + ["AMMO_SHOTGUN"] = "12-gauge bullet", + ["AMMO_SNIPER"] = "Large caliber bullet", +} + +Config.Radars = { + vector4(-623.44421386719, -823.08361816406, 25.25704574585, 145.0), + vector4(-652.44421386719, -854.08361816406, 24.55704574585, 325.0), + vector4(1623.0114746094, 1068.9924316406, 80.903594970703, 84.0), + vector4(-2604.8994140625, 2996.3391113281, 27.528566360474, 175.0), + vector4(2136.65234375, -591.81469726563, 94.272926330566, 318.0), + vector4(2117.5764160156, -558.51013183594, 95.683128356934, 158.0), + vector4(406.89505004883, -969.06286621094, 29.436267852783, 33.0), + vector4(657.315, -218.819, 44.06, 320.0), + vector4(2118.287, 6040.027, 50.928, 172.0), + vector4(-106.304, -1127.5530, 30.778, 230.0), + vector4(-823.3688, -1146.980, 8.0, 300.0), +} + +Config.CarItems = { + [1] = { + name = "heavyarmor", + amount = 2, + info = {}, + type = "item", + slot = 1, + }, + [2] = { + name = "empty_evidence_bag", + amount = 10, + info = {}, + type = "item", + slot = 2, + }, + [3] = { + name = "police_stormram", + amount = 1, + info = {}, + type = "item", + slot = 3, + }, +} + +Config.Items = { + label = "Police Armory", + slots = 30, + items = { + [1] = { + name = "weapon_pistol", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_PI_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 1, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [2] = { + name = "weapon_stungun", + price = 0, + amount = 1, + info = { + serie = "", + }, + type = "weapon", + slot = 2, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [3] = { + name = "weapon_pumpshotgun", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 3, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [4] = { + name = "weapon_smg", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_SCOPE_MACRO_02", label = "1x Scope"}, + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + } + }, + type = "weapon", + slot = 4, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [5] = { + name = "weapon_carbinerifle", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + {component = "COMPONENT_AT_SCOPE_MEDIUM", label = "3x Scope"}, + } + }, + type = "weapon", + slot = 5, + authorizedJobGrades = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [18] = { + name = "weapon_carbinerifle_mk2", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_AT_AR_FLSH", label = "Flashlight"}, + {component = "COMPONENT_AT_AR_AFGRIP_02", label = "Foregrip"}, + {component = "COMPONENT_AT_SIGHTS", label = "Holographic Sight"}, + {component = "COMPONENT_AT_AR_SUPP", label = "Supressor"}, + {component = "COMPONENT_AT_CR_BARREL_02", label = "Heavy Barrel"}, + {component = "COMPONENT_CARBINERIFLE_MK2_CLIP_FMJ", label = "FMJ Rounds"}, + } + }, + type = "weapon", + slot = 5, + authorizedJobGrades = { 10, 18} + }, + [19] = { + name = "weapon_tacticalrifle", + price = 0, + amount = 1, + info = { + serie = "", + attachments = { + {component = "COMPONENT_TACTICALRIFLE_CLIP_02", label = "Større magasin"}, + {component = "COMPONENT_AT_AR_FLSH_REH", label = "Lommelygte"}, + {component = "COMPONENT_AT_AR_SUPP_02", label = "Lyddæmper"}, + {component = "COMPONENT_AT_AR_AFGRIP", label = "Foregrip"}, + } + }, + type = "weapon", + slot = 5, + authorizedJobGrades = { 10, 18} + }, + [6] = { + name = "weapon_nightstick", + price = 0, + amount = 1, + info = {}, + type = "weapon", + slot = 6, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [7] = { + name = "pistol_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 7, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [8] = { + name = "smg_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 8, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [9] = { + name = "shotgun_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 9, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [10] = { + name = "rifle_ammo", + price = 0, + amount = 5, + info = {}, + type = "item", + slot = 10, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [11] = { + name = "handcuffs", + price = 0, + amount = 1, + info = {}, + type = "item", + slot = 11, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [12] = { + name = "weapon_flashlight", + price = 0, + amount = 1, + info = {}, + type = "weapon", + slot = 12, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [13] = { + name = "empty_evidence_bag", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 13, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [14] = { + name = "police_stormram", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 14, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [15] = { + name = "armor", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 15, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [16] = { + name = "radio", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 16, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + }, + [17] = { + name = "heavyarmor", + price = 0, + amount = 50, + info = {}, + type = "item", + slot = 17, + authorizedJobGrades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + } + } +} + +Config.VehicleSettings = { + ["car1"] = { --- Model name + ["extras"] = { + ["1"] = true, -- on/off + ["2"] = true, + ["3"] = true, + ["4"] = true, + ["5"] = true, + ["6"] = true, + ["7"] = true, + ["8"] = true, + ["9"] = true, + ["10"] = true, + ["11"] = true, + ["12"] = true, + ["13"] = true, + }, + ["livery"] = 1, + }, + ["car2"] = { + ["extras"] = { + ["1"] = true, + ["2"] = true, + ["3"] = true, + ["4"] = true, + ["5"] = true, + ["6"] = true, + ["7"] = true, + ["8"] = true, + ["9"] = true, + ["10"] = true, + ["11"] = true, + ["12"] = true, + ["13"] = true, + }, + ["livery"] = 1, + } +} diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/fxmanifest.lua b/resources/[qb]/[qb_jobs]/qb-policejob/fxmanifest.lua new file mode 100644 index 0000000..307128f --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/fxmanifest.lua @@ -0,0 +1,46 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-PoliceJob' +version '1.2.0' + +shared_scripts { + 'config.lua', + '@qb-core/shared/locale.lua', + 'locales/en.lua', + 'locales/*.lua' +} + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/ComboZone.lua', + 'client/main.lua', + 'client/camera.lua', + 'client/interactions.lua', + 'client/job.lua', + 'client/heli.lua', + --'client/anpr.lua', + 'client/evidence.lua', + 'client/objects.lua', + 'client/tracker.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server/main.lua' +} + +ui_page 'html/index.html' + +files { + 'html/index.html', + 'html/vue.min.js', + 'html/script.js', + 'html/tablet-frame.png', + 'html/fingerprint.png', + 'html/main.css', + 'html/vcr-ocd.ttf' +} + +lua54 'yes' diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/fingerprint.png b/resources/[qb]/[qb_jobs]/qb-policejob/html/fingerprint.png new file mode 100644 index 0000000..7b12e3e Binary files /dev/null and b/resources/[qb]/[qb_jobs]/qb-policejob/html/fingerprint.png differ diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/index.html b/resources/[qb]/[qb_jobs]/qb-policejob/html/index.html new file mode 100644 index 0000000..3b76225 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/html/index.html @@ -0,0 +1,264 @@ + + + + + + + + +
+
{{ cameraLabel }}
+
{{ dateLabel }}
+
{{ timeLabel }}
+
{{ ipLabel }}
+
{{ connectLabel }}
+ +
+
+ +
+
+ fingerprint +
+ Fingerprint ID +

No result

+
+
+
+
+
+
+
+

MODEL: COSAGNETTI

+
+
+

Spanish Ave | Lagunas Pl

+
+
+

PLATE: 01AGB123

+
+
+

420 KM/U

+
+
+
+
+
+
+
+ + + + + + diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/main.css b/resources/[qb]/[qb_jobs]/qb-policejob/html/main.css new file mode 100644 index 0000000..b7b0964 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/html/main.css @@ -0,0 +1,342 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@100&display=swap'); + +.databank-container { + display:none!important; + user-select: none; +} + +/* Police Radar */ +#policeradar { + width: 495px; + height: 202px; + + position: absolute; + bottom: 10px; + right: 10px; + margin: auto; + + color: white; + background: rgba(20, 20, 20, 0.97); + background: linear-gradient(to bottom, rgb(50, 50, 50), rgb(25, 25, 25)); + border-radius: 10px; + + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: center; +} + +#policeradar .antennalabel { + font-family: 'Poppins', sans-serif; + font-size: 14px; + font-weight: bold; + text-align: center; + width: 100%; + position: absolute; +} + +#policeradar .antennalabeltop { + top: 0; + left: 0; + padding-top: 5px; +} + +#policeradar .antennalabelbottom { + bottom: 0; + left: 0; + padding-bottom: 5px; +} + +#policeradar .logo { + font-family: 'Poppins', sans-serif; + font-size: 17px; + font-weight: bold; + bottom: 15px; + right: 20px; + position: absolute; +} + +#policeradar .main { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + width: 100%; + height: 100%; +} + +#policeradar .patrolcontainer { + background-color: black; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; +} + +#policeradar .typecontainer { + background-color: black; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + width: 0; +} + +#policeradar .typecontainer .text { + font-family: 'Poppins', sans-serif; + font-size: 10px; + line-height: 27px; + margin-left: 13px; + color: black; +} + +#policeradar .typecontainer .active { + color: white; +} + +#policeradar .container { + display: flex; + flex-direction: column; + align-items: center; + height: 100%; + justify-content: space-around; +} + +#policeradar .arrowbox { + justify-content: center; + align-items: center; +} + +#policeradar .arrowbox i { + font-size: 20px; + padding-top: 5px; + padding-bottom: 5px; + color: black; +} + +#policeradar .arrowbox .active { + color: white; +} + +#policeradar .arrowbox .inactive { + color: black; +} + +#policeradar .container .label { + font-family: 'Poppins', sans-serif; + font-weight: bold; + font-size: 10px; + text-align: center; +} + +#policeradar .container .speedsourcecontainer { + width: 135px; + height: 58px; + display: flex; + justify-content: space-around; +} + +#policeradar .container .speedsourcecontainer .speednumber { + width: 100%; +} + +#policeradar .container .speedsourcecontainer .text { + font-family: 'Poppins', sans-serif; + font-size: 58px; + line-height: 58px; + width: 100%; + text-align: center; +} + +#policeradar .container .target { + background: rgb(200, 0, 0); + background: linear-gradient(to bottom, rgb(220, 0, 40), rgb(90, 0, 0)); +} + +#policeradar .container .patrol { + background: rgb(0, 125, 0); + background: linear-gradient(to bottom, rgb(0, 150, 0), rgb(0, 75, 0)); +} + +#policeradar .container .locked { + color: rgb(50, 0, 0); +} + +#policeradar .container .speedfastcontainer { + width: 99px; + height: 50px; + display: flex; + flex-direction: row; + justify-content: space-around; +} + +#policeradar .container .speedfastcontainer .speednumber { + width: 100%; +} + +#policeradar .container .speedfastcontainer .text { + font-family: 'Poppins', sans-serif; + font-size: 50px; + line-height: 50px; + width: 100%; + text-align: center; +} + +/* Police Radar - Remote Control */ +#policeradarrc { + width: 290px; + height: 350px; + + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + padding: 10px 5px; + + color: white; + background-color: rgba(20, 20, 20, 0.95); + border-radius: 5px; + + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: center; +} + +#policeradarrc .breakline { + width: 230px; + height: 10px; + background-color: white; +} + +#policeradarrc .label { + font-family: 'Poppins', sans-serif; +} + +#policeradarrc .container { + font-family: 'Poppins', sans-serif; + align-items: center; +} + +#policeradarrc .container button { + display: inline-block; + cursor: pointer; + text-decoration: none; + outline: none; + border: none; +} + +#policeradarrc .container button:hover { + background-color: #6cd3f9; +} + +#policeradarrc .container button:active { + background-color: #56a8c7; +} + +#policeradarrc .container .toggle { + padding: 5px 15px; + font-size: 16px; + text-align: center; + color: black; + background-color: white; + border-radius: 15px; + margin-bottom: 15px; +} + +#policeradarrc .container .limit { + padding: 5px 15px; + font-size: 16px; + text-align: center; + color: black; + background-color: white; + border-radius: 15px; + margin-top: 15px; +} + +#policeradarrc .container .close { + padding: 3px 7px; + font-size: 12px; +} + +#policeradarrc .container .rowbutton { + width: 60px; + height: 60px; +} + +#policeradarrc .container .frontopp { + border-top-left-radius: 50%; +} + +#policeradarrc .container .frontsame { + border-top-right-radius: 50%; +} + +#policeradarrc .container .rearopp { + border-bottom-left-radius: 50%; +} + +#policeradarrc .container .rearsame { + border-bottom-right-radius: 50%; +} + +/* Plate Reader */ +#platereader { + width: 300px; + height: 50px; + + position: absolute; + bottom: 105%; + margin: auto; + + color: white; + background: rgba(20, 20, 20, 0.97); + background: linear-gradient(to bottom, rgb(50, 50, 50), rgb(25, 25, 25)); + border-radius: 10px; + + display: grid; + grid-column-gap: 10px; + grid-row-gap: 10px; + grid-template-columns: repeat(2, 2fr); + background-color: #2196f3; + padding: 2%; +} + +#platereader .label { + display: grid; + grid-area: label; +} + +#platereader .container { + display: grid; + grid-template-columns: 100%; + grid-template-rows: 75% 25%; + grid-template-areas: + "pReader" + "label"; + background-color: #2196f3; + background: linear-gradient(to bottom, rgb(220, 0, 40), rgb(90, 0, 0)); +} + +#platereader .pReader { + display: grid; + grid-area: pReader; + font-family: 'Poppins', sans-serif; + font-weight: bold; + font-size: 20px; + letter-spacing: 2px; + text-align: center; + overflow-x: hidden; +} + +#platereader .label { + width: 100%; + height: 100%; + background-color: black; + font-family: 'Poppins', sans-serif; + font-weight: bold; + font-size: 10px; + text-align: center; +} diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/script.js b/resources/[qb]/[qb_jobs]/qb-policejob/html/script.js new file mode 100644 index 0000000..fefd493 --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/html/script.js @@ -0,0 +1,170 @@ + + +const CameraApp = new Vue({ + el: "#camcontainer", + + data: { + camerasOpen: false, + cameraLabel: ":)", + connectLabel: "CONNECTED", + ipLabel: "192.168.0.1", + dateLabel: "04/09/1999", + timeLabel: "16:27:49", + }, + + methods: { + OpenCameras(label, connected, cameraId, time) { + var today = new Date(); + var date = today.getDate()+'/'+(today.getMonth()+1)+'/'+today.getFullYear(); + var formatTime = "00:" + time + + this.camerasOpen = true; + this.ipLabel = "145.101.0."+cameraId; + if (connected) { + $("#blockscreen").css("display", "none"); + this.cameraLabel = label; + this.connectLabel = "CONNECTED"; + this.dateLabel = date; + this.timeLabel = formatTime; + + $("#connectedlabel").removeClass("disconnect"); + $("#connectedlabel").addClass("connect"); + } else { + $("#blockscreen").css("display", "block"); + this.cameraLabel = "ERROR #400: BAD REQUEST" + this.connectLabel = "CONNECTION FAILED"; + this.dateLabel = "ERROR"; + this.timeLabel = "ERROR"; + + $("#connectedlabel").removeClass("connect"); + $("#connectedlabel").addClass("disconnect"); + } + + }, + + CloseCameras() { + this.camerasOpen = false; + $("#blockscreen").css("display", "none"); + }, + + UpdateCameraLabel(label) { + this.cameraLabel = label; + }, + + UpdateCameraTime(time) { + var formatTime = "00:" + time + this.timeLabel = formatTime; + }, + } +}); + +HeliCam = {} +Databank = {} +Fingerprint = {} + +HeliCam.Open = function(data) { + $("#helicontainer").css("display", "block"); + $(".scanBar").css("height", "0%"); +} + +HeliCam.UpdateScan = function(data) { + $(".scanBar").css("height", data.scanvalue +"%"); +} + +HeliCam.UpdateVehicleInfo = function(data) { + $(".vehicleinfo").css("display", "block"); + $(".scanBar").css("height", "100%"); + $(".heli-model").find("p").html("MODEL: " + data.model); + $(".heli-plate").find("p").html("PLATE: " + data.plate); + $(".heli-street").find("p").html(data.street); + $(".heli-speed").find("p").html(data.speed + " KM/U"); +} + +HeliCam.DisableVehicleInfo = function() { + $(".vehicleinfo").css("display", "none"); +} + +HeliCam.Close = function() { + $("#helicontainer").css("display", "none"); + $(".vehicleinfo").css("display", "none"); + $(".scanBar").css("height", "0%"); +} + +Databank.Open = function() { + $(".databank-container").css("display", "block").css("user-select", "none"); + $(".databank-container iframe").css("display", "block"); + $(".tablet-frame").css("display", "block").css("user-select", "none"); + $(".databank-bg").css("display", "block"); +} + +Databank.Close = function() { + $(".databank-container iframe").css("display", "none"); + $(".databank-container").css("display", "none"); + $(".tablet-frame").css("display", "none"); + $(".databank-bg").css("display", "none"); + $.post("https://qb-policejob/closeDatabank", JSON.stringify({})); +} + +Fingerprint.Open = function() { + $(".fingerprint-container").fadeIn(150); + $(".fingerprint-id").html("Fingerprint ID

No result

"); +} + +Fingerprint.Close = function() { + $(".fingerprint-container").fadeOut(150); + $.post('https://qb-policejob/closeFingerprint'); +} + +Fingerprint.Update = function(data) { + $(".fingerprint-id").html("Fingerprint ID

"+data.fingerprintId+"

"); +} + +$(document).on('click', '.take-fingerprint', function(){ + $.post('https://qb-policejob/doFingerScan'); +}) + +document.onreadystatechange = () => { + if (document.readyState === "complete") { + window.addEventListener('message', function(event) { + + if (event.data.type == "enablecam") { + CameraApp.OpenCameras(event.data.label, event.data.connected, event.data.id, event.data.time); + } else if (event.data.type == "disablecam") { + CameraApp.CloseCameras(); + } else if (event.data.type == "updatecam") { + CameraApp.UpdateCameraLabel(event.data.label); + } else if (event.data.type == "updatecamtime") { + CameraApp.UpdateCameraTime(event.data.time); + } else if (event.data.type == "heliopen") { + HeliCam.Open(event.data); + } else if (event.data.type == "heliclose") { + HeliCam.Close(); + } else if (event.data.type == "heliscan") { + HeliCam.UpdateScan(event.data); + } else if (event.data.type == "heliupdateinfo") { + HeliCam.UpdateVehicleInfo(event.data); + } else if (event.data.type == "disablescan") { + HeliCam.DisableVehicleInfo(); + } else if (event.data.type == "databank") { + Databank.Open(); + } else if (event.data.type == "closedatabank") { + Databank.Close(); + } else if (event.data.type == "fingerprintOpen") { + Fingerprint.Open(); + } else if (event.data.type == "fingerprintClose") { + Fingerprint.Close(); + } else if (event.data.type == "updateFingerprintId") { + Fingerprint.Update(event.data); + } + }); + }; +}; + +$(document).on('keydown', function() { + switch(event.keyCode) { + case 27: // ESC + Databank.Close(); + Fingerprint.Close(); + break; + } +}); diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/tablet-frame.png b/resources/[qb]/[qb_jobs]/qb-policejob/html/tablet-frame.png new file mode 100644 index 0000000..3ed34e5 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/qb-policejob/html/tablet-frame.png differ diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/vcr-ocd.ttf b/resources/[qb]/[qb_jobs]/qb-policejob/html/vcr-ocd.ttf new file mode 100644 index 0000000..dcca687 Binary files /dev/null and b/resources/[qb]/[qb_jobs]/qb-policejob/html/vcr-ocd.ttf differ diff --git a/resources/[qb]/[qb_jobs]/qb-policejob/html/vue.min.js b/resources/[qb]/[qb_jobs]/qb-policejob/html/vue.min.js new file mode 100644 index 0000000..836793b --- /dev/null +++ b/resources/[qb]/[qb_jobs]/qb-policejob/html/vue.min.js @@ -0,0 +1,6 @@ +/*! + * Vue.js v2.5.13 + * (c) 2014-2017 Evan You + * Released under the MIT License. + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Vue=e()}(this,function(){"use strict";function t(t){return void 0===t||null===t}function e(t){return void 0!==t&&null!==t}function n(t){return!0===t}function r(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function i(t){return null!==t&&"object"==typeof t}function o(t){return"[object Object]"===Nn.call(t)}function a(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function s(t){return null==t?"":"object"==typeof t?JSON.stringify(t,null,2):String(t)}function c(t){var e=parseFloat(t);return isNaN(e)?t:e}function u(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i-1)return t.splice(n,1)}}function f(t,e){return Mn.call(t,e)}function p(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}function d(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function v(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function h(t,e){for(var n in e)t[n]=e[n];return t}function m(t){for(var e={},n=0;n0&&(tt((s=et(s,(o||"")+"_"+a))[0])&&tt(u)&&(l[c]=x(u.text+s[0].text),s.shift()),l.push.apply(l,s)):r(s)?tt(u)?l[c]=x(u.text+s):""!==s&&l.push(x(s)):tt(s)&&tt(u)?l[c]=x(u.text+s.text):(n(i._isVList)&&e(s.tag)&&t(s.key)&&e(o)&&(s.key="__vlist"+o+"_"+a+"__"),l.push(s)));return l}function nt(t,e){return(t.__esModule||fr&&"Module"===t[Symbol.toStringTag])&&(t=t.default),i(t)?e.extend(t):t}function rt(t){return t.isComment&&t.asyncFactory}function it(t){if(Array.isArray(t))for(var n=0;n=0||n.indexOf(t[i])<0)&&r.push(t[i]);return r}return t}}(n[o],r[o],i[o]));return e}(t);r&&h(t.extendOptions,r),(e=t.options=F(n,t.extendOptions)).name&&(e.components[e.name]=t)}}return e}function Rt(t){this._init(t)}function Ht(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i[r])return i[r];var o=t.name||n.options.name,a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=F(n.options,t),a.super=n,a.options.props&&function(t){var e=t.options.props;for(var n in e)mt(t.prototype,"_props",n)}(a),a.options.computed&&function(t){var e=t.options.computed;for(var n in e)gt(t.prototype,n,e[n])}(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,zn.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=h({},a.options),i[r]=a,a}}function Bt(t){return t&&(t.Ctor.options.name||t.tag)}function Ut(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!function(t){return"[object RegExp]"===Nn.call(t)}(t)&&t.test(e)}function Vt(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var s=Bt(a.componentOptions);s&&!e(s)&&zt(n,o,r,i)}}}function zt(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,l(n,e)}function Kt(t){for(var n=t.data,r=t,i=t;e(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(n=Jt(i.data,n));for(;e(r=r.parent);)r&&r.data&&(n=Jt(n,r.data));return function(t,n){if(e(t)||e(n))return qt(t,Wt(n));return""}(n.staticClass,n.class)}function Jt(t,n){return{staticClass:qt(t.staticClass,n.staticClass),class:e(t.class)?[t.class,n.class]:n.class}}function qt(t,e){return t?e?t+" "+e:t:e||""}function Wt(t){return Array.isArray(t)?function(t){for(var n,r="",i=0,o=t.length;i=0&&" "===(m=t.charAt(h));h--);m&&Ii.test(m)||(l=!0)}}else void 0===o?(v=i+1,o=t.slice(0,i).trim()):e();if(void 0===o?o=t.slice(0,i).trim():0!==v&&e(),a)for(i=0;i-1?{exp:t.slice(0,ii),key:'"'+t.slice(ii+1)+'"'}:{exp:t,key:null};ni=t,ii=oi=ai=0;for(;!_e();)be(ri=ge())?$e(ri):91===ri&&function(t){var e=1;oi=ii;for(;!_e();)if(t=ge(),be(t))$e(t);else if(91===t&&e++,93===t&&e--,0===e){ai=ii;break}}(ri);return{exp:t.slice(0,oi),key:t.slice(oi+1,ai)}}(t);return null===n.key?t+"="+e:"$set("+n.exp+", "+n.key+", "+e+")"}function ge(){return ni.charCodeAt(++ii)}function _e(){return ii>=ei}function be(t){return 34===t||39===t}function $e(t){for(var e=t;!_e()&&(t=ge())!==e;);}function Ce(t,e,n,r,i){e=function(t){return t._withTask||(t._withTask=function(){Er=!0;var e=t.apply(null,arguments);return Er=!1,e})}(e),n&&(e=function(t,e,n){var r=si;return function i(){null!==t.apply(null,arguments)&&we(e,i,n,r)}}(e,t,r)),si.addEventListener(t,e,or?{capture:r,passive:i}:r)}function we(t,e,n,r){(r||si).removeEventListener(t,e._withTask||e,n)}function xe(n,r){if(!t(n.data.on)||!t(r.data.on)){var i=r.data.on||{},o=n.data.on||{};si=r.elm,function(t){if(e(t[Li])){var n=Qn?"change":"input";t[n]=[].concat(t[Li],t[n]||[]),delete t[Li]}e(t[Mi])&&(t.change=[].concat(t[Mi],t.change||[]),delete t[Mi])}(i),X(i,o,Ce,we,r.context),si=void 0}}function ke(n,r){if(!t(n.data.domProps)||!t(r.data.domProps)){var i,o,a=r.elm,s=n.data.domProps||{},u=r.data.domProps||{};e(u.__ob__)&&(u=r.data.domProps=h({},u));for(i in s)t(u[i])&&(a[i]="");for(i in u){if(o=u[i],"textContent"===i||"innerHTML"===i){if(r.children&&(r.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i){a._value=o;var l=t(o)?"":String(o);(function(t,n){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,n)||function(t,n){var r=t.value,i=t._vModifiers;if(e(i)){if(i.lazy)return!1;if(i.number)return c(r)!==c(n);if(i.trim)return r.trim()!==n.trim()}return r!==n}(t,n))})(a,l)&&(a.value=l)}else a[i]=o}}}function Ae(t){var e=Oe(t.style);return t.staticStyle?h(t.staticStyle,e):e}function Oe(t){return Array.isArray(t)?m(t):"string"==typeof t?Fi(t):t}function Se(n,r){var i=r.data,o=n.data;if(!(t(i.staticStyle)&&t(i.style)&&t(o.staticStyle)&&t(o.style))){var a,s,c=r.elm,u=o.staticStyle,l=o.normalizedStyle||o.style||{},f=u||l,p=Oe(r.data.style)||{};r.data.normalizedStyle=e(p.__ob__)?h({},p):p;var d=function(t,e){var n,r={};if(e)for(var i=t;i.componentInstance;)(i=i.componentInstance._vnode)&&i.data&&(n=Ae(i.data))&&h(r,n);(n=Ae(t.data))&&h(r,n);for(var o=t;o=o.parent;)o.data&&(n=Ae(o.data))&&h(r,n);return r}(r,!0);for(s in f)t(d[s])&&Bi(c,s,"");for(s in d)(a=d[s])!==f[s]&&Bi(c,s,null==a?"":a)}}function Te(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(/\s+/).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Ee(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(/\s+/).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function je(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&h(e,Ki(t.name||"v")),h(e,t),e}return"string"==typeof t?Ki(t):void 0}}function Ne(t){Qi(function(){Qi(t)})}function Ie(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Te(t,e))}function Le(t,e){t._transitionClasses&&l(t._transitionClasses,e),Ee(t,e)}function Me(t,e,n){var r=De(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===qi?Zi:Yi,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c0&&(n=qi,l=a,f=o.length):e===Wi?u>0&&(n=Wi,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?qi:Wi:null)?n===qi?o.length:c.length:0;return{type:n,timeout:l,propCount:f,hasTransform:n===qi&&to.test(r[Gi+"Property"])}}function Pe(t,e){for(;t.length1}function Ve(t,e){!0!==e.data.show&&Re(e)}function ze(t,e,n){Ke(t,e,n),(Qn||er)&&setTimeout(function(){Ke(t,e,n)},0)}function Ke(t,e,n){var r=e.value,i=t.multiple;if(!i||Array.isArray(r)){for(var o,a,s=0,c=t.options.length;s-1,a.selected!==o&&(a.selected=o);else if(g(qe(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));i||(t.selectedIndex=-1)}}function Je(t,e){return e.every(function(e){return!g(e,t)})}function qe(t){return"_value"in t?t._value:t.value}function We(t){t.target.composing=!0}function Ge(t){t.target.composing&&(t.target.composing=!1,Ze(t.target,"input"))}function Ze(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function Xe(t){return!t.componentInstance||t.data&&t.data.transition?t:Xe(t.componentInstance._vnode)}function Ye(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Ye(it(e.children)):t}function Qe(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[Pn(o)]=i[o];return e}function tn(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}function en(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function nn(t){t.data.newPos=t.elm.getBoundingClientRect()}function rn(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}function on(t,e){var n=e?zo:Vo;return t.replace(n,function(t){return Uo[t]})}function an(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:function(t){for(var e={},n=0,r=t.length;n=0&&a[i].lowerCasedTag!==s;i--);else i=0;if(i>=0){for(var c=a.length-1;c>=i;c--)e.end&&e.end(a[c].tag,n,r);a.length=i,o=i&&a[i-1].tag}else"br"===s?e.start&&e.start(t,[],!0,n,r):"p"===s&&(e.start&&e.start(t,[],!1,n,r),e.end&&e.end(t,n,r))}for(var i,o,a=[],s=e.expectHTML,c=e.isUnaryTag||Bn,u=e.canBeLeftOpenTag||Bn,l=0;t;){if(i=t,o&&Ho(o)){var f=0,p=o.toLowerCase(),d=Bo[p]||(Bo[p]=new RegExp("([\\s\\S]*?)(]*>)","i")),v=t.replace(d,function(t,n,r){return f=r.length,Ho(p)||"noscript"===p||(n=n.replace(//g,"$1").replace(//g,"$1")),Jo(p,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""});l+=t.length-v.length,t=v,r(p,l-f,l)}else{var h=t.indexOf("<");if(0===h){if(Ao.test(t)){var m=t.indexOf("--\x3e");if(m>=0){e.shouldKeepComment&&e.comment(t.substring(4,m)),n(m+3);continue}}if(Oo.test(t)){var y=t.indexOf("]>");if(y>=0){n(y+2);continue}}var g=t.match(ko);if(g){n(g[0].length);continue}var _=t.match(xo);if(_){var b=l;n(_[0].length),r(_[1],b,l);continue}var $=function(){var e=t.match(Co);if(e){var r={tagName:e[1],attrs:[],start:l};n(e[0].length);for(var i,o;!(i=t.match(wo))&&(o=t.match(_o));)n(o[0].length),r.attrs.push(o);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=l,r}}();if($){!function(t){var n=t.tagName,i=t.unarySlash;s&&("p"===o&&go(n)&&r(o),u(n)&&o===n&&r(n));for(var l=c(n)||!!i,f=t.attrs.length,p=new Array(f),d=0;d=0){for(w=t.slice(h);!(xo.test(w)||Co.test(w)||Ao.test(w)||Oo.test(w)||(x=w.indexOf("<",1))<0);)h+=x,w=t.slice(h);C=t.substring(0,h),n(h)}h<0&&(C=t,t=""),e.chars&&C&&e.chars(C)}if(t===i){e.chars&&e.chars(t);break}}r()}(t,{warn:To,expectHTML:e.expectHTML,isUnaryTag:e.isUnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecodeNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,start:function(t,a,u){var l=i&&i.ns||Do(t);Qn&&"svg"===l&&(a=function(t){for(var e=[],n=0;nc&&(s.push(o=t.slice(c,i)),a.push(JSON.stringify(o)));var u=ae(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c':'
',Ro.innerHTML.indexOf(" ")>0}var jn=Object.freeze({}),Nn=Object.prototype.toString,In=u("slot,component",!0),Ln=u("key,ref,slot,slot-scope,is"),Mn=Object.prototype.hasOwnProperty,Dn=/-(\w)/g,Pn=p(function(t){return t.replace(Dn,function(t,e){return e?e.toUpperCase():""})}),Fn=p(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),Rn=/\B([A-Z])/g,Hn=p(function(t){return t.replace(Rn,"-$1").toLowerCase()}),Bn=function(t,e,n){return!1},Un=function(t){return t},Vn="data-server-rendered",zn=["component","directive","filter"],Kn=["beforeCreate","created","beforeMount","mounted","beforeUpdate","updated","beforeDestroy","destroyed","activated","deactivated","errorCaptured"],Jn={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:Bn,isReservedAttr:Bn,isUnknownElement:Bn,getTagNamespace:y,parsePlatformTagName:Un,mustUseProp:Bn,_lifecycleHooks:Kn},qn=/[^\w.$]/,Wn="__proto__"in{},Gn="undefined"!=typeof window,Zn="undefined"!=typeof WXEnvironment&&!!WXEnvironment.platform,Xn=Zn&&WXEnvironment.platform.toLowerCase(),Yn=Gn&&window.navigator.userAgent.toLowerCase(),Qn=Yn&&/msie|trident/.test(Yn),tr=Yn&&Yn.indexOf("msie 9.0")>0,er=Yn&&Yn.indexOf("edge/")>0,nr=Yn&&Yn.indexOf("android")>0||"android"===Xn,rr=Yn&&/iphone|ipad|ipod|ios/.test(Yn)||"ios"===Xn,ir=(Yn&&/chrome\/\d+/.test(Yn),{}.watch),or=!1;if(Gn)try{var ar={};Object.defineProperty(ar,"passive",{get:function(){or=!0}}),window.addEventListener("test-passive",null,ar)}catch(t){}var sr,cr,ur=function(){return void 0===sr&&(sr=!Gn&&"undefined"!=typeof global&&"server"===global.process.env.VUE_ENV),sr},lr=Gn&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,fr="undefined"!=typeof Symbol&&w(Symbol)&&"undefined"!=typeof Reflect&&w(Reflect.ownKeys);cr="undefined"!=typeof Set&&w(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var pr=y,dr=0,vr=function(){this.id=dr++,this.subs=[]};vr.prototype.addSub=function(t){this.subs.push(t)},vr.prototype.removeSub=function(t){l(this.subs,t)},vr.prototype.depend=function(){vr.target&&vr.target.addDep(this)},vr.prototype.notify=function(){for(var t=this.subs.slice(),e=0,n=t.length;eVr&&Fr[n].id>t.id;)n--;Fr.splice(n+1,0,t)}else Fr.push(t);Br||(Br=!0,q(ht))}}(this)},Kr.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||i(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){V(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},Kr.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},Kr.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Kr.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||l(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var Jr={enumerable:!0,configurable:!0,get:y,set:y},qr={lazy:!0};Nt(It.prototype);var Wr={init:function(t,n,r,i){if(!t.componentInstance||t.componentInstance._isDestroyed){(t.componentInstance=function(t,n,r,i){var o={_isComponent:!0,parent:n,_parentVnode:t,_parentElm:r||null,_refElm:i||null},a=t.data.inlineTemplate;return e(a)&&(o.render=a.render,o.staticRenderFns=a.staticRenderFns),new t.componentOptions.Ctor(o)}(t,Pr,r,i)).$mount(n?t.elm:void 0,n)}else if(t.data.keepAlive){var o=t;Wr.prepatch(o,o)}},prepatch:function(t,e){var n=e.componentOptions;!function(t,e,n,r,i){var o=!!(i||t.$options._renderChildren||r.data.scopedSlots||t.$scopedSlots!==jn);if(t.$options._parentVnode=r,t.$vnode=r,t._vnode&&(t._vnode.parent=r),t.$options._renderChildren=i,t.$attrs=r.data&&r.data.attrs||jn,t.$listeners=n||jn,e&&t.$options.props){Cr.shouldConvert=!1;for(var a=t._props,s=t.$options._propKeys||[],c=0;c1?v(n):n;for(var r=v(arguments,1),i=0,o=n.length;iparseInt(this.max)&&zt(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={};e.get=function(){return Jn},Object.defineProperty(t,"config",e),t.util={warn:pr,extend:h,mergeOptions:F,defineReactive:E},t.set=j,t.delete=N,t.nextTick=q,t.options=Object.create(null),zn.forEach(function(e){t.options[e+"s"]=Object.create(null)}),t.options._base=t,h(t.options.components,ti),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=v(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=F(this.options,t),this}}(t),Ht(t),function(t){zn.forEach(function(e){t[e]=function(t,n){return n?("component"===e&&o(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}})}(t)}(Rt),Object.defineProperty(Rt.prototype,"$isServer",{get:ur}),Object.defineProperty(Rt.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Rt.version="2.5.13";var ei,ni,ri,ii,oi,ai,si,ci,ui=u("style,class"),li=u("input,textarea,option,select,progress"),fi=function(t,e,n){return"value"===n&&li(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},pi=u("contenteditable,draggable,spellcheck"),di=u("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),vi="http://www.w3.org/1999/xlink",hi=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},mi=function(t){return hi(t)?t.slice(6,t.length):""},yi=function(t){return null==t||!1===t},gi={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},_i=u("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot"),bi=u("svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view",!0),$i=function(t){return _i(t)||bi(t)},Ci=Object.create(null),wi=u("text,number,password,search,email,tel,url"),xi=Object.freeze({createElement:function(t,e){var n=document.createElement(t);return"select"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute("multiple","multiple"),n)},createElementNS:function(t,e){return document.createElementNS(gi[t],e)},createTextNode:function(t){return document.createTextNode(t)},createComment:function(t){return document.createComment(t)},insertBefore:function(t,e,n){t.insertBefore(e,n)},removeChild:function(t,e){t.removeChild(e)},appendChild:function(t,e){t.appendChild(e)},parentNode:function(t){return t.parentNode},nextSibling:function(t){return t.nextSibling},tagName:function(t){return t.tagName},setTextContent:function(t,e){t.textContent=e},setAttribute:function(t,e,n){t.setAttribute(e,n)}}),ki={create:function(t,e){Xt(e)},update:function(t,e){t.data.ref!==e.data.ref&&(Xt(t,!0),Xt(e))},destroy:function(t){Xt(t,!0)}},Ai=new mr("",{},[]),Oi=["create","activate","update","remove","destroy"],Si={create:te,update:te,destroy:function(t){te(t,Ai)}},Ti=Object.create(null),Ei=[ki,Si],ji={create:re,update:re},Ni={create:oe,update:oe},Ii=/[\w).+\-_$\]]/,Li="__r",Mi="__c",Di={create:xe,update:xe},Pi={create:ke,update:ke},Fi=p(function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach(function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e}),Ri=/^--/,Hi=/\s*!important$/,Bi=function(t,e,n){if(Ri.test(e))t.style.setProperty(e,n);else if(Hi.test(n))t.style.setProperty(e,n.replace(Hi,""),"important");else{var r=Vi(e);if(Array.isArray(n))for(var i=0,o=n.length;id?v(n,t(i[g+1])?null:i[g+1].elm,i,p,g,o):p>g&&m(0,r,f,d)}function _(r,i,o,a){if(r!==i){var s=i.elm=r.elm;if(n(r.isAsyncPlaceholder))e(i.asyncFactory.resolved)?$(r.elm,i,o):i.isAsyncPlaceholder=!0;else if(n(i.isStatic)&&n(r.isStatic)&&i.key===r.key&&(n(i.isCloned)||n(i.isOnce)))i.componentInstance=r.componentInstance;else{var c,u=i.data;e(u)&&e(c=u.hook)&&e(c=c.prepatch)&&c(r,i);var l=r.children,p=i.children;if(e(u)&&f(i)){for(c=0;c-1?Ci[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Ci[t]=/HTMLUnknownElement/.test(e.toString())},h(Rt.options.directives,ro),h(Rt.options.components,so),Rt.prototype.__patch__=Gn?eo:y,Rt.prototype.$mount=function(t,e){return t=t&&Gn?Zt(t):void 0,function(t,e,n){t.$el=e,t.$options.render||(t.$options.render=gr),vt(t,"beforeMount");var r;return r=function(){t._update(t._render(),n)},new Kr(t,r,y,null,!0),n=!1,null==t.$vnode&&(t._isMounted=!0,vt(t,"mounted")),t}(this,t,e)},Rt.nextTick(function(){Jn.devtools&&lr&&lr.emit("init",Rt)},0);var co,uo=/\{\{((?:.|\n)+?)\}\}/g,lo=/[-.*+?^${}()|[\]\/\\]/g,fo=p(function(t){var e=t[0].replace(lo,"\\$&"),n=t[1].replace(lo,"\\$&");return new RegExp(e+"((?:.|\\n)+?)"+n,"g")}),po={staticKeys:["staticClass"],transformNode:function(t,e){e.warn;var n=he(t,"class");n&&(t.staticClass=JSON.stringify(n));var r=ve(t,"class",!1);r&&(t.classBinding=r)},genData:function(t){var e="";return t.staticClass&&(e+="staticClass:"+t.staticClass+","),t.classBinding&&(e+="class:"+t.classBinding+","),e}},vo={staticKeys:["staticStyle"],transformNode:function(t,e){e.warn;var n=he(t,"style");n&&(t.staticStyle=JSON.stringify(Fi(n)));var r=ve(t,"style",!1);r&&(t.styleBinding=r)},genData:function(t){var e="";return t.staticStyle&&(e+="staticStyle:"+t.staticStyle+","),t.styleBinding&&(e+="style:("+t.styleBinding+"),"),e}},ho=function(t){return co=co||document.createElement("div"),co.innerHTML=t,co.textContent},mo=u("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),yo=u("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),go=u("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),_o=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,bo="[a-zA-Z_][\\w\\-\\.]*",$o="((?:"+bo+"\\:)?"+bo+")",Co=new RegExp("^<"+$o),wo=/^\s*(\/?)>/,xo=new RegExp("^<\\/"+$o+"[^>]*>"),ko=/^]+>/i,Ao=/^ + + + + + + + + 24/7 SHOP + + + + + + + + + + + + + +
+
+
+
+
+
+

24/7 SHOP

+ + Altid åbent, fordi du sover vel aldrig? + + images not found +
+
+
+
+
    +
+
+
+
+ Total + 150,000 $ +
+
+ + +
+
+
+

+ + + + Indkøbskurv +

+
+
+
+
+
+
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-shop/html/js/jquery-3.6.3.min.js b/resources/[qb]/[qb_shops]/qb-shop/html/js/jquery-3.6.3.min.js new file mode 100644 index 0000000..b5329e9 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-shop/html/js/jquery-3.6.3.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.3 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},S=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||S).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.3",E=function(e,t){return new E.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,S)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=E)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{if(d.cssSupportsSelector&&!CSS.supports("selector(:is("+c+"))"))throw new Error;return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===E&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[E]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,S=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssSupportsSelector=ce(function(){return CSS.supports("selector(*)")&&C.querySelectorAll(":is(:jqfake)")&&!CSS.supports("selector(:is(*,:jqfake))")}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=E,!C.getElementsByName||!C.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&S)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+E+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+E+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssSupportsSelector||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&S&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:S,!0)),N.test(r[1])&&E.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=S.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,D=E(S);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=S.createDocumentFragment().appendChild(S.createElement("div")),(fe=S.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),S.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;E.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||E.expando+"_"+Ct.guid++;return this[e]=!0,e}}),E.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||E.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?E(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=S.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=S.implementation.createHTMLDocument("")).createElement("base")).href=S.location.href,t.head.appendChild(r)):t=S),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0 +
+

${data.display}

+

${data.description}

+ +
+
+ image not found +
+
+ `); + + } else if (data.action == 'clear') { + $(".product_box").empty(); + $('.clear_btn').click(); + + } else if (data.action == 'close') { + $('.clear_btn').click(); + $('body').hide() + } + }); + + document.onkeyup = function (data) { + if (data.which == 27) { + $('body').hide(); + $.post('https://qb-shop/escape', '{}'); + } + }; + + $('.clear_btn').click(function () { + $("#shoppingCart_list").empty(); + shoppingCart = {}; + + $('.cart_item_box .total_price').attr('data-totalPrice', 0.0); + $('.cart_item_box .total_price').text(`0.0${moneySymbol}`); + }); + $('.pay_btn').click(async function() { + await $.post('https://qb-shop/buy', JSON.stringify({shoppingCart}), function(success) { + if (success) { + $('.clear_btn').click(); + $('body').hide(); + + } else { + $('body').hide(); + setTimeout(() => { + $('body').show(); + }, 2500); + }; + }); + }); + + $('.product_box').on('click', '.addToCartBtn', function() { + const productBox = $(this).parent().parent(); + const productItem = $(productBox).attr('data-item'); + const productDisplay = $(productBox).attr('data-display'); + const productUnityPrice = parseFloat($(productBox).attr('data-price')); + let productAmount = 1; + + if (!shoppingCart[productItem]) { + shoppingCart[productItem] = { display: productDisplay, price: productUnityPrice, amount: productAmount }; + $("#shoppingCart_list").append(` +
  • +
    + ${productDisplay}${productUnityPrice}$ +
    +
    +
    +
    ${productDisplay} x1
    +
    +
    +
  • + `); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_plus`).on('click', cartPlus_addProduct); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_minus`).on('click', cartMinus_removeProduct); + } else { + shoppingCart[productItem].amount++; + shoppingCart[productItem].price+=productUnityPrice; + productAmount = parseFloat(shoppingCart[productItem].amount); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_price`).text(`${productAmount}x - ${productUnityPrice}${moneySymbol}`); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_text`).html(`${productDisplay} x ${productAmount}`); + }; + + const currentTotalPrice = parseFloat($('.cart_item_box .total_price').attr('data-totalPrice')); + const newTotalPrice = parseFloat(currentTotalPrice + productUnityPrice); + $('.cart_item_box .total_price').attr('data-totalPrice', newTotalPrice); + $('.cart_item_box .total_price').text(`${newTotalPrice}${moneySymbol}`); + }); + + function cartPlus_addProduct() { + const productItem = $(this).parent().parent().attr('data-productItem'); + const inCartProduct = shoppingCart[productItem]; + const productCurrentAmount = parseFloat(inCartProduct.amount); + const productUnityPrice = parseFloat(parseFloat(inCartProduct.price)/productCurrentAmount); + + shoppingCart[productItem].amount++; + shoppingCart[productItem].price += productUnityPrice; + + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_price`).text(`${shoppingCart[productItem].amount}x - ${shoppingCart[productItem].price}${moneySymbol}`); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_text`).html(`${inCartProduct.display} x ${shoppingCart[productItem].amount}`); + + const currentTotalPrice = parseFloat($('.cart_item_box .total_price').attr('data-totalPrice')); + const newTotalPrice = parseFloat(currentTotalPrice + productUnityPrice); + $('.cart_item_box .total_price').attr('data-totalPrice', newTotalPrice); + $('.cart_item_box .total_price').text(`${newTotalPrice}${moneySymbol}`); + }; + function cartMinus_removeProduct() { + const productItem = $(this).parent().parent().attr('data-productItem'); + const inCartProduct = shoppingCart[productItem]; + const productCurrentAmount = parseFloat(inCartProduct.amount); + const productUnityPrice = parseFloat(parseFloat(inCartProduct.price)/productCurrentAmount); + + if (productCurrentAmount <= 1) { + delete shoppingCart[productItem]; + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"]`).remove(); + + } else { + shoppingCart[productItem].amount--; + shoppingCart[productItem].price -= productUnityPrice; + + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_price`).text(`${shoppingCart[productItem].amount}x - ${shoppingCart[productItem].price}${moneySymbol}`); + $("#shoppingCart_list").find(`li[data-productItem="${productItem}"] .cart_text`).html(`${inCartProduct.display} x ${shoppingCart[productItem].amount}`); + }; + + const currentTotalPrice = parseFloat($('.cart_item_box .total_price').attr('data-totalPrice')); + const newTotalPrice = parseFloat(currentTotalPrice - productUnityPrice); + $('.cart_item_box .total_price').attr('data-totalPrice', newTotalPrice); + $('.cart_item_box .total_price').text(`${newTotalPrice}${moneySymbol}`); + }; + + $(".filter-button").click(function () { + const value = $(this).attr("data-filter"); + + if (value == "all") { + $(".filter").show("2000"); + } else { + $(".filter") + .not("." + value) + .hide("2000"); + $(".filter") + .filter("." + value) + .show("2000"); + } + }); + if ($(".filter-button").removeClass("active")) { + $(this).removeClass("active"); + }; + $(this).addClass("active"); +}); \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-shop/html/style.css b/resources/[qb]/[qb_shops]/qb-shop/html/style.css new file mode 100644 index 0000000..8f63c4f --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-shop/html/style.css @@ -0,0 +1,606 @@ +@font-face { + font-family: Akrobat_bold; + src: url(fonts/Akrobat-ExtraBold.otf); +} +@font-face { + font-family: Akrobat; + src: url(fonts/Akrobat-Regular.otf); +} +@font-face { + font-family: PFDinDisplayPro; + src: url(fonts/PFDinDisplayPro-Regular.woff); + font-weight: 400; +} +@font-face { + font-family: PFDinDisplayPro; + font-weight: 700; + src: url(fonts/PFDinDisplayPro-Bold.woff); +} +* { + box-sizing: border-box; + margin: 0px; + padding: 0px; +} + +body { + font-family: "Akrobat", sans-serif; + font-weight: 400; + color: #ffffff; + font-size: 16px; + line-height: 1.4; + overflow-x: hidden; + display: none; +} +a, +a:hover { + color: inherit; + cursor: pointer; + text-decoration: none; +} + +ul { + list-style-type: none; + padding: 0; + margin: 0; +} +img { + max-width: 100%; +} +button { + border: none; + outline: none; + box-shadow: none; + cursor: pointer; +} +/* Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} +::placeholder { + /* Chrome, Firefox, Opera, Safari 10.1+ */ + color: #ffffff; + opacity: 1; /* Firefox */ +} + +:-ms-input-placeholder { + /* Internet Explorer 10-11 */ + color: #ffffff; +} +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +input:-webkit-autofill:active { + color: #ffffff; + transition: background-color 5000s ease-in-out 0s; +} +::-ms-input-placeholder { + /* Microsoft Edge */ + color: #ffffff; +} +/* Firefox */ +input[type="number"] { + -moz-appearance: textfield; +} +textarea:focus, +input:focus { + border: none; + outline: none; + box-shadow: none; +} +::selection { + color: white; + background: #ff7675; +} + +::-webkit-selection { + color: white; + background: #ff7675; +} + +::-moz-selection { + color: white; + background: #ff7675; +} + +.main_area { + position: relative; + background-image: url(img/shop_bg.png); + background-size: cover; + background-position: bottom center; + background-repeat: no-repeat; + min-height: 100vh; + width: 100%; +} +.container_box { + max-width: 1640px; + padding: 0px 150px; + margin: 0 auto; +} +.main_row { + display: flex; + justify-content: space-between; +} +.main_right { + width: 70%; + position: relative; + right: -40px; +} +.main_left { + width: 34%; + max-width: 300px; +} +.logo_box { + padding-top: 60px; + padding-bottom: 120px; +} +.logo_box h3 { + position: relative; + z-index: 9999; + font-family: PFDinDisplayPro; + font-weight: bold; + font-size: 48px; + color: #ffffff; + text-transform: uppercase; + text-shadow: 0px 0px 79px rgba(255, 255, 255, 0.35); +} +.logo_box span { + position: relative; + z-index: 9999; + font-family: PFDinDisplayPro; + font-size: 16px; + display: block; + font-weight: 400; +} +.logo_text { + position: relative; +} +.logo_text img { + max-width: 220px; + width: 100%; + position: absolute; + top: -14px; + left: -60px; +} +.cart_item_box { + position: relative; +} +.cart_item_box ul li .cart_price { + color: rgba(255, 255, 255, 0.65); +} + +.cart_item_box ul li { + position: relative; + z-index: 9999; + height: 55px; + margin-bottom: 10px; + font-weight: 600; + align-items: center; + justify-content: space-between; + overflow: hidden; + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 8px; +} +.cart_item_box ul li .cart_items { + position: absolute; + width: 100%; + height: 100%; + z-index: 9999; + display: flex; + padding: 12px 20px; + height: 55px; + margin-bottom: 10px; + font-weight: 600; + align-items: center; + justify-content: space-between; + overflow: hidden; + z-index: 999; + border-radius: 8px; + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} +.cart_item_box ul li .cart_items_number { + position: absolute; + bottom: -100%; + left: 0px; + width: 100%; + height: 100%; + padding: 12px 20px; + display: flex; + align-items: center; + justify-content: space-between; + z-index: -999; + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} + +.cart_item_box ul { + padding-bottom: 20px; +} +.cart_item_box ul li:hover .cart_items_number { + bottom: 0px; + z-index: 999999; + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} +.cart_item_box ul li:hover .cart_items { + position: absolute; + left: -100%; + z-index: -999; + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} +.cart_items .cart_text { + position: relative; +} +.cart_items_number button { + position: relative; + z-index: 999999; + background: transparent; + border: none; + font-size: 20px; + border-radius: 5px; + cursor: pointer; + font-weight: bold; + overflow: hidden; +} +.cart_items_number .cart_plus button, +.cart_items_number .cart_minus button { + background: transparent; + border: none; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +.cart_items_number .cart_minus button { + background: rgba(189, 101, 101, 0.15); + color: rgba(189, 101, 101, 1); +} +.cart_items_number .cart_plus button { + background: rgba(116, 189, 101, 0.15); + color: rgba(116, 189, 101, 1); +} +.cart_items_number .title_cart { + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + color: rgba(255, 255, 255, 0.05); + font-weight: bold; + text-transform: uppercase; + font-size: 24px; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + cursor: default; +} +.cart_item_box .side_title { + position: absolute; + left: -210px; + bottom: 78%; + display: flex; + transform: rotate(-90deg); + width: 100%; + height: 60px; +} + +.cart_item_box .side_title h4 { + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; +} + +.cart_item_box .side_title svg { + transform: rotate(90deg); + margin-right: 20px; + max-width: 26px; +} +.total_price_box { + max-width: 186px; + margin: 0px auto; + width: 100%; + border-bottom: 1px solid rgba(255, 255, 255, 0.11); + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 0px; +} +.total_price_box span { + display: block; + font-size: 16px; + font-weight: 600; + text-transform: uppercase; +} + +.total_price_box .total_price { + color: rgba(116, 189, 101, 1); + font-size: 20px; +} +.total_price_btns { + display: flex; + align-items: center; + justify-content: space-between; + max-width: 240px; + margin: 14px auto 0px; + padding-bottom: 70px; +} +.product_content button, +.total_price_btns button { + padding: 10px; + height: 50px; + max-width: 130px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background: rgba(116, 189, 101, 0.15); + border: 1px solid rgba(255, 255, 255, 0.11); + border-radius: 8px; + overflow: hidden; + font-weight: 600; + font-size: 16px; + text-transform: uppercase; + color: rgba(116, 189, 101, 1); + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} + +.total_price_btns .clear_btn { + max-width: 100px; + width: 100%; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.11); + border-radius: 8px; + color: rgba(255, 255, 255, 0.55); + transition: 0.3s ease-in-out; + -webkit-transition: 0.3s ease-in-out; + -moz-transition: 0.3s ease-in-out; +} + +.total_price_btns .clear_btn:hover, +.total_price_btns button:hover { + background: rgba(116, 189, 101, 0.6); + color: #ffffff; +} + +.product_box { + display: flex; + justify-content: flex-start; + align-items: flex-start; + flex-wrap: wrap; + padding-right: 10px; + padding-bottom: 10px; + /* height: 630px; */ + /* overflow-y: scroll; */ +} +.product__box-container { + max-height: 620px; + overflow-y: auto; + height: 100%; +} +/* Scroll Bar */ +/* ===== Scrollbar CSS ===== */ +/* Firefox */ +.product__box-container { + scrollbar-width: auto; + scrollbar-color: rgba(255, 255, 255, 0.1); +} + +/* Chrome, Edge, and Safari */ +.product__box-container::-webkit-scrollbar { + width: 4px; +} +.product__box-container::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); +} + +.product__box-container::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.1); + border-radius: 10px; + border: 4px solid #ffffff; +} +/* Scroll Bar */ + +.product_btns { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 60px; + padding-bottom: 70px; +} + +.filter-button { + width: 20%; + font-family: PFDinDisplayPro; + background: rgba(255, 255, 255, 0.03); + border-radius: 12px; + color: rgba(255, 255, 255, 0.55); + display: block; + text-transform: uppercase; + font-size: 15px; + padding: 8px 26px 10px; + font-weight: 600; + border-bottom: 1.5px solid rgba(116, 185, 110, 0); + min-width: 70px; + margin: 0% 0.5%; + overflow: hidden; + transition: 0.25s ease-in-out; + -webkit-transition: 0.25s ease-in-out; + -moz-transition: 0.25s ease-in-out; +} +.all_filter_button { + width: 15%; +} + +.filter-button:hover, +.product_btns .active { + background: linear-gradient( + 0deg, + rgba(116, 185, 110, 0.15) 0%, + rgba(116, 185, 110, 0.018) 45.05%, + rgba(116, 185, 110, 0) 74.14% + ); + border-bottom: 1.5px solid rgba(116, 185, 110, 0.65); + filter: drop-shadow(0px 0px 73px rgba(116, 185, 110, 0.05)); + border-radius: 25px; +} + +.filter-button span { + display: block; + max-width: 30px; + height: 2px; + background: transparent; + margin: 0px auto 5px; + transition: 0.25s ease-in-out; + -webkit-transition: 0.25s ease-in-out; + -moz-transition: 0.25s ease-in-out; +} +.filter-button:hover span { + background: rgba(116, 185, 110, 0.65); +} +.product_item { + width: 32%; + margin: 0% 0.65%; + background: linear-gradient( + 90deg, + rgba(255, 255, 255, 0.07) 0%, + rgba(255, 255, 255, 0) 80.34% + ); + border-radius: 12px; + overflow: hidden; + margin-bottom: 10px; + display: flex; + backdrop-filter: blur(4px); + align-items: center; + justify-content: space-between; +} +.product_content { + width: 55%; + padding: 20px; + padding-right: 0px; +} +.product_img { + width: 42%; +} +.product_img img { + height: 100%; + width: 100%; + margin-left: auto; +} +.product_content h4 { + font-size: 22px; + margin-bottom: 6px; +} +.product_content p { + font-size: 15px; + line-height: 1.4; + margin-bottom: 12px; +} +.product_content button { + height: 36px; + width: 76px; + font-size: 16px; + background: rgba(116, 189, 101, 0.15); + border-radius: 8px; + transition: 0.25s ease-in-out; + -webkit-transition: 0.25s ease-in-out; + -moz-transition: 0.25s ease-in-out; +} + +.product_content button:hover { + background: rgba(116, 189, 101, 0.3); +} + +@media screen and (max-width: 1400px) { + .container_box { + padding: 0px 100px; + } + .cart_item_box .side_title { + left: -180px; + } + .logo_box { + padding-bottom: 90px; + } + .filter-button { + font-size: 14px; + padding-left: 10px; + padding-right: 10px; + } + .product_btns { + padding-bottom: 40px; + } +} +@media screen and (max-width: 1300px) { + .container_box { + padding: 0px 100px; + } + .cart_item_box .side_title { + left: -180px; + } + .logo_box { + padding-bottom: 90px; + } + .product_item { + width: 48%; + } + .filter-button { + font-size: 12px; + padding-left: 10px; + padding-right: 10px; + } + .product_btns { + padding-bottom: 40px; + } +} + +/* some update css */ +.product__box-container { + overflow: hidden; + overflow-y: scroll; + scrollbar-width: thin; +} + +.t_new_div{ + height: 325px; + overflow: hidden; + overflow-y: scroll; + scrollbar-width: thin; + +} + +/* Firefox */ +.t_new_div { + scrollbar-width: auto; + scrollbar-color: rgba(255, 255, 255, 0.1); +} + +/* Chrome, Edge, and Safari */ +.t_new_div::-webkit-scrollbar { + width: 4px; +} +.t_new_div::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); +} + +.t_new_div::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.1); + border-radius: 10px; + border: 4px solid #ffffff; +} +/* Scroll Bar */ + + +/* End some update css */ \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-shop/server/main.lua b/resources/[qb]/[qb_shops]/qb-shop/server/main.lua new file mode 100644 index 0000000..76c2111 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-shop/server/main.lua @@ -0,0 +1,75 @@ +local FrameworkSelected = Config.Framework and Config.Framework:lower() or nil + +local ESX = nil +local QBCore = nil + +if (FrameworkSelected == "esx") then + if (Config.FrameworkCore) then + ESX = exports[Config.FrameworkCore]:getSharedObject() + if (not ESX) then + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + end + else + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + end + if (not ESX) then + print(' ERROR: Invalid FrameworkCore! Pls fix it on Config!!!') + end +elseif (FrameworkSelected == "qb" or FrameworkSelected == "qb-core" or FrameworkSelected == "qbcore") then + if (Config.FrameworkCore) then + QBCore = exports[Config.FrameworkCore]:GetCoreObject() + else + print(' ERROR: Invalid FrameworkCore! Pls fix it on Config!!!') + end +else + print(' ERROR: Unknown Framework! Available: ESX or QB!') +end + +local function getFrameworkPlayerBalance(FPlayer) + local balance = 0 + local payMethod = Config.PayMethod + if (ESX) then + if (payMethod == 'cash') then payMethod = 'money' end + balance = FPlayer.getAccount(payMethod).money + elseif (QBCore) then + if (payMethod == 'money') then payMethod = 'cash' end + balance = FPlayer.Functions.GetMoney(payMethod) + end + + return tonumber(balance) +end +local function removeFrameworkPlayerMoney(FPlayer, amount) + local payMethod = Config.PayMethod + if (ESX) then + if (payMethod == 'cash') then payMethod = 'money' end + FPlayer.removeAccountMoney(payMethod, amount) + elseif (QBCore) then + if (payMethod == 'cash') then payMethod = 'money' end + FPlayer.Functions.RemoveMoney(payMethod, amount) + end +end + +local function canAfford(source, cb, totalPrice, shoppingCart) + local _source = source + local FPlayer = ESX and ESX.GetPlayerFromId(_source) or QBCore and QBCore.Functions.GetPlayer(_source) + local playerBalance = getFrameworkPlayerBalance(FPlayer) + totalPrice = tonumber(totalPrice) + + if (playerBalance and playerBalance >= totalPrice) then + for k, v in pairs(shoppingCart) do + if (ESX) then FPlayer.addInventoryItem(k, v.amount or 1) + elseif (QBCore) then FPlayer.Functions.AddItem(k, v.amount or 1) + end + end + + removeFrameworkPlayerMoney(FPlayer, totalPrice) + + cb(true) + else + cb(false) + end +end + +if (ESX) then ESX.RegisterServerCallback('qb-shop:canAfford', canAfford) +elseif (QBCore) then QBCore.Functions.CreateCallback('qb-shop:canAfford', canAfford) +end diff --git a/resources/[qb]/[qb_shops]/qb-vape/client/cl_vape.lua b/resources/[qb]/[qb_shops]/qb-vape/client/cl_vape.lua new file mode 100644 index 0000000..70da012 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vape/client/cl_vape.lua @@ -0,0 +1,191 @@ +local QBCore = exports['qb-core']:GetCoreObject() -- Core +local isVaping = false +local dragsLeft = 0 + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() == resourceName then + VapeCraft() + end +end) + +AddEventHandler('onResourceStop', function(resourceName) + if GetCurrentResourceName() == resourceName then + exports['qb-target']:RemoveZone("vapeStuff") + isVaping = false + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + VapeCraft() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload') +AddEventHandler('QBCore:Client:OnPlayerUnload', function() + exports['qb-target']:RemoveZone("vapeStuff") + isVaping = false +end) + +function VapeCraft() + exports['qb-target']:AddCircleZone("vapeStuff", vector3(-1167.97, -1573.82, 4.26), 0.65, { + name="vapeStuff", + useZ=true, + }, { + options = { + { + type = "client", + icon = "fa-solid fa-screwdriver", + event = "qb-vape:client:OpenCraft", + label = "Craft Station", + }, + { + type = "client", + icon = "fa-solid fa-basket-shopping", + event = "qb-vape:client:supplies", + label = "Vape Store", + }, + }, + distance = 1.5 + }) +end + +RegisterNetEvent("qb-vape:client:supplies", function() + TriggerServerEvent("inventory:server:OpenInventory", "shop", "Vape", Config.Juice) +end) + +RegisterNetEvent('qb-vape:client:OpenCraft', function() + exports['qb-menu']:openMenu({ + { + id = 0, + header = "Vape-samling", + icon = "fa-solid fa-toolbox", + isMenuHeader = true, + }, + { + id = 1, + header = "Saml Vape", + txt = "Kræver:

    2x Jern | 2x Glas | 1x Elektronik Kit", + icon = "fa-solid fa-square-up-right", + params = { + event = "qb-vape:client:craftVape" + } + }, + { + id = 2, + header = "Genopfyld vape", + txt = "Kræver:

    1x Tom vape | 1x Vape Juice", + icon = "fa-solid fa-square-up-right", + params = { + event = "qb-vape:client:refillVape" + } + }, + { + id = 3, + header = "Luk menu", + txt = "", + icon = "fa-solid fa-angle-left", + params = { + event = "qb-menu:closeMenu" + } + }, + }) +end) + +RegisterNetEvent("qb-vape:client:useVape", function(ItemData) + local ped = PlayerPedId() + local pos = GetEntityCoords(ped) + local pedNet = PedToNet(ped) + local deadBozo = QBCore.Functions.GetPlayerData().metadata["isdead"] + if not deadBozo then + if not isVaping then + isVaping = true + TriggerEvent('animations:client:EmoteCommandStart', {"hitvape"}) + TriggerServerEvent("InteractSound_SV:PlayWithinDistance", 10.0, "vaping", 0.3) + QBCore.Functions.Progressbar("isVaping_lol", "Bapper på vapen..", 5000, false, false, { + disableMovement = false, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerEvent('animations:client:EmoteCommandStart', {"hitvape"}) + Wait(250) -- My hacky way of removing the prop that gets stuck if you go into first person and come back out. + TriggerEvent('animations:client:EmoteCommandStart', {"c"}) + TriggerServerEvent("qb-vape:server:syncSmoke", pedNet, pos) + TriggerServerEvent('hud:server:RelieveStress', math.random(6, 8)) + dragsLeft = ItemData.info.uses + dragsLeftData = ItemData + dragsLeft = dragsLeft - 5 -- -5% juice + TriggerServerEvent('qb-vape:server:updateVape', dragsLeft, dragsLeftData) + isVaping = false + end) + else + QBCore.Functions.Notify("Du har lige pattet på din vape, rolig.", "error") + end + else + QBCore.Functions.Notify("Du er død, bozo..", "error") + end +end) + +RegisterNetEvent("qb-vape:client:syncSmoke", function(netPed, pos) + local ped = PlayerPedId() + local plyPos = GetEntityCoords(ped) + local pedNet = NetToPed(netPed) + if #(plyPos - pos) < 150.0 then + if not HasNamedPtfxAssetLoaded("core") then RequestNamedPtfxAsset("core") while not HasNamedPtfxAssetLoaded("core") do Wait(0) end end + SetPtfxAssetNextCall("core") + vapeClouds = StartParticleFxLoopedOnEntityBone("exp_grd_bzgas_smoke", pedNet, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, GetPedBoneIndex(pedNet, 20279), 0.5, 0.0, 0.0, 0.0) + SetParticleFxLoopedAlpha(vapeClouds, 1.0) -- Not sure if this actually makes it more visible? + SetTimeout(5000, function() + StopParticleFxLooped(vapeClouds, 0) + end) + end +end) + +RegisterNetEvent('qb-vape:client:craftVape', function() + local iron = QBCore.Functions.HasItem("iron", 2) + local glass = QBCore.Functions.HasItem("glass", 2) + local elec = QBCore.Functions.HasItem("electronickit", 1) + if iron then + if glass then + if elec then + TriggerEvent('animations:client:EmoteCommandStart', {"mechanic4"}) + QBCore.Functions.Progressbar("vape_craft", "Samler vape..", 5000, false, false, { + disableMovement = true, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerServerEvent('qb-vape:server:makeVape') + end) + else + QBCore.Functions.Notify("Du skal bruge et elektronik kit", "error") + end + else + QBCore.Functions.Notify("Du har ikke nok glas.", "error") + end + else + QBCore.Functions.Notify("Du har ikke nok jern.", "error") + end +end) + + +RegisterNetEvent('qb-vape:client:refillVape', function() + local gotVape = QBCore.Functions.HasItem("emptyvape") + local gotJuice = QBCore.Functions.HasItem("vapejuice") + if gotVape then + if gotJuice then + TriggerEvent('animations:client:EmoteCommandStart', {"mechanic4"}) + QBCore.Functions.Progressbar("vape_craft", "Genopfylder vape..", 5000, false, false, { + disableMovement = true, + disableCarMovement = false, + disableMouse = false, + disableCombat = true, + }, {}, {}, {}, function() -- Done + TriggerServerEvent('qb-vape:server:fillVape') + end) + else + QBCore.Functions.Notify("Du har intet vapejuice at genopfylde med.", "error") + end + else + QBCore.Functions.Notify("Du skal bruge en tom vape, din tegning.", "error") + end +end) diff --git a/resources/[qb]/[qb_shops]/qb-vape/config.lua b/resources/[qb]/[qb_shops]/qb-vape/config.lua new file mode 100644 index 0000000..0ba5f26 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vape/config.lua @@ -0,0 +1,24 @@ +Config = {} + +Config.Juice = { + label = "Vape", + slots = 1, + items = { + [1] = { + name = "vapejuice", + price = 5500, + amount = 100, + info = {}, + type = "item", + slot = 1, + }, + [2] = { + name = "vape", + price = 10000, + amount = 100, + info = {}, + type = "item", + slot = 2, + }, + } +} \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vape/fxmanifest.lua b/resources/[qb]/[qb_shops]/qb-vape/fxmanifest.lua new file mode 100644 index 0000000..158fd6d --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vape/fxmanifest.lua @@ -0,0 +1,19 @@ +fx_version 'cerulean' +game 'gta5' + + +version 'V1.0' + +shared_scripts { + "config.lua" +} + +client_scripts { + "client/*.lua" +} + +server_scripts { + "server/*.lua" +} + +lua54 'yes' diff --git a/resources/[qb]/[qb_shops]/qb-vape/server/sv_vape.lua b/resources/[qb]/[qb_shops]/qb-vape/server/sv_vape.lua new file mode 100644 index 0000000..daca270 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vape/server/sv_vape.lua @@ -0,0 +1,70 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +RegisterNetEvent("qb-vape:server:syncSmoke", function(pedNet, pos) + for k, v in pairs(QBCore.Functions.GetPlayers()) do + TriggerClientEvent("qb-vape:client:syncSmoke", v, pedNet, pos) + end +end) + +RegisterNetEvent('QBCore:Server:UpdateObject', function() + if source ~= '' then return false end + QBCore = exports['qb-core']:GetCoreObject() +end) + +QBCore.Functions.CreateUseableItem("vape", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + TriggerClientEvent('qb-vape:client:useVape', src, item) +end) + + +QBCore.Functions.CreateUseableItem("emptyvape", function(source, item) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + QBCore.Functions.Notify(src, "Der er ikke mere vapejuice tilbage.", "error") +end) + +RegisterNetEvent('qb-vape:server:updateVape', function(vapesLeft, data) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + + if vapesLeft == 0 then + Player.Functions.RemoveItem('vape', 1, data.slot) + Player.Functions.AddItem('emptyvape', 1) + QBCore.Functions.Notify(src, "Din vape er løbet tør for vapejuice.", "error") + else + Player.PlayerData.items[data.slot].info.uses = Player.PlayerData.items[data.slot].info.uses - 5 + Player.Functions.SetInventory(Player.PlayerData.items) + end +end) + +RegisterNetEvent('qb-vape:server:makeVape', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local info = { + uses = 100 + } + Player.Functions.RemoveItem('electronickit', 1) + Player.Functions.RemoveItem('iron', 2) + Player.Functions.RemoveItem('glass', 2) + Player.Functions.AddItem('vape', 1, true, info) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items["vape"], "add") +end) + +RegisterNetEvent('qb-vape:server:fillVape', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if QBCore.Functions.HasItem(src, "emptyvape", 1) then + if QBCore.Functions.HasItem(src, "vapejuice", 1) then + local info = { + uses = 100 + } + Player.Functions.RemoveItem('emptyvape', 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items["emptyvape"], "remove") + Player.Functions.RemoveItem('vapejuice', 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items["vapejuice"], "remove") + Player.Functions.AddItem('vape', 1, true, info) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items["vape"], "add") + end + end +end) \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/bug_report.md b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..62f702f --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve or fix something +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. A stranger to qbcore should be able to read your bug report and understand how to reproduce it themselves and understand how the feature should work normally. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Use this item '....' (item's name from shared.lua if applicable) +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Questions (please complete the following information):** + - When you last updated: [e.g. last week] + - Are you using custom resource? which ones? [e.g. zdiscord, qb-target] + - Have you renamed `qb-` to something custom? [e.g. yes/no] + +**Additional context** +Add any other context about the problem here. diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/feature-request.md b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..9e9bf3e --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: Suggest an idea for QBCore +title: "[SUGGESTION]" +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. + +**Describe the feature you'd like** +A clear and concise description of what you want to happen. and with as much detail as possible how it would function in your opinion. Please try to keep it unique. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered for people to have in mind just in case the main idea isn't liked but a derivative is. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/auto_assign.yml b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/auto_assign.yml new file mode 100644 index 0000000..2a80921 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/auto_assign.yml @@ -0,0 +1,17 @@ +# Set to true to add reviewers to pull requests +addReviewers: true + +# Set to true to add assignees to pull requests +addAssignees: author + +# A list of reviewers to be added to pull requests (GitHub user name) +reviewers: + - /maintenance + +# A list of keywords to be skipped the process that add reviewers if pull requests include it +skipKeywords: + - wip + +# A number of reviewers added to the pull request +# Set 0 to add all the reviewers (default: 0) +numberOfReviewers: 0 \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/contributing.md b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/contributing.md new file mode 100644 index 0000000..21fb806 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/contributing.md @@ -0,0 +1,201 @@ +# Contributing to QBCore + +First of all, thank you for taking the time to contribute! + +These guidelines will help you help us in the best way possible regardless of your skill level. We ask that you try to read everything related to the way you'd like to contribute and try and use your best judgement for anything not covered. + +### Table of Contents + +[Code of Conduct](#code-of-conduct) + +[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) + +[How Can I Contribute?](#how-can-i-contribute) + * [Reporting Bugs](#reporting-bugs) + * [Suggesting Features / Enhancements](#suggesting-features--enhancements) + * [Your First Code Contribution](#your-first-code-contribution) + * [Pull Requests](#pull-requests) + +[Styleguides](#styleguides) + * [Git Commit Messages](#git-commit-messages) + * [Lua Styleguide](#lua-styleguide) + * [JavaScript Styleguide](#javascript-styleguide) + + + +## Code of Conduct + +- Refrain from using languages other than English. +- Refrain from discussing any politically charged or inflammatory topics. +- Uphold mature conversations and respect each other; excessive profanity, hate speech or any kind of harassment will not be tolerated. +- No advertising of any kind. +- Follow these guidelines. +- Do not mention members of github unless a question is directed at them and can't be answered by anyone else. +- Do not mention any of the development team for any reason. We will read things as we get to them. + +## I don't want to read this whole thing I just have a question!!! + +> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below. + +* [QBCore Website](https://qbcore.org) +* [QBCore Discord](https://discord.gg/qbcore) +* [FiveM Discord - #qbcore channel](https://discord.gg/fivem) + + + + + + + + + + +## How Can I Contribute? + +### Reporting Bugs + +The easiest way to contribute for most people is just to report bugs you find cause if nobody reports it there's a chance we'll never know it exists and then we'll never fix it. + +Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out the bug-report template with the information it asks for helps us resolve issues faster. + +> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. + +#### Before Submitting A Bug Report + +* **Check the docs** There's a chance what you see as a bug might just work differently than you expect and if you think it could work better consider a feature enhancement report instead. +* **Search the [discord](https://discord.gg/qbcore)** to see if anyone else has run into the issue and see if it was solved through user error or code changes. (if the code change isn't pending a PR and you know what you're doing consider submitting one following [Pull Requests](#pull-requests) ) +* **Determine which resource the problem should be reported in**. If the bug is related to the inventory for example report this bug under qb-inventory rather than under qb-core or some other resource. +* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aqbcore-framework)** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Bug Report? + +Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined which resource your bug is related to, create an issue on that repository and provide the following information by filling in bug-report template. + +Explain the problem and include additional details to help maintainers reproduce the problem: + +* **Use a clear and descriptive title** for the issue to identify the problem. +* **Describe the exact steps which reproduce the problem** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. If something happened with only a specific group or single item but not others, specify that. +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +* **Explain which behavior you expected to see instead and why.** +* **Include screenshots** which show the specific bug in action or before and after. +* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. + +Provide more context by answering these questions if possible: + +* **Did the problem start happening recently** (e.g. after updating to a new version of QBCore?) or was this always a problem? +* If the problem started happening recently, **can you reproduce the problem in an older version of QBCore?** What's the most recent commit in which the problem doesn't happen? +* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. + +Include details about your setup: + +* **When was your QBCore last updated?** +* **What OS is the server running on**? +* **Which *extra* resources do you have installed?** + + +--- + + +### Suggesting Features / Enhancements + +This section guides you through submitting an enhancement suggestion for QBCore, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion. + +Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in feature request template, including the steps that you imagine you would take if the feature you're requesting existed. + +#### Before Submitting An Enhancement Suggestion + +* **Make sure it doesn't already exist.** Sounds silly, but there's a lot of features built in to qbcore that people don't realize so take a look through the docs and stuff to make sure it's not already there. +* **Check if there's already PR which provides that enhancement.** +* **Determine which resource the enhancement should be suggested in.** if it fits with another resource suggest it in that resource. if it would be it's own resource suggest it in the main qb-core repository. +* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aqbcore-framework)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined which resource your enhancement suggestion is related to, create an issue on that repository and provide the following information: + +* **Use a clear and descriptive title** for the issue to identify the suggestion. +* **Provide a step-by-step description of the suggested enhancement** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of QBCore which the suggestion is related to. +* **Explain why this enhancement would be useful.** +* **Be creative and unique.** Stealing ideas from popular servers 1:1 detail isn't going to get accepted. + + +--- + + + +### Your First Code Contribution + +Unsure where to begin contributing to QBCore? You can start by looking through these `beginner` and `help-wanted` issues. + + + +--- + + +### Pull Requests + +The process described here has several goals: + +- Maintain QBCore's quality. +- Fix problems that are important to users. +- Engage the community in working toward the best possible QBCore. +- Enable a sustainable system for QBCore's maintainers to review contributions. + +Please follow these steps to have your contribution considered by the maintainers: + +1. Follow all instructions in The Pull Request template. +2. Follow the [styleguides](#styleguides). +3. Await review by the reviewer(s). + +While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted. + + +--- + +## Styleguides + +### Git Commit Messages + +* Limit the first line to 72 characters or less. +* Reference issues and pull requests liberally after the first line. +* Consider starting the commit message with an applicable emoji: + * :art: `:art:` when improving the format/structure of the code + * :racehorse: `:racehorse:` when improving performance + * :memo: `:memo:` when writing docs + * :bug: `:bug:` when fixing a bug + * :fire: `:fire:` when removing code or files + * :white_check_mark: `:white_check_mark:` when adding tests + * :lock: `:lock:` when dealing with security + * :arrow_up: `:arrow_up:` when upgrading dependencies + * :arrow_down: `:arrow_down:` when downgrading dependencies + * :shirt: `:shirt:` when removing linter warnings + +### Lua Styleguide + +All lua code should be done using all the best practices of proper lua using the easiest to read yet fastest/most optimized methods of execution. + +- Use 4 Space indentation +- Aim for lua 5.4 (include `lua54 'yes'` in the fxmanifest.lua) +- Use `PlayerPedId()` instead of `GetPlayerPed(-1)` +- Use `#(vector3 - vector3)` instead of `GetDistanceBetweenCoords()` +- Don't create unnecessary threads. always try to find a better method of triggering events +- Don't repeat yourself.. if you're using the same operations in many different places convert them into a function with flexible variables +- For distance checking loops set longer waits if you're outside of a range +- Job specific loops should only run for players with that job, don't waste cycles +- When possible don't trust the client, esspecially with transactions +- Balance security and optimizations +- [Consider this Lua Performance guide](https://springrts.com/wiki/Lua_Performance) +- Use local varriables everywhere possible +- Make use of config options where it makes sense making features optional or customizable +- Instead of `table.insert(myTable, "Value")` use `myTable[#myTable + 1] = "Value"` +- Instead of `table.insert(ages, "bob", 30)` use `ages["bob"] = 30` + + +### JavaScript Styleguide + +- Use 4 Space indentation +- Don't repeat yourself.. if you're using the same operations in many different places convert them into a function with flexible variables. diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/pull_request_template.md b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/pull_request_template.md new file mode 100644 index 0000000..000f0f9 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/pull_request_template.md @@ -0,0 +1,10 @@ +**Describe Pull request** +First, make sure you've read and are following the contribution guidelines and style guide and your code reflects that. +Write up a clear and concise description of what your pull request adds or fixes and if it's an added feature explain why you think it should be included in the core. + +If your PR is to fix an issue mention that issue here + +**Questions (please complete the following information):** +- Have you personally loaded this code into an updated qbcore project and checked all it's functionality? [yes/no] (Be honest) +- Does your code fit the style guidelines? [yes/no] +- Does your PR fit the contribution guidelines? [yes/no] diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/workflows/lint.yml b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/workflows/lint.yml new file mode 100644 index 0000000..fb74fd6 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint +on: [push, pull_request_target] +jobs: + lint: + name: Lint Resource + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Lint + uses: iLLeniumStudios/fivem-lua-lint-action@v2 + with: + capture: "junit.xml" + args: "-t --formatter JUnit" + extra_libs: mysql+polyzone+qblocales + - name: Generate Lint Report + if: always() + uses: mikepenz/action-junit-report@v3 + with: + report_paths: "**/junit.xml" + check_name: Linting Report + fail_on_failure: false \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/LICENSE b/resources/[qb]/[qb_shops]/qb-vehiclesales/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/README.md b/resources/[qb]/[qb_shops]/qb-vehiclesales/README.md new file mode 100644 index 0000000..3a514e1 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/README.md @@ -0,0 +1,347 @@ +# qb-vehiclesales +Used Car Sale for QB-Core Framework :blue_car: + +# License + + QBCore Framework + Copyright (C) 2021 Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + + +## Dependencies +- [qb-core](https://github.com/qbcore-framework/qb-core) +- [qb-garages](https://github.com/qbcore-framework/qb-garages) - Vehicle ownership +- [qb-phone](https://github.com/qbcore-framework/qb-phone) - For the e-mail +- [qb-logs](https://github.com/qbcore-framework/qb-logs) - Keep event logs + +## Screenshots +![Put Vehicle On Sale](https://imgur.com/bzE9e3o.png) +![Vehicle Sale Contract](https://imgur.com/A1ARcFV.png) +![Sell Vehicle To Dealer](https://imgur.com/zpEeBwk.png) +![Vehicle Sold Mail](https://imgur.com/vvz2UM3.png) +![Buy Vehicle](https://imgur.com/BEf5nDu.png) +![Vehicle Actions](https://imgur.com/HMuXtBd.png) + +## Features +- Ability to put your vehicle on sale for other players to buy +- Ability to take your vehicle back if it is not sold yet +- Ability to sell your vehicle to the dealer for a fixed amount + +## Installation +### Manual +- Download the script and put it in the `[qb]` directory. +- Import `qb-vehiclesales.sql` in your database +- Add the following code to your server.cfg/resouces.cfg +``` +ensure qb-core +ensure qb-garages +ensure qb-phone +ensure qb-logs +ensure qb-vehiclesales +``` + +## Configuration +- To adjust tax, go to qb-vehiclesales\server\main.lua row 85 and change "77" to your liking +``` +Config = Config or {} + +Config.SellVehicle = { -- Put Vehicle On Sale Marker + ["x"] = 1235.43, + ["y"] = 2730.95, + ["z"] = 37.91, +} + +Config.SellVehicleBack = { -- Sell Vehicle To Dealer Marker + ["x"] = 1235.1, + ["y"] = 2740.7, + ["z"] = 37.68, +} + +Config.BuyVehicle = { -- Location Bought Vehicle Will Be Spawned + ["x"] = 1213.31, + ["y"] = 2735.4, + ["z"] = 38.27, + ["h"] = 182.5 + } + +Config.OccasionSlots = { -- Vehicle Display Places + { + ["x"] = 1237.07, + ["y"] = 2699.0, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1232.98, + ["y"] = 2698.92, + ["z"] = 38.27, + ["h"] = 2.5 + }, + + { + ["x"] = 1228.9, + ["y"] = 2698.78, + ["z"] = 38.27, + ["h"] = 3.5 + }, + + { + ["x"] = 1224.9, + ["y"] = 2698.51, + ["z"] = 38.27, + ["h"] = 2.5 + }, + + { + ["x"] = 1220.93, + ["y"] = 2698.28, + ["z"] = 38.27, + ["h"] = 2.5 + }, + + + { + ["x"] = 1216.97, + ["y"] = 2698.05, + ["z"] = 38.27, + ["h"] = 0.5 + }, + + { + ["x"] = 1216.67, + ["y"] = 2709.21, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1220.67, + ["y"] = 2709.26, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1224.53, + ["y"] = 2709.27, + ["z"] = 38.27, + ["h"] = 2.5 + }, + + { + ["x"] = 1228.52, + ["y"] = 2709.42, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1232.53, + ["y"] = 2709.49, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1236.71, + ["y"] = 2709.51, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1216.41, + ["y"] = 2717.99, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1220.39, + ["y"] = 2718.0, + ["z"] = 38.27, + ["h"] = 0.5 + }, + + { + ["x"] = 1224.35, + ["y"] = 2718.07, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1228.41, + ["y"] = 2718.22, + ["z"] = 38.27, + ["h"] = 1.5 + }, + + { + ["x"] = 1249.63, + ["y"] = 2707.84, + ["z"] = 38.27, + ["h"] = 99.5 + }, + + { + ["x"] = 1248.92, + ["y"] = 2712.25, + ["z"] = 38.27, + ["h"] = 101.5 + }, + + { + ["x"] = 1247.3, + ["y"] = 2716.59, + ["z"] = 38.27, + ["h"] = 120.5 + }, + + { + ["x"] = 1244.09, + ["y"] = 2720.4, + ["z"] = 38.27, + ["h"] = 149.5 + }, + + { + ["x"] = 1239.93, + ["y"] = 2722.39, + ["z"] = 38.27, + ["h"] = 163.5 + }, + + { + ["x"] = 1248.28, + ["y"] = 2727.41, + ["z"] = 38.53, + ["h"] = 338.5 + }, + + + { + ["x"] = 1251.84, + ["y"] = 2725.65, + ["z"] = 38.52, + ["h"] = 331.5 + }, + + + { + ["x"] = 1255.19, + ["y"] = 2723.21, + ["z"] = 38.44, + ["h"] = 309.5 + }, + + + { + ["x"] = 1257.28, + ["y"] = 2719.77, + ["z"] = 38.49, + ["h"] = 296.5 + }, + + + { + ["x"] = 1258.43, + ["y"] = 2716.2, + ["z"] = 38.46, + ["h"] = 285.5 + }, + + + { + ["x"] = 1258.92, + ["y"] = 2712.28, + ["z"] = 38.37, + ["h"] = 270.5 + }, + + + { + ["x"] = 1258.9, + ["y"] = 2708.3, + ["z"] = 38.21, + ["h"] = 269.5 + }, + + + { + ["x"] = 1258.87, + ["y"] = 2704.21, + ["z"] = 38.05, + ["h"] = 271.5 + }, + + + { + ["x"] = 1269.11, + ["y"] = 2694.67, + ["z"] = 37.85, + ["h"] = 184.5 + }, + + + { + ["x"] = 1273.53, + ["y"] = 2694.98, + ["z"] = 37.87, + ["h"] = 184.5 + }, + + + { + ["x"] = 1277.56, + ["y"] = 2695.43, + ["z"] = 37.87, + ["h"] = 183.5 + }, + + + { + ["x"] = 1281.53, + ["y"] = 2695.67, + ["z"] = 37.88, + ["h"] = 186.5 + }, + + + { + ["x"] = 1285.51, + ["y"] = 2696.02, + ["z"] = 37.88, + ["h"] = 185.5 + }, + + + { + ["x"] = 1289.74, + ["y"] = 2696.27, + ["z"] = 37.88, + ["h"] = 182.5 + }, + + + { + ["x"] = 1293.75, + ["y"] = 2696.47, + ["z"] = 37.86, + ["h"] = 184.5 + }, +} +``` diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/client/main.lua b/resources/[qb]/[qb_shops]/qb-vehiclesales/client/main.lua new file mode 100644 index 0000000..ed36e6e --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/client/main.lua @@ -0,0 +1,478 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local Zone = nil +local TextShown = false +local AcitveZone = {} +local CurrentVehicle = {} +local SpawnZone = {} +local EntityZones = {} +local occasionVehicles = {} + +-- Functions + +local function spawnOccasionsVehicles(vehicles) + if Zone then + local oSlot = Config.Zones[Zone].VehicleSpots + if not occasionVehicles[Zone] then occasionVehicles[Zone] = {} end + if vehicles then + for i = 1, #vehicles, 1 do + local model = GetHashKey(vehicles[i].model) + RequestModel(model) + while not HasModelLoaded(model) do + Wait(0) + end + occasionVehicles[Zone][i] = { + car = CreateVehicle(model, oSlot[i].x, oSlot[i].y, oSlot[i].z, false, false), + loc = vector3(oSlot[i].x, oSlot[i].y, oSlot[i].z), + price = vehicles[i].price, + owner = vehicles[i].seller, + model = vehicles[i].model, + plate = vehicles[i].plate, + oid = vehicles[i].occasionid, + desc = vehicles[i].description, + mods = vehicles[i].mods + } + + QBCore.Functions.SetVehicleProperties(occasionVehicles[Zone][i].car, json.decode(occasionVehicles[Zone][i].mods)) + + SetModelAsNoLongerNeeded(model) + SetVehicleOnGroundProperly(occasionVehicles[Zone][i].car) + SetEntityInvincible(occasionVehicles[Zone][i].car,true) + SetEntityHeading(occasionVehicles[Zone][i].car, oSlot[i].w) + SetVehicleDoorsLocked(occasionVehicles[Zone][i].car, 3) + SetVehicleNumberPlateText(occasionVehicles[Zone][i].car, occasionVehicles[Zone][i].oid) + FreezeEntityPosition(occasionVehicles[Zone][i].car,true) + if Config.UseTarget then + if not EntityZones then EntityZones = {} end + EntityZones[i] = exports['qb-target']:AddTargetEntity(occasionVehicles[Zone][i].car, { + options = { + { + type = "client", + event = "qb-vehiclesales:client:OpenContract", + icon = "fas fa-car", + label = Lang:t("menu.view_contract"), + Contract = i + } + }, + distance = 3.0 + }) + end + end + end + end +end + +local function despawnOccasionsVehicles() + if not Zone then return end + local oSlot = Config.Zones[Zone].VehicleSpots + for i = 1, #oSlot, 1 do + local loc = oSlot[i] + local oldVehicle = GetClosestVehicle(loc.x, loc.y, loc.z, 1.3, 0, 70) + + if oldVehicle then + QBCore.Functions.DeleteVehicle(oldVehicle) + end + + if EntityZones[i] and Config.UseTarget then + exports['qb-target']:RemoveZone(EntityZones[i]) + end + end + EntityZones = {} +end + +local function openSellContract(bool) + local pData = QBCore.Functions.GetPlayerData() + + SetNuiFocus(bool, bool) + SendNUIMessage({ + action = "sellVehicle", + showTakeBackOption = false, + bizName = Config.Zones[Zone].BusinessName, + sellerData = { + firstname = pData.charinfo.firstname, + lastname = pData.charinfo.lastname, + account = pData.charinfo.account, + phone = pData.charinfo.phone + }, + plate = QBCore.Functions.GetPlate(GetVehiclePedIsUsing(PlayerPedId())) + }) +end + +local function openBuyContract(sellerData, vehicleData) + local pData = QBCore.Functions.GetPlayerData() + SetNuiFocus(true, true) + SendNUIMessage({ + action = "buyVehicle", + showTakeBackOption = sellerData.charinfo.firstname == pData.charinfo.firstname and sellerData.charinfo.lastname == pData.charinfo.lastname, + bizName = Config.Zones[Zone].BusinessName, + sellerData = { + firstname = sellerData.charinfo.firstname, + lastname = sellerData.charinfo.lastname, + account = sellerData.charinfo.account, + phone = sellerData.charinfo.phone + }, + vehicleData = { + desc = vehicleData.desc, + price = vehicleData.price + }, + plate = vehicleData.plate + }) +end + +local function sellVehicleWait(price) + DoScreenFadeOut(250) + Wait(250) + QBCore.Functions.DeleteVehicle(GetVehiclePedIsIn(PlayerPedId())) + Wait(1500) + DoScreenFadeIn(250) + QBCore.Functions.Notify(Lang:t('success.car_up_for_sale', { value = price }), 'success') + PlaySound(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", 0, 0, 1) +end + +local function SellData(data, model) + QBCore.Functions.TriggerCallback("qb-vehiclesales:server:CheckModelName",function(DataReturning) + local vehicleData = {} + vehicleData.ent = GetVehiclePedIsUsing(PlayerPedId()) + vehicleData.model = DataReturning + vehicleData.plate = model + vehicleData.mods = QBCore.Functions.GetVehicleProperties(vehicleData.ent) + vehicleData.desc = data.desc + TriggerServerEvent('qb-occasions:server:sellVehicle', data.price, vehicleData) + sellVehicleWait(data.price) + end, model) +end + +local listen = false +local function Listen4Control(spot) -- Uses this to listen for controls to open various menus. + listen = true + CreateThread(function() + while listen do + if IsControlJustReleased(0, 38) then -- E + if spot then + local data = {Contract = spot} + TriggerEvent('qb-vehiclesales:client:OpenContract', data) + else + if IsPedInAnyVehicle(PlayerPedId(), false) then + listen = false + TriggerEvent('qb-occasions:client:MainMenu') + --TriggerEvent('qb-vehiclesales:client:SellVehicle') + else + QBCore.Functions.Notify(Lang:t("error.not_in_veh"), "error", 4500) + end + end + end + Wait(0) + end + end) +end + +---- ** Main Zone Functions ** ---- + +local function CreateZones() + for k, v in pairs(Config.Zones) do + local SellSpot = PolyZone:Create(v.PolyZone, { + name = k, + minZ = v.MinZ, + maxZ = v.MaxZ, + debugPoly = false + }) + + SellSpot:onPlayerInOut(function(isPointInside) + if isPointInside and Zone ~= k then + Zone = k + QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) + despawnOccasionsVehicles() + spawnOccasionsVehicles(vehicles) + end) + else + despawnOccasionsVehicles() + Zone = nil + end + end) + AcitveZone[k] = SellSpot + end +end + +local function DeleteZones() + for k in pairs(AcitveZone) do + AcitveZone[k]:destroy() + end + AcitveZone = {} +end + +local function IsCarSpawned(Car) + local bool = false + + if occasionVehicles then + for k in pairs(occasionVehicles[Zone]) do + if k == Car then + bool = true + break + end + end + end + return bool +end + +-- NUI Callbacks + +RegisterNUICallback('sellVehicle', function(data, cb) + local plate = QBCore.Functions.GetPlate(GetVehiclePedIsUsing(PlayerPedId())) --Getting the plate and sending to the function + SellData(data,plate) + cb('ok') +end) + +RegisterNUICallback('close', function(_, cb) + SetNuiFocus(false, false) + cb('ok') +end) + +RegisterNUICallback('buyVehicle', function(_, cb) + TriggerServerEvent('qb-occasions:server:buyVehicle', CurrentVehicle) + cb('ok') +end) + +RegisterNUICallback('takeVehicleBack', function(_, cb) + TriggerServerEvent('qb-occasions:server:ReturnVehicle', CurrentVehicle) + cb('ok') +end) + +-- Events + +RegisterNetEvent('qb-occasions:client:BuyFinished', function(vehdata) + local vehmods = json.decode(vehdata.mods) + + DoScreenFadeOut(250) + Wait(500) + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleNumberPlateText(veh, vehdata.plate) + SetEntityHeading(veh, Config.Zones[Zone].BuyVehicle.w) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + SetVehicleFuelLevel(veh, 100) + QBCore.Functions.Notify(Lang:t('success.vehicle_bought'), "success", 2500) + TriggerEvent("vehiclekeys:client:SetOwner", vehdata.plate) + SetVehicleEngineOn(veh, true, true) + Wait(500) + QBCore.Functions.SetVehicleProperties(veh, vehmods) + end, vehdata.model, Config.Zones[Zone].BuyVehicle, true) + Wait(500) + DoScreenFadeIn(250) + CurrentVehicle = {} +end) + +RegisterNetEvent('qb-occasions:client:SellBackCar', function() + local ped = PlayerPedId() + if IsPedInAnyVehicle(ped, false) then + local vehicleData = {} + local vehicle = GetVehiclePedIsIn(ped, false) + vehicleData.model = GetEntityModel(vehicle) + vehicleData.plate = GetVehicleNumberPlateText(vehicle) + QBCore.Functions.TriggerCallback('qb-garage:server:checkVehicleOwner', function(owned, balance) + if owned then + TriggerServerEvent('qb-occasions:server:sellVehicleBack', vehicleData) + QBCore.Functions.DeleteVehicle(vehicle) + else + QBCore.Functions.Notify(Lang:t('error.not_your_vehicle'), 'error', 3500) + end + end, vehicleData.plate) + else + QBCore.Functions.Notify(Lang:t("error.not_in_veh"), "error", 4500) + end +end) + +RegisterNetEvent('qb-occasions:client:ReturnOwnedVehicle', function(vehdata) + local vehmods = json.decode(vehdata.mods) + DoScreenFadeOut(250) + Wait(500) + QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId) + local veh = NetToVeh(netId) + SetVehicleNumberPlateText(veh, vehdata.plate) + SetEntityHeading(veh, Config.Zones[Zone].BuyVehicle.w) + TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) + SetVehicleFuelLevel(veh, 100) + QBCore.Functions.Notify(Lang:t('info.vehicle_returned')) + TriggerEvent("vehiclekeys:client:SetOwner", vehdata.plate) + SetVehicleEngineOn(veh, true, true) + Wait(500) + QBCore.Functions.SetVehicleProperties(veh, vehmods) + end, vehdata.model, Config.Zones[Zone].BuyVehicle, true) + Wait(500) + DoScreenFadeIn(250) + CurrentVehicle = {} +end) + +RegisterNetEvent('qb-occasion:client:refreshVehicles', function() + if Zone then + QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) + despawnOccasionsVehicles() + spawnOccasionsVehicles(vehicles) + end) + end +end) + +RegisterNetEvent('qb-vehiclesales:client:SellVehicle', function() + local VehiclePlate = QBCore.Functions.GetPlate(GetVehiclePedIsIn(PlayerPedId())) + QBCore.Functions.TriggerCallback('qb-garage:server:checkVehicleOwner', function(owned, balance) + if owned then + -- if balance < 1 then + QBCore.Functions.TriggerCallback('qb-occasions:server:getVehicles', function(vehicles) + if vehicles == nil or #vehicles < #Config.Zones[Zone].VehicleSpots then + openSellContract(true) + else + QBCore.Functions.Notify(Lang:t('error.no_space_on_lot'), 'error', 3500) + end + end) + -- else + -- QBCore.Functions.Notify(Lang:t('error.finish_payments'), 'error', 3500) + -- end + else + QBCore.Functions.Notify(Lang:t('error.not_your_vehicle'), 'error', 3500) + end + end, VehiclePlate) +end) + +RegisterNetEvent('qb-vehiclesales:client:OpenContract', function(data) + CurrentVehicle = occasionVehicles[Zone][data.Contract] + if CurrentVehicle then + QBCore.Functions.TriggerCallback('qb-occasions:server:getSellerInformation', function(info) + if info then + info.charinfo = json.decode(info.charinfo) + else + info = {} + info.charinfo = { + firstname = Lang:t('charinfo.firstname'), + lastname = Lang:t('charinfo.lastname'), + account = Lang:t('charinfo.account'), + phone = Lang:t('charinfo.phone') + } + end + + openBuyContract(info, CurrentVehicle) + end, CurrentVehicle.owner) + else + QBCore.Functions.Notify(Lang:t("error.not_for_sale"), 'error', 7500) + end +end) + +RegisterNetEvent('qb-occasions:client:MainMenu', function() + local MainMenu = { + { + isMenuHeader = true, + header = Config.Zones[Zone].BusinessName + }, + { + header = Lang:t("menu.sell_vehicle"), + txt = Lang:t("menu.sell_vehicle_help"), + params = { + event = 'qb-vehiclesales:client:SellVehicle', + } + }, + { + header = Lang:t("menu.sell_back"), + txt = Lang:t("menu.sell_back_help"), + params = { + event = 'qb-occasions:client:SellBackCar', + } + } + } + + exports['qb-menu']:openMenu(MainMenu) +end) + +-- Threads + +CreateThread(function() + RequestStreamedTextureDict("shops", 1) + while not HasStreamedTextureDictLoaded("shops") do + Wait(0) + end + for _, cars in pairs(Config.Zones) do + local OccasionBlip = AddBlipForCoord(cars.SellVehicle.x, cars.SellVehicle.y, cars.SellVehicle.z) + SetBlipSprite (OccasionBlip, 326) + SetBlipDisplay(OccasionBlip, 4) + SetBlipScale (OccasionBlip, 0.75) + SetBlipAsShortRange(OccasionBlip, true) + SetBlipColour(OccasionBlip, 3) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(Lang:t('info.used_vehicle_lot')) + EndTextCommandSetBlipName(OccasionBlip) + + exports['blip_info']:SetBlipInfoTitle(OccasionBlip, Lang:t('info.used_vehicle_lot'), 0) + exports['blip_info']:SetBlipInfoImage(OccasionBlip, "shops", "usedcars") + exports['blip_info']:AddBlipInfoName(OccasionBlip, "Ejet af", "Larry") + exports['blip_info']:AddBlipInfoName(OccasionBlip, "Type", "Forhandler") + exports['blip_info']:AddBlipInfoHeader(OccasionBlip, "") + exports['blip_info']:AddBlipInfoHeader(OccasionBlip, "") + exports['blip_info']:AddBlipInfoText(OccasionBlip, "Ikke tilfreds med din bil mere? Du kan sælge den her og tjene lidt penge") + end +end) + +CreateThread(function() + for k, cars in pairs(Config.Zones) do + SpawnZone[k] = CircleZone:Create(vector3(cars.SellVehicle.x, cars.SellVehicle.y, cars.SellVehicle.z), 3.0, { + name="OCSell"..k, + debugPoly = false, + }) + + SpawnZone[k]:onPlayerInOut(function(isPointInside) + if isPointInside and IsPedInAnyVehicle(PlayerPedId(), false) then + exports['qb-core']:DrawText(Lang:t("menu.interaction"), 'top') + TextShown = true + Listen4Control() + else + listen = false + if TextShown then + TextShown = false + exports['qb-core']:HideText() + end + end + end) + if not Config.UseTarget then + for k2, v in pairs(Config.Zones[k].VehicleSpots) do + local VehicleZones = BoxZone:Create(vector3(v.x, v.y, v.z), 4.3, 3.6, { + name="VehicleSpot"..k..k2, + debugPoly = false, + minZ = v.z-2, + maxZ = v.z+2, + }) + + VehicleZones:onPlayerInOut(function(isPointInside) + if isPointInside and IsCarSpawned(k2) then + exports['qb-core']:DrawText(Lang:t("menu.view_contract_int"), 'top') + TextShown = true + Listen4Control(k2) + else + listen = false + if TextShown then + TextShown = false + exports['qb-core']:HideText() + end + end + end) + end + end + end +end) + +---- ** Mostly just to ensure you can restart resources live without issues, also improves the code slightly. ** ---- + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + CreateZones() +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + DeleteZones() +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() == resourceName then + CreateZones() + end +end) + +AddEventHandler('onResourceStop', function(resourceName) + if GetCurrentResourceName() == resourceName then + DeleteZones() + despawnOccasionsVehicles() + end +end) diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/config.lua b/resources/[qb]/[qb_shops]/qb-vehiclesales/config.lua new file mode 100644 index 0000000..ac9cce3 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/config.lua @@ -0,0 +1,48 @@ +Config = Config or {} + +Config.UseTarget = GetConvar('UseTarget', 'false') == 'true' + +Config.Zones = { + ["SandyOccasions"] = { + BusinessName = "Brugtvogns handler - Larry's Biler", + SellVehicle = vector4(1235.61, 2733.44, 37.4, 0.42), + BuyVehicle = vector4(1213.31, 2735.4, 38.27, 182.5), + + PolyZone = { + vector2(1338.3748779297, 2645.0153808594), + vector2(1098.9381103516, 2621.7487792969), + vector2(1117.9478759766, 2822.0729980469), + vector2(1370.98828125, 2859.197265625) + }, + MinZ = 36.0, + MaxZ = 64.0, + + VehicleSpots = { + vector4(1237.07, 2699, 38.27, 1.5), + vector4(1232.98, 2698.92, 38.27, 2.5), + vector4(1228.9, 2698.78, 38.27, 3.5), + vector4(1224.9, 2698.51, 38.27, 2.5), + vector4(1220.93, 2698.28, 38.27, 2.5), + vector4(1216.97, 2698.05, 38.27, 0.5), + vector4(1216.67, 2709.21, 38.27, 1.5), + vector4(1220.67, 2709.26, 38.27, 1.5), + vector4(1224.53, 2709.27, 38.27, 2.5), + vector4(1228.52, 2709.42, 38.27, 1.5), + vector4(1232.53, 2709.49, 38.27, 1.5), + vector4(1236.71, 2709.51, 38.27, 1.6), + vector4(1216.41, 2717.99, 38.27, 1.5), + vector4(1220.39, 2718, 38.27, 0.5), + vector4(1224.35, 2718.07, 38.27, 1.5), + vector4(1228.41, 2718.22, 38.27, 1.5), + vector4(1249.63, 2707.84, 38.27, 99.5), + vector4(1248.92, 2712.25, 38.27, 101.5), + vector4(1247.3, 2716.59, 38.27, 120.5), + vector4(1244.09, 2720.4, 38.27, 149.5), + vector4(1239.93, 2722.39, 38.27, 163.5), + vector4(1248.28, 2727.41, 38.53, 338.5), + vector4(1251.84, 2725.65, 38.52, 331.5), + vector4(1255.19, 2723.21, 38.44, 309.5), + vector4(1257.28, 2719.77, 38.49, 296.5), + } + } +} diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/fxmanifest.lua b/resources/[qb]/[qb_shops]/qb-vehiclesales/fxmanifest.lua new file mode 100644 index 0000000..07488c2 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/fxmanifest.lua @@ -0,0 +1,37 @@ +fx_version 'cerulean' +game 'gta5' + +description 'QB-VehicleSales' +version '1.2.0' + +ui_page 'html/ui.html' + +shared_scripts { + 'config.lua', + '@qb-core/shared/locale.lua', + 'locales/da.lua', + 'locales/*.lua' +} + +client_scripts { + '@PolyZone/client.lua', + '@PolyZone/BoxZone.lua', + '@PolyZone/EntityZone.lua', + '@PolyZone/CircleZone.lua', + '@PolyZone/ComboZone.lua', + 'client/main.lua' +} +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server/main.lua' +} + +files { + 'html/logo.svg', + 'html/ui.css', + 'html/ui.html', + 'html/vue.min.js', + 'html/ui.js', +} + +lua54 'yes' \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/html/logo.svg b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/logo.svg new file mode 100644 index 0000000..059a278 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + RV ASSOCIATION + LOS SANTOS + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.css b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.css new file mode 100644 index 0000000..101f46c --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.css @@ -0,0 +1,339 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap'); +@import url('https://fonts.googleapis.com/css?family=Bebas Neue'); +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap'); + +body { + overflow: hidden; + display: none; +} + +.container { + overflow: hidden; +} + +.centred { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + +} + +.centred-h { + position: fixed; + left: 28%; + transform: translate(-50%, 0%); +} + +#sell-contract { + max-width: 700px; + max-height: 70vh; + width: 30vw; + height: 75vh; + background-color: white; + padding: 10px; + background: rgb(23 23 23); + border-radius: 8px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; +} + +#buy-contract { + position: absolute; + width: 165vh; + margin: 0 auto; + left: 0; + right: 0; + user-select: none; +} + +#buy-vehicle-desc { + position: absolute; + left: 66.8vh; + bottom: 48vh; + font-family: 'Poppins'; + font-size: 13px; + width: 45vh; + overflow: hidden; + word-wrap: break-word; +} + +.vehicle-description:hover { + color: #ffffff; +} + +.vehicle-description:focus { + color: #ffffff; +} + +.vehicle-description::placeholder { + text-align: left; + color:white +} + +#sell-vehicle { + width: 100px; + height: 35px; + background: rgb(30 30 30); + box-shadow: -0.072rem 0rem 0.6rem 0.05rem #000000; + border-radius: 25px 0px 0px 25px; + margin-top: 100px; + margin-left: 452px; + left: 0; + right: 0; + transition: all 0.1s ease-in-out; +} + +#sell-vehicle:hover { + background: #dc143c; + transition: all 0.1s ease-in-out; +} + +#sell-vehicle > p { + text-align: center; + line-height: 3.5vh; + color: white; + font-size: 20px; + font-family: "Poppins", sans-serif !important; + font-weight: 700; + text-transform: uppercase; + cursor: pointer; +} + +input.vehicle-sell-price::placeholder { + color: white; + opacity: 1; + +} + +#buy-vehicle { + +width: 250px; + +height: 35px; + +background: rgb(30 30 30); + +box-shadow: -0.072rem 0rem 0.6rem 0.05rem #000000; + +border-radius: 25px; + +transition: all 0.1s ease-in-out; + +bottom: 50vh; + +margin:auto; + +user-select: none; +} + +#buy-vehicle-back { + width: 250px; + height: 35px; + background: rgb(30 30 30); + box-shadow: -0.072rem 0rem 0.6rem 0.05rem #000000; + border-radius: 25px; + transition: all 0.1s ease-in-out; + bottom: 88vh; + margin: 0 auto; + user-select: none; +} + +#buy-vehicle:hover { + border-radius: 25px; + background: #dc143c; + transition: all 0.1s ease-in-out; +} + + #buy-vehicle-back:hover { + border-radius: 25px; + background: #dc143c; + transition: all 0.1s ease-in-out; + +} + +#buy-vehicle > p { + text-align: center; + line-height: 3.5vh; + color: rgb(255, 255, 255); + font-size: 19px; + font-family: "Poppins", sans-serif !important; + text-transform: uppercase; + cursor: pointer; +} + +#buy-vehicle-back > p { + text-align: center; + line-height: 3.5vh; + color: rgb(255, 255, 255); + font-size: 19px; + font-family: "Poppins", sans-serif !important; + text-transform: uppercase; + cursor: pointer; +} + + +#form-header { + height: 120px; + border-bottom: solid; + border-color: #ffffffde; + border-width: 2px; + margin-bottom: 30px; + display: flex; + flex-direction: row; +} + +.v-centred-container { + position: relative; + +} + +.vertical-center { + margin: 0; + position: absolute; + top: 50%; + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} + +.logo { + width: 20%; + text-align: center; + padding-top: 5px; + padding-bottom: 10px; +} + +#biz-name { + width: 68%; + text-align: center; + font-family: 'Bebas Neue'; + font-size: 35px; + font-weight: bold; + color: #ffffff; + letter-spacing: 3.0px; +} + +#the-form { + margin-top: 45px; + width: 85%; + height: 72%; +} + +ul { + list-style-type: none; +} + +.errors { + font-family: 'Poppins'; + background: #f7a261; + width: 50%; + border-radius: 25px; + bottom: -10vh; + left:25vh; +} + +.form-entry { + margin-top: 60px; + height: 2%; +} + +.form-entry input { + width: 90.5%; + margin-top: 1px; + border-radius: 0.1px; + outline:none; + border-top: none; + border-left: none; + border-right: none; + border-bottom: solid rgb(255, 255, 255) 1.5px; +} + +.form-field { + font-family: 'Poppins'; + font-size: 16px; + padding-top: 3px; + border-top: solid; + color: rgb(170, 170, 170); + border-color: #d8d8d8b0; + border-width: 1px; +} + +.form-field-summary { + font-family: 'Poppins'; + font-size: 14px; + color: #ffffff; +} + +.vehicle-description { + outline: none; + background: none; + font-family: 'Poppins'; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + white-space: nowrap; + color: white +} + +.vehicle-sell-price { + font-size: 12px; + outline: none; + color: rgb(255, 255, 255); + background-color: #00000000; +} + +table { + font-size: 18px; + bottom: -500px; + font-family: 'Poppins'; + color: white; +} + +.pricing-table { + margin-bottom: 480px; + margin-left: -50px; + width: 50%; +} + + +.table-field-heading { + font-weight:500; +} + +#buy-price { + position: absolute; + left: 87vh; + bottom: 35.8vh; + font-family: 'Poppins'; + font-size: 12px; +} + +#buy-seller-name { + position: absolute; + left: 66.8vh; + top: 21.5vh; + font-family: 'Poppins'; + font-size: 14px; +} + +#buy-seller-banknr { + position: absolute; + left: 66.8vh; + top: 28vh; + font-family: 'Poppins'; + font-size: 14px; +} + +#buy-seller-telnr { + position: absolute; + left: 66.8vh; + top: 34.2vh; + font-family: 'Poppins'; + font-size: 14px; +} + +#buy-vehicle-plate { + position: absolute; + left: 66.8vh; + top: 40.5vh; + font-family: 'Poppins'; +} diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.html b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.html new file mode 100644 index 0000000..f1272df --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.html @@ -0,0 +1,89 @@ + + + + + + + + qb-vehiclesales + + +
    +
    +
    + +
    +
    {{ bizName }}
    +
    +
    + +
    +
    +
    {{ sellerName }}
    + (Navn på sælger) +
    +
    +
    {{ bankAccount }}
    + (Kontonummer) +
    +
    +
    {{ phoneNumber }}
    + (Telefon nummer) +
    +
    +
    {{ licensePlate }}
    + (Nummerplade) +
    +
    +
    + +
    + (Beskrivelse, maks 500 tegn.) +
    {{ vehicleDescription }}
    +
    + +
    + + + + + +
    Salgspris: + +
    Skat:{{ tax }},-
    Mosely's Cut:{{ mosleys }},-
    Total Yield:{{ total }},-
    +
    + +
    + + +
    Køretøjspris: {{ sellPrice }},-
    +
    + +

    Sælg

    +

    Køb

    +

    Tag tilbage

    + +
    +
      +
    • {{ error }}
    • +
    +
    +
    + +
    + +
    + + + + + diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.js b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.js new file mode 100644 index 0000000..e918137 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/ui.js @@ -0,0 +1,130 @@ +var app = new Vue({ + el: "#app", + data: { + mode: "", + bizName: "", + sellerName: "", + bankAccount: "", + phoneNumber: "", + licensePlate: "", + vehicleDescription: "", + sellPrice: "", + showTakeBackOption: false, + errors: [] + }, + methods: { + sell(sellPrice) { + this.errors = []; + if (this.sellPrice != "") { + if (!isNaN(sellPrice)) { + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + price: this.sellPrice, + desc: this.vehicleDescription + }) + }; + fetch("https://qb-vehiclesales/sellVehicle", requestOptions); + this.close(); + } else { + this.errors.push("Du må kun bruge tal i salgsprisen."); + } + } else { + this.errors.push("Du skal udfylde salgsprisen.") + } + }, + buy() { + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}) + }; + fetch("https://qb-vehiclesales/buyVehicle", requestOptions); + this.close(); + }, + takeBack() { + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}) + }; + fetch("https://qb-vehiclesales/takeVehicleBack", requestOptions); + this.close(); + }, + close() { + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}) + }; + fetch("https://qb-vehiclesales/close", requestOptions); + + this.resetForm(); + this.hideForm(); + + }, + resetForm() { + this.sellerName = ""; + this.bankAccount = ""; + this.phoneNumber = ""; + this.licensePlate = ""; + this.vehicleDescription = ""; + this.sellPrice = ""; + this.errors = []; + }, + hideForm() { + document.body.style.display = "none"; + } + + }, + computed: { + tax() { + return (this.sellPrice / 100 * 19).toFixed(0); + }, + mosleys() { + return (this.sellPrice / 100 * 4).toFixed(0); + }, + total() { + return (this.sellPrice / 100 * 77).toFixed(0); + } + } + +}); + +function setupForm(data) { + if(data.action === "sellVehicle" || data.action === "buyVehicle") { + document.body.style.display = "block"; + } + + app.mode = data.action; + + app.showTakeBackOption = data.showTakeBackOption; + + app.bizName = data.bizName; + + app.sellerName = data.sellerData.firstname + " " + data.sellerData.lastname; + app.bankAccount = data.sellerData.account; + app.phoneNumber = data.sellerData.phone; + app.licensePlate = data.plate; + + if (data.action === "buyVehicle") { + app.vehicleDescription = data.vehicleData.desc; + app.sellPrice = data.vehicleData.price; + } +} + +document.onreadystatechange = () => { + if (document.readyState === "complete") { + window.addEventListener("message", (event) => { + this.setupForm(event.data); + }); + } +}; + +/* Handle escape key press to close the menu */ +document.onkeyup = function (data) { + if (data.key != "Escape") return; + + app.close(); +}; diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/html/vue.min.js b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/vue.min.js new file mode 100644 index 0000000..d998ff7 --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/html/vue.min.js @@ -0,0 +1,6 @@ +/*! + * Vue.js v2.6.14 + * (c) 2014-2021 Evan You + * Released under the MIT License. + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Vue=t()}(this,function(){"use strict";var e=Object.freeze({});function t(e){return null==e}function n(e){return null!=e}function r(e){return!0===e}function i(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function o(e){return null!==e&&"object"==typeof e}var a=Object.prototype.toString;function s(e){return"[object Object]"===a.call(e)}function c(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function u(e){return n(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function l(e){return null==e?"":Array.isArray(e)||s(e)&&e.toString===a?JSON.stringify(e,null,2):String(e)}function f(e){var t=parseFloat(e);return isNaN(t)?e:t}function p(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}var m=Object.prototype.hasOwnProperty;function y(e,t){return m.call(e,t)}function g(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var _=/-(\w)/g,b=g(function(e){return e.replace(_,function(e,t){return t?t.toUpperCase():""})}),$=g(function(e){return e.charAt(0).toUpperCase()+e.slice(1)}),w=/\B([A-Z])/g,C=g(function(e){return e.replace(w,"-$1").toLowerCase()});var x=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function k(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function A(e,t){for(var n in t)e[n]=t[n];return e}function O(e){for(var t={},n=0;n0,Z=J&&J.indexOf("edge/")>0,G=(J&&J.indexOf("android"),J&&/iphone|ipad|ipod|ios/.test(J)||"ios"===K),X=(J&&/chrome\/\d+/.test(J),J&&/phantomjs/.test(J),J&&J.match(/firefox\/(\d+)/)),Y={}.watch,Q=!1;if(V)try{var ee={};Object.defineProperty(ee,"passive",{get:function(){Q=!0}}),window.addEventListener("test-passive",null,ee)}catch(e){}var te=function(){return void 0===B&&(B=!V&&!z&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),B},ne=V&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function re(e){return"function"==typeof e&&/native code/.test(e.toString())}var ie,oe="undefined"!=typeof Symbol&&re(Symbol)&&"undefined"!=typeof Reflect&&re(Reflect.ownKeys);ie="undefined"!=typeof Set&&re(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var ae=S,se=0,ce=function(){this.id=se++,this.subs=[]};ce.prototype.addSub=function(e){this.subs.push(e)},ce.prototype.removeSub=function(e){h(this.subs,e)},ce.prototype.depend=function(){ce.target&&ce.target.addDep(this)},ce.prototype.notify=function(){for(var e=this.subs.slice(),t=0,n=e.length;t-1)if(o&&!y(i,"default"))a=!1;else if(""===a||a===C(e)){var c=Re(String,i.type);(c<0||s0&&(ct((u=e(u,(a||"")+"_"+c))[0])&&ct(f)&&(s[l]=he(f.text+u[0].text),u.shift()),s.push.apply(s,u)):i(u)?ct(f)?s[l]=he(f.text+u):""!==u&&s.push(he(u)):ct(u)&&ct(f)?s[l]=he(f.text+u.text):(r(o._isVList)&&n(u.tag)&&t(u.key)&&n(a)&&(u.key="__vlist"+a+"_"+c+"__"),s.push(u)));return s}(e):void 0}function ct(e){return n(e)&&n(e.text)&&!1===e.isComment}function ut(e,t){if(e){for(var n=Object.create(null),r=oe?Reflect.ownKeys(e):Object.keys(e),i=0;i0,a=t?!!t.$stable:!o,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&r&&r!==e&&s===r.$key&&!o&&!r.$hasNormal)return r;for(var c in i={},t)t[c]&&"$"!==c[0]&&(i[c]=vt(n,c,t[c]))}else i={};for(var u in n)u in i||(i[u]=ht(n,u));return t&&Object.isExtensible(t)&&(t._normalized=i),R(i,"$stable",a),R(i,"$key",s),R(i,"$hasNormal",o),i}function vt(e,t,n){var r=function(){var e=arguments.length?n.apply(null,arguments):n({}),t=(e=e&&"object"==typeof e&&!Array.isArray(e)?[e]:st(e))&&e[0];return e&&(!t||1===e.length&&t.isComment&&!pt(t))?void 0:e};return n.proxy&&Object.defineProperty(e,t,{get:r,enumerable:!0,configurable:!0}),r}function ht(e,t){return function(){return e[t]}}function mt(e,t){var r,i,a,s,c;if(Array.isArray(e)||"string"==typeof e)for(r=new Array(e.length),i=0,a=e.length;idocument.createEvent("Event").timeStamp&&(cn=function(){return un.now()})}function ln(){var e,t;for(sn=cn(),on=!0,en.sort(function(e,t){return e.id-t.id}),an=0;anan&&en[n].id>e.id;)n--;en.splice(n+1,0,e)}else en.push(e);rn||(rn=!0,Qe(ln))}}(this)},pn.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||o(e)||this.deep){var t=this.value;if(this.value=e,this.user){var n='callback for watcher "'+this.expression+'"';Be(this.cb,this.vm,[e,t],this.vm,n)}else this.cb.call(this.vm,e,t)}}},pn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},pn.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},pn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||h(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var dn={enumerable:!0,configurable:!0,get:S,set:S};function vn(e,t,n){dn.get=function(){return this[t][n]},dn.set=function(e){this[t][n]=e},Object.defineProperty(e,n,dn)}function hn(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},r=e._props={},i=e.$options._propKeys=[];e.$parent&&$e(!1);var o=function(o){i.push(o);var a=Ie(o,t,n,e);xe(r,o,a),o in e||vn(e,"_props",o)};for(var a in t)o(a);$e(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]="function"!=typeof t[n]?S:x(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;s(t=e._data="function"==typeof t?function(e,t){le();try{return e.call(t,t)}catch(e){return He(e,t,"data()"),{}}finally{fe()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];r&&y(r,o)||(a=void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&vn(e,"_data",o))}var a;Ce(t,!0)}(e):Ce(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=te();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;r||(n[i]=new pn(e,a||S,S,mn)),i in e||yn(e,i,o)}}(e,t.computed),t.watch&&t.watch!==Y&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;i-1:"string"==typeof e?e.split(",").indexOf(t)>-1:(n=e,"[object RegExp]"===a.call(n)&&e.test(t));var n}function On(e,t){var n=e.cache,r=e.keys,i=e._vnode;for(var o in n){var a=n[o];if(a){var s=a.name;s&&!t(s)&&Sn(n,o,r,i)}}}function Sn(e,t,n,r){var i=e[t];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),e[t]=null,h(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=$n++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),r=t._parentVnode;n.parent=t.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=De(wn(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&Wt(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,r=t.$vnode=n._parentVnode,i=r&&r.context;t.$slots=lt(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,r,i){return Ht(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return Ht(t,e,n,r,i,!0)};var o=r&&r.data;xe(t,"$attrs",o&&o.attrs||e,null,!0),xe(t,"$listeners",n._parentListeners||e,null,!0)}(n),Qt(n,"beforeCreate"),function(e){var t=ut(e.$options.inject,e);t&&($e(!1),Object.keys(t).forEach(function(n){xe(e,n,t[n])}),$e(!0))}(n),hn(n),function(e){var t=e.$options.provide;t&&(e._provided="function"==typeof t?t.call(e):t)}(n),Qt(n,"created"),n.$options.el&&n.$mount(n.$options.el)}}(Cn),function(e){var t={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(e.prototype,"$data",t),Object.defineProperty(e.prototype,"$props",n),e.prototype.$set=ke,e.prototype.$delete=Ae,e.prototype.$watch=function(e,t,n){if(s(t))return bn(this,e,t,n);(n=n||{}).user=!0;var r=new pn(this,e,t,n);if(n.immediate){var i='callback for immediate watcher "'+r.expression+'"';le(),Be(t,this,[r.value],this,i),fe()}return function(){r.teardown()}}}(Cn),function(e){var t=/^hook:/;e.prototype.$on=function(e,n){var r=this;if(Array.isArray(e))for(var i=0,o=e.length;i1?k(t):t;for(var n=k(arguments,1),r='event handler for "'+e+'"',i=0,o=t.length;iparseInt(this.max)&&Sn(e,t[0],t,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var e in this.cache)Sn(this.cache,e,this.keys)},mounted:function(){var e=this;this.cacheVNode(),this.$watch("include",function(t){On(e,function(e){return An(t,e)})}),this.$watch("exclude",function(t){On(e,function(e){return!An(t,e)})})},updated:function(){this.cacheVNode()},render:function(){var e=this.$slots.default,t=zt(e),n=t&&t.componentOptions;if(n){var r=kn(n),i=this.include,o=this.exclude;if(i&&(!r||!An(i,r))||o&&r&&An(o,r))return t;var a=this.cache,s=this.keys,c=null==t.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):t.key;a[c]?(t.componentInstance=a[c].componentInstance,h(s,c),s.push(c)):(this.vnodeToCache=t,this.keyToCache=c),t.data.keepAlive=!0}return t||e&&e[0]}}};!function(e){var t={get:function(){return F}};Object.defineProperty(e,"config",t),e.util={warn:ae,extend:A,mergeOptions:De,defineReactive:xe},e.set=ke,e.delete=Ae,e.nextTick=Qe,e.observable=function(e){return Ce(e),e},e.options=Object.create(null),I.forEach(function(t){e.options[t+"s"]=Object.create(null)}),e.options._base=e,A(e.options.components,Nn),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=k(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=De(this.options,e),this}}(e),xn(e),function(e){I.forEach(function(t){e[t]=function(e,n){return n?("component"===t&&s(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}})}(e)}(Cn),Object.defineProperty(Cn.prototype,"$isServer",{get:te}),Object.defineProperty(Cn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Cn,"FunctionalRenderContext",{value:Et}),Cn.version="2.6.14";var En=p("style,class"),jn=p("input,textarea,option,select,progress"),Dn=function(e,t,n){return"value"===n&&jn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},Ln=p("contenteditable,draggable,spellcheck"),In=p("events,caret,typing,plaintext-only"),Mn=function(e,t){return Bn(t)||"false"===t?"false":"contenteditable"===e&&In(t)?t:"true"},Fn=p("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),Pn="http://www.w3.org/1999/xlink",Rn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Hn=function(e){return Rn(e)?e.slice(6,e.length):""},Bn=function(e){return null==e||!1===e};function Un(e){for(var t=e.data,r=e,i=e;n(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Vn(i.data,t));for(;n(r=r.parent);)r&&r.data&&(t=Vn(t,r.data));return function(e,t){if(n(e)||n(t))return zn(e,Kn(t));return""}(t.staticClass,t.class)}function Vn(e,t){return{staticClass:zn(e.staticClass,t.staticClass),class:n(e.class)?[e.class,t.class]:t.class}}function zn(e,t){return e?t?e+" "+t:e:t||""}function Kn(e){return Array.isArray(e)?function(e){for(var t,r="",i=0,o=e.length;i-1?mr(e,t,n):Fn(t)?Bn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):Ln(t)?e.setAttribute(t,Mn(t,n)):Rn(t)?Bn(n)?e.removeAttributeNS(Pn,Hn(t)):e.setAttributeNS(Pn,t,n):mr(e,t,n)}function mr(e,t,n){if(Bn(n))e.removeAttribute(t);else{if(q&&!W&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var r=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",r)};e.addEventListener("input",r),e.__ieph=!0}e.setAttribute(t,n)}}var yr={create:vr,update:vr};function gr(e,r){var i=r.elm,o=r.data,a=e.data;if(!(t(o.staticClass)&&t(o.class)&&(t(a)||t(a.staticClass)&&t(a.class)))){var s=Un(r),c=i._transitionClasses;n(c)&&(s=zn(s,Kn(c))),s!==i._prevClass&&(i.setAttribute("class",s),i._prevClass=s)}}var _r,br,$r,wr,Cr,xr,kr={create:gr,update:gr},Ar=/[\w).+\-_$\]]/;function Or(e){var t,n,r,i,o,a=!1,s=!1,c=!1,u=!1,l=0,f=0,p=0,d=0;for(r=0;r=0&&" "===(h=e.charAt(v));v--);h&&Ar.test(h)||(u=!0)}}else void 0===i?(d=r+1,i=e.slice(0,r).trim()):m();function m(){(o||(o=[])).push(e.slice(d,r).trim()),d=r+1}if(void 0===i?i=e.slice(0,r).trim():0!==d&&m(),o)for(r=0;r-1?{exp:e.slice(0,wr),key:'"'+e.slice(wr+1)+'"'}:{exp:e,key:null};br=e,wr=Cr=xr=0;for(;!zr();)Kr($r=Vr())?qr($r):91===$r&&Jr($r);return{exp:e.slice(0,Cr),key:e.slice(Cr+1,xr)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Vr(){return br.charCodeAt(++wr)}function zr(){return wr>=_r}function Kr(e){return 34===e||39===e}function Jr(e){var t=1;for(Cr=wr;!zr();)if(Kr(e=Vr()))qr(e);else if(91===e&&t++,93===e&&t--,0===t){xr=wr;break}}function qr(e){for(var t=e;!zr()&&(e=Vr())!==t;);}var Wr,Zr="__r",Gr="__c";function Xr(e,t,n){var r=Wr;return function i(){null!==t.apply(null,arguments)&&ei(e,i,n,r)}}var Yr=Ke&&!(X&&Number(X[1])<=53);function Qr(e,t,n,r){if(Yr){var i=sn,o=t;t=o._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||e.timeStamp<=0||e.target.ownerDocument!==document)return o.apply(this,arguments)}}Wr.addEventListener(e,t,Q?{capture:n,passive:r}:n)}function ei(e,t,n,r){(r||Wr).removeEventListener(e,t._wrapper||t,n)}function ti(e,r){if(!t(e.data.on)||!t(r.data.on)){var i=r.data.on||{},o=e.data.on||{};Wr=r.elm,function(e){if(n(e[Zr])){var t=q?"change":"input";e[t]=[].concat(e[Zr],e[t]||[]),delete e[Zr]}n(e[Gr])&&(e.change=[].concat(e[Gr],e.change||[]),delete e[Gr])}(i),it(i,o,Qr,ei,Xr,r.context),Wr=void 0}}var ni,ri={create:ti,update:ti};function ii(e,r){if(!t(e.data.domProps)||!t(r.data.domProps)){var i,o,a=r.elm,s=e.data.domProps||{},c=r.data.domProps||{};for(i in n(c.__ob__)&&(c=r.data.domProps=A({},c)),s)i in c||(a[i]="");for(i in c){if(o=c[i],"textContent"===i||"innerHTML"===i){if(r.children&&(r.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i&&"PROGRESS"!==a.tagName){a._value=o;var u=t(o)?"":String(o);oi(a,u)&&(a.value=u)}else if("innerHTML"===i&&Wn(a.tagName)&&t(a.innerHTML)){(ni=ni||document.createElement("div")).innerHTML=""+o+"";for(var l=ni.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else if(o!==s[i])try{a[i]=o}catch(e){}}}}function oi(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var r=e.value,i=e._vModifiers;if(n(i)){if(i.number)return f(r)!==f(t);if(i.trim)return r.trim()!==t.trim()}return r!==t}(e,t))}var ai={create:ii,update:ii},si=g(function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach(function(e){if(e){var r=e.split(n);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t});function ci(e){var t=ui(e.style);return e.staticStyle?A(e.staticStyle,t):t}function ui(e){return Array.isArray(e)?O(e):"string"==typeof e?si(e):e}var li,fi=/^--/,pi=/\s*!important$/,di=function(e,t,n){if(fi.test(t))e.style.setProperty(t,n);else if(pi.test(n))e.style.setProperty(C(t),n.replace(pi,""),"important");else{var r=hi(t);if(Array.isArray(n))for(var i=0,o=n.length;i-1?t.split(gi).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function bi(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(gi).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function $i(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&A(t,wi(e.name||"v")),A(t,e),t}return"string"==typeof e?wi(e):void 0}}var wi=g(function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}}),Ci=V&&!W,xi="transition",ki="animation",Ai="transition",Oi="transitionend",Si="animation",Ti="animationend";Ci&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Ai="WebkitTransition",Oi="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Si="WebkitAnimation",Ti="webkitAnimationEnd"));var Ni=V?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Ei(e){Ni(function(){Ni(e)})}function ji(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),_i(e,t))}function Di(e,t){e._transitionClasses&&h(e._transitionClasses,t),bi(e,t)}function Li(e,t,n){var r=Mi(e,t),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===xi?Oi:Ti,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=a&&u()};setTimeout(function(){c0&&(n=xi,l=a,f=o.length):t===ki?u>0&&(n=ki,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?xi:ki:null)?n===xi?o.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===xi&&Ii.test(r[Ai+"Property"])}}function Fi(e,t){for(;e.length1}function Vi(e,t){!0!==t.data.show&&Ri(t)}var zi=function(e){var o,a,s={},c=e.modules,u=e.nodeOps;for(o=0;ov?_(e,t(i[y+1])?null:i[y+1].elm,i,d,y,o):d>y&&$(r,p,v)}(p,h,y,o,l):n(y)?(n(e.text)&&u.setTextContent(p,""),_(p,null,y,0,y.length-1,o)):n(h)?$(h,0,h.length-1):n(e.text)&&u.setTextContent(p,""):e.text!==i.text&&u.setTextContent(p,i.text),n(v)&&n(d=v.hook)&&n(d=d.postpatch)&&d(e,i)}}}function k(e,t,i){if(r(i)&&n(e.parent))e.parent.data.pendingInsert=t;else for(var o=0;o-1,a.selected!==o&&(a.selected=o);else if(E(Zi(a),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function Wi(e,t){return t.every(function(t){return!E(t,e)})}function Zi(e){return"_value"in e?e._value:e.value}function Gi(e){e.target.composing=!0}function Xi(e){e.target.composing&&(e.target.composing=!1,Yi(e.target,"input"))}function Yi(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function Qi(e){return!e.componentInstance||e.data&&e.data.transition?e:Qi(e.componentInstance._vnode)}var eo={model:Ki,show:{bind:function(e,t,n){var r=t.value,i=(n=Qi(n)).data&&n.data.transition,o=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;r&&i?(n.data.show=!0,Ri(n,function(){e.style.display=o})):e.style.display=r?o:"none"},update:function(e,t,n){var r=t.value;!r!=!t.oldValue&&((n=Qi(n)).data&&n.data.transition?(n.data.show=!0,r?Ri(n,function(){e.style.display=e.__vOriginalDisplay}):Hi(n,function(){e.style.display="none"})):e.style.display=r?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,r,i){i||(e.style.display=e.__vOriginalDisplay)}}},to={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function no(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?no(zt(t.children)):e}function ro(e){var t={},n=e.$options;for(var r in n.propsData)t[r]=e[r];var i=n._parentListeners;for(var o in i)t[b(o)]=i[o];return t}function io(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var oo=function(e){return e.tag||pt(e)},ao=function(e){return"show"===e.name},so={name:"transition",props:to,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(oo)).length){var r=this.mode,o=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return o;var a=no(o);if(!a)return o;if(this._leaving)return io(e,o);var s="__transition-"+this._uid+"-";a.key=null==a.key?a.isComment?s+"comment":s+a.tag:i(a.key)?0===String(a.key).indexOf(s)?a.key:s+a.key:a.key;var c=(a.data||(a.data={})).transition=ro(this),u=this._vnode,l=no(u);if(a.data.directives&&a.data.directives.some(ao)&&(a.data.show=!0),l&&l.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(a,l)&&!pt(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=A({},c);if("out-in"===r)return this._leaving=!0,ot(f,"afterLeave",function(){t._leaving=!1,t.$forceUpdate()}),io(e,o);if("in-out"===r){if(pt(a))return u;var p,d=function(){p()};ot(c,"afterEnter",d),ot(c,"enterCancelled",d),ot(f,"delayLeave",function(e){p=e})}}return o}}},co=A({tag:String,moveClass:String},to);function uo(e){e.elm._moveCb&&e.elm._moveCb(),e.elm._enterCb&&e.elm._enterCb()}function lo(e){e.data.newPos=e.elm.getBoundingClientRect()}function fo(e){var t=e.data.pos,n=e.data.newPos,r=t.left-n.left,i=t.top-n.top;if(r||i){e.data.moved=!0;var o=e.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}delete co.mode;var po={Transition:so,TransitionGroup:{props:co,beforeMount:function(){var e=this,t=this._update;this._update=function(n,r){var i=Gt(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,r)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=ro(this),s=0;s-1?Xn[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:Xn[e]=/HTMLUnknownElement/.test(t.toString())},A(Cn.options.directives,eo),A(Cn.options.components,po),Cn.prototype.__patch__=V?zi:S,Cn.prototype.$mount=function(e,t){return function(e,t,n){var r;return e.$el=t,e.$options.render||(e.$options.render=ve),Qt(e,"beforeMount"),r=function(){e._update(e._render(),n)},new pn(e,r,S,{before:function(){e._isMounted&&!e._isDestroyed&&Qt(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,Qt(e,"mounted")),e}(this,e=e&&V?Qn(e):void 0,t)},V&&setTimeout(function(){F.devtools&&ne&&ne.emit("init",Cn)},0);var vo=/\{\{((?:.|\r?\n)+?)\}\}/g,ho=/[-.*+?^${}()|[\]\/\\]/g,mo=g(function(e){var t=e[0].replace(ho,"\\$&"),n=e[1].replace(ho,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")});var yo={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=Pr(e,"class");n&&(e.staticClass=JSON.stringify(n));var r=Fr(e,"class",!1);r&&(e.classBinding=r)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}};var go,_o={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=Pr(e,"style");n&&(e.staticStyle=JSON.stringify(si(n)));var r=Fr(e,"style",!1);r&&(e.styleBinding=r)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},bo=function(e){return(go=go||document.createElement("div")).innerHTML=e,go.textContent},$o=p("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),wo=p("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),Co=p("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),xo=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,ko=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Ao="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+P.source+"]*",Oo="((?:"+Ao+"\\:)?"+Ao+")",So=new RegExp("^<"+Oo),To=/^\s*(\/?)>/,No=new RegExp("^<\\/"+Oo+"[^>]*>"),Eo=/^]+>/i,jo=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Fo=/&(?:lt|gt|quot|amp|#39);/g,Po=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,Ro=p("pre,textarea",!0),Ho=function(e,t){return e&&Ro(e)&&"\n"===t[0]};function Bo(e,t){var n=t?Po:Fo;return e.replace(n,function(e){return Mo[e]})}var Uo,Vo,zo,Ko,Jo,qo,Wo,Zo,Go=/^@|^v-on:/,Xo=/^v-|^@|^:|^#/,Yo=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,Qo=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,ea=/^\(|\)$/g,ta=/^\[.*\]$/,na=/:(.*)$/,ra=/^:|^\.|^v-bind:/,ia=/\.[^.\]]+(?=[^\]]*$)/g,oa=/^v-slot(:|$)|^#/,aa=/[\r\n]/,sa=/[ \f\t\r\n]+/g,ca=g(bo),ua="_empty_";function la(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:ya(t),rawAttrsMap:{},parent:n,children:[]}}function fa(e,t){Uo=t.warn||Tr,qo=t.isPreTag||T,Wo=t.mustUseProp||T,Zo=t.getTagNamespace||T;t.isReservedTag;zo=Nr(t.modules,"transformNode"),Ko=Nr(t.modules,"preTransformNode"),Jo=Nr(t.modules,"postTransformNode"),Vo=t.delimiters;var n,r,i=[],o=!1!==t.preserveWhitespace,a=t.whitespace,s=!1,c=!1;function u(e){if(l(e),s||e.processed||(e=pa(e,t)),i.length||e===n||n.if&&(e.elseif||e.else)&&va(n,{exp:e.elseif,block:e}),r&&!e.forbidden)if(e.elseif||e.else)a=e,(u=function(e){var t=e.length;for(;t--;){if(1===e[t].type)return e[t];e.pop()}}(r.children))&&u.if&&va(u,{exp:a.elseif,block:a});else{if(e.slotScope){var o=e.slotTarget||'"default"';(r.scopedSlots||(r.scopedSlots={}))[o]=e}r.children.push(e),e.parent=r}var a,u;e.children=e.children.filter(function(e){return!e.slotScope}),l(e),e.pre&&(s=!1),qo(e.tag)&&(c=!1);for(var f=0;f]*>)","i")),p=e.replace(f,function(e,n,r){return u=r.length,Lo(l)||"noscript"===l||(n=n.replace(//g,"$1").replace(//g,"$1")),Ho(l,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""});c+=e.length-p.length,e=p,A(l,c-u,c)}else{var d=e.indexOf("<");if(0===d){if(jo.test(e)){var v=e.indexOf("--\x3e");if(v>=0){t.shouldKeepComment&&t.comment(e.substring(4,v),c,c+v+3),C(v+3);continue}}if(Do.test(e)){var h=e.indexOf("]>");if(h>=0){C(h+2);continue}}var m=e.match(Eo);if(m){C(m[0].length);continue}var y=e.match(No);if(y){var g=c;C(y[0].length),A(y[1],g,c);continue}var _=x();if(_){k(_),Ho(_.tagName,e)&&C(1);continue}}var b=void 0,$=void 0,w=void 0;if(d>=0){for($=e.slice(d);!(No.test($)||So.test($)||jo.test($)||Do.test($)||(w=$.indexOf("<",1))<0);)d+=w,$=e.slice(d);b=e.substring(0,d)}d<0&&(b=e),b&&C(b.length),t.chars&&b&&t.chars(b,c-b.length,c)}if(e===n){t.chars&&t.chars(e);break}}function C(t){c+=t,e=e.substring(t)}function x(){var t=e.match(So);if(t){var n,r,i={tagName:t[1],attrs:[],start:c};for(C(t[0].length);!(n=e.match(To))&&(r=e.match(ko)||e.match(xo));)r.start=c,C(r[0].length),r.end=c,i.attrs.push(r);if(n)return i.unarySlash=n[1],C(n[0].length),i.end=c,i}}function k(e){var n=e.tagName,c=e.unarySlash;o&&("p"===r&&Co(n)&&A(r),s(n)&&r===n&&A(n));for(var u=a(n)||!!c,l=e.attrs.length,f=new Array(l),p=0;p=0&&i[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=i.length-1;u>=a;u--)t.end&&t.end(i[u].tag,n,o);i.length=a,r=a&&i[a-1].tag}else"br"===s?t.start&&t.start(e,[],!0,n,o):"p"===s&&(t.start&&t.start(e,[],!1,n,o),t.end&&t.end(e,n,o))}A()}(e,{warn:Uo,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,o,a,l,f){var p=r&&r.ns||Zo(e);q&&"svg"===p&&(o=function(e){for(var t=[],n=0;nc&&(s.push(o=e.slice(c,i)),a.push(JSON.stringify(o)));var u=Or(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c-1"+("true"===o?":("+t+")":":_q("+t+","+o+")")),Mr(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Ur(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Ur(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Ur(t,"$$c")+"}",null,!0)}(e,r,i);else if("input"===o&&"radio"===a)!function(e,t,n){var r=n&&n.number,i=Fr(e,"value")||"null";Er(e,"checked","_q("+t+","+(i=r?"_n("+i+")":i)+")"),Mr(e,"change",Ur(t,i),null,!0)}(e,r,i);else if("input"===o||"textarea"===o)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?Zr:"input",l="$event.target.value";s&&(l="$event.target.value.trim()"),a&&(l="_n("+l+")");var f=Ur(t,l);c&&(f="if($event.target.composing)return;"+f),Er(e,"value","("+t+")"),Mr(e,u,f,null,!0),(s||a)&&Mr(e,"blur","$forceUpdate()")}(e,r,i);else if(!F.isReservedTag(o))return Br(e,r,i),!1;return!0},text:function(e,t){t.value&&Er(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Er(e,"innerHTML","_s("+t.value+")",t)}},isPreTag:function(e){return"pre"===e},isUnaryTag:$o,mustUseProp:Dn,canBeLeftOpenTag:wo,isReservedTag:Zn,getTagNamespace:Gn,staticKeys:function(e){return e.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(",")}($a)},ka=g(function(e){return p("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))});function Aa(e,t){e&&(wa=ka(t.staticKeys||""),Ca=t.isReservedTag||T,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||d(e.tag)||!Ca(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(wa)))}(t);if(1===t.type){if(!Ca(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;n|^function(?:\s+[\w$]+)?\s*\(/,Sa=/\([^)]*?\);*$/,Ta=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Na={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Ea={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},ja=function(e){return"if("+e+")return null;"},Da={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:ja("$event.target !== $event.currentTarget"),ctrl:ja("!$event.ctrlKey"),shift:ja("!$event.shiftKey"),alt:ja("!$event.altKey"),meta:ja("!$event.metaKey"),left:ja("'button' in $event && $event.button !== 0"),middle:ja("'button' in $event && $event.button !== 1"),right:ja("'button' in $event && $event.button !== 2")};function La(e,t){var n=t?"nativeOn:":"on:",r="",i="";for(var o in e){var a=Ia(e[o]);e[o]&&e[o].dynamic?i+=o+","+a+",":r+='"'+o+'":'+a+","}return r="{"+r.slice(0,-1)+"}",i?n+"_d("+r+",["+i.slice(0,-1)+"])":n+r}function Ia(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return Ia(e)}).join(",")+"]";var t=Ta.test(e.value),n=Oa.test(e.value),r=Ta.test(e.value.replace(Sa,""));if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(Da[s])o+=Da[s],Na[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=ja(["ctrl","shift","alt","meta"].filter(function(e){return!c[e]}).map(function(e){return"$event."+e+"Key"}).join("||"))}else a.push(s);return a.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(Ma).join("&&")+")return null;"}(a)),o&&(i+=o),"function($event){"+i+(t?"return "+e.value+".apply(null, arguments)":n?"return ("+e.value+").apply(null, arguments)":r?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(r?"return "+e.value:e.value)+"}"}function Ma(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Na[e],r=Ea[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var Fa={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:S},Pa=function(e){this.options=e,this.warn=e.warn||Tr,this.transforms=Nr(e.modules,"transformCode"),this.dataGenFns=Nr(e.modules,"genData"),this.directives=A(A({},Fa),e.directives);var t=e.isReservedTag||T;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Ra(e,t){var n=new Pa(t);return{render:"with(this){return "+(e?"script"===e.tag?"null":Ha(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Ha(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ba(e,t);if(e.once&&!e.onceProcessed)return Ua(e,t);if(e.for&&!e.forProcessed)return za(e,t);if(e.if&&!e.ifProcessed)return Va(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=Wa(e,t),i="_t("+n+(r?",function(){return "+r+"}":""),o=e.attrs||e.dynamicAttrs?Xa((e.attrs||[]).concat(e.dynamicAttrs||[]).map(function(e){return{name:b(e.name),value:e.value,dynamic:e.dynamic}})):null,a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var r=t.inlineTemplate?null:Wa(t,n,!0);return"_c("+e+","+Ka(t,n)+(r?","+r:"")+")"}(e.component,e,t);else{var r;(!e.plain||e.pre&&t.maybeComponent(e))&&(r=Ka(e,t));var i=e.inlineTemplate?null:Wa(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o>>0}(a):"")+")"}(e,e.scopedSlots,t)+","),e.model&&(n+="model:{value:"+e.model.value+",callback:"+e.model.callback+",expression:"+e.model.expression+"},"),e.inlineTemplate){var o=function(e,t){var n=e.children[0];if(n&&1===n.type){var r=Ra(n,t.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map(function(e){return"function(){"+e+"}"}).join(",")+"]}"}}(e,t);o&&(n+=o+",")}return n=n.replace(/,$/,"")+"}",e.dynamicAttrs&&(n="_b("+n+',"'+e.tag+'",'+Xa(e.dynamicAttrs)+")"),e.wrapData&&(n=e.wrapData(n)),e.wrapListeners&&(n=e.wrapListeners(n)),n}function Ja(e){return 1===e.type&&("slot"===e.tag||e.children.some(Ja))}function qa(e,t){var n=e.attrsMap["slot-scope"];if(e.if&&!e.ifProcessed&&!n)return Va(e,t,qa,"null");if(e.for&&!e.forProcessed)return za(e,t,qa);var r=e.slotScope===ua?"":String(e.slotScope),i="function("+r+"){return "+("template"===e.tag?e.if&&n?"("+e.if+")?"+(Wa(e,t)||"undefined")+":undefined":Wa(e,t)||"undefined":Ha(e,t))+"}",o=r?"":",proxy:true";return"{key:"+(e.slotTarget||'"default"')+",fn:"+i+o+"}"}function Wa(e,t,n,r,i){var o=e.children;if(o.length){var a=o[0];if(1===o.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?t.maybeComponent(a)?",1":",0":"";return""+(r||Ha)(a,t)+s}var c=n?function(e,t){for(var n=0,r=0;r':'
    ',ns.innerHTML.indexOf(" ")>0}var as=!!V&&os(!1),ss=!!V&&os(!0),cs=g(function(e){var t=Qn(e);return t&&t.innerHTML}),us=Cn.prototype.$mount;return Cn.prototype.$mount=function(e,t){if((e=e&&Qn(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=cs(r));else{if(!r.nodeType)return this;r=r.innerHTML}else e&&(r=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(r){var i=is(r,{outputSourceRange:!1,shouldDecodeNewlines:as,shouldDecodeNewlinesForHref:ss,delimiters:n.delimiters,comments:n.comments},this),o=i.render,a=i.staticRenderFns;n.render=o,n.staticRenderFns=a}}return us.call(this,e,t)},Cn.compile=is,Cn}); \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/locales/da.lua b/resources/[qb]/[qb_shops]/qb-vehiclesales/locales/da.lua new file mode 100644 index 0000000..c58c24a --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/locales/da.lua @@ -0,0 +1,53 @@ +local Translations = { + error = { + not_your_vehicle = 'Dette er ikke dit køretøj..', + vehicle_does_not_exist = 'Køretøjet eksisterer ikke', + not_enough_money = 'Du har ikke nok penge', + finish_payments = 'Du skal betale køretøjet helt ud, før du kan sælge det..', + no_space_on_lot = 'Der er ikke plads til dit køretøj på pladsen!', + not_in_veh = 'Du er ikke i et køretøj!', + not_for_sale = 'Dette køretøj er IKKE til salg!', + }, + menu = { + view_contract = 'Se kontrakt', + view_contract_int = '[E] Se kontrakt', + sell_vehicle = 'Sælg køretøj', + sell_vehicle_help = 'Sælg dit køretøj til en medborger!', + sell_back = 'Sælg tilbage', + sell_back_help = 'Sælg dit køretøj direkte tilbage til forhandleren for en reduceret pris!', + interaction = '[E] Sælg køretøj', + }, + success = { + sold_car_for_price = 'Du har solgt dit køretøj for %{value},-', + car_up_for_sale = 'Dit køretøj er sat til salg! Pris - %{value},-', + vehicle_bought = 'Køretøj købt', + }, + info = { + confirm_cancel = '~g~Y~w~ - Bekræft / ~r~N~w~ - Annuller ~g~', + vehicle_returned = 'Dit køretøj er returneret', + used_vehicle_lot = 'Brugvognsforhandler', + sell_vehicle_to_dealer = '[~g~E~w~] - Sælg køretøj til forhandler for ~g~%{value},-', + view_contract = '[~g~E~w~] - Se køretøjskontrakt', + cancel_sale = '[~r~G~w~] - Annuller køretøjs salg', + model_price = '%{value}, Pris: ~g~%{value2},-', + are_you_sure = 'Er du sikker på at du ikke længere vil sælge dit køretøj?', + yes_no = '[~g~7~w~] - Ja | [~r~8~w~] - Nej', + place_vehicle_for_sale = '[~g~E~w~] - Sæt køretøj til salg som ejer', + }, + charinfo = { + firstname = 'Ukendt', + lastname = 'Navn', + account = 'Ukendt konto', + phone = 'Ukendt nummer', + }, + mail = { + sender = 'Larrys RV Salg', + subject = 'Du har solgt et køretøj!', + message = 'Du tjente %{value},- for salget af din %{value2}.', + } +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +}) diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/qb-vehiclesales.sql b/resources/[qb]/[qb_shops]/qb-vehiclesales/qb-vehiclesales.sql new file mode 100644 index 0000000..e07637f --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/qb-vehiclesales.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `occasion_vehicles` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `seller` varchar(50) DEFAULT NULL, + `price` int(11) DEFAULT NULL, + `description` longtext DEFAULT NULL, + `plate` varchar(50) DEFAULT NULL, + `model` varchar(50) DEFAULT NULL, + `mods` text DEFAULT NULL, + `occasionid` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `occasionId` (`occasionid`) +) ENGINE=InnoDB AUTO_INCREMENT=325 DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/resources/[qb]/[qb_shops]/qb-vehiclesales/server/main.lua b/resources/[qb]/[qb_shops]/qb-vehiclesales/server/main.lua new file mode 100644 index 0000000..8a4faca --- /dev/null +++ b/resources/[qb]/[qb_shops]/qb-vehiclesales/server/main.lua @@ -0,0 +1,152 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +-- Functions + +local function generateOID() + local num = math.random(1, 10) .. math.random(111, 999) + + return "OC" .. num +end + +-- Callbacks + +QBCore.Functions.CreateCallback('qb-occasions:server:getVehicles', function(_, cb) + local result = MySQL.query.await('SELECT * FROM occasion_vehicles', {}) + if result[1] then + cb(result) + else + cb(nil) + end +end) + +--Call from qb-vehiclesales +QBCore.Functions.CreateCallback("qb-garage:server:checkVehicleOwner", function(source, cb, plate) + local src = source + local pData = QBCore.Functions.GetPlayer(src) + MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?',{plate, pData.PlayerData.citizenid}, function(result) + if result[1] then + cb(true, result[1].balance) + else + cb(false) + end + end) +end) + +QBCore.Functions.CreateCallback("qb-occasions:server:getSellerInformation", function(_, cb, citizenid) + MySQL.query('SELECT * FROM players WHERE citizenid = ?', {citizenid}, function(result) + if result[1] then + cb(result[1]) + else + cb(nil) + end + end) +end) + +QBCore.Functions.CreateCallback("qb-vehiclesales:server:CheckModelName", function(_, cb, plate) + if plate then + local ReturnData = MySQL.scalar.await("SELECT vehicle FROM player_vehicles WHERE plate = ?", {plate}) + cb(ReturnData) + end +end) + +-- Events + +RegisterNetEvent('qb-occasions:server:ReturnVehicle', function(vehicleData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local result = MySQL.query.await('SELECT * FROM occasion_vehicles WHERE plate = ? AND occasionid = ?', {vehicleData['plate'], vehicleData["oid"]}) + if result[1] then + if result[1].seller == Player.PlayerData.citizenid then + MySQL.insert('INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, state) VALUES (?, ?, ?, ?, ?, ?, ?)', {Player.PlayerData.license, Player.PlayerData.citizenid, vehicleData["model"], joaat(vehicleData["model"]), vehicleData["mods"], vehicleData["plate"], 0}) + MySQL.query('DELETE FROM occasion_vehicles WHERE occasionid = ? AND plate = ?', {vehicleData["oid"], vehicleData['plate']}) + TriggerClientEvent("qb-occasions:client:ReturnOwnedVehicle", src, result[1]) + TriggerClientEvent('qb-occasion:client:refreshVehicles', -1) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_your_vehicle'), 'error', 3500) + end + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.vehicle_does_not_exist'), 'error', 3500) + end +end) + +RegisterNetEvent('qb-occasions:server:sellVehicle', function(vehiclePrice, vehicleData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + MySQL.query('DELETE FROM player_vehicles WHERE plate = ? AND vehicle = ?',{vehicleData.plate, vehicleData.model}) + MySQL.insert('INSERT INTO occasion_vehicles (seller, price, description, plate, model, mods, occasionid) VALUES (?, ?, ?, ?, ?, ?, ?)',{Player.PlayerData.citizenid, vehiclePrice, vehicleData.desc, vehicleData.plate, vehicleData.model,json.encode(vehicleData.mods), generateOID()}) + TriggerEvent("qb-log:server:CreateLog", "vehicleshop", "Vehicle for Sale", "red","**" .. GetPlayerName(src) .. "** has a " .. vehicleData.model .. " priced at " .. vehiclePrice) + TriggerClientEvent('qb-occasion:client:refreshVehicles', -1) +end) + +RegisterNetEvent('qb-occasions:server:sellVehicleBack', function(vehData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local price = 0 + local plate = vehData.plate + for _, v in pairs(QBCore.Shared.Vehicles) do + if v["hash"] == vehData.model then + price = tonumber(v["price"]) + break + end + end + local payout = math.floor(tonumber(price * 0.5)) -- This will give you half of the cars value + Player.Functions.AddMoney('bank', payout) + TriggerClientEvent('QBCore:Notify', src, Lang:t('success.sold_car_for_price', { value = payout }), 'success', 5500) + MySQL.query('DELETE FROM player_vehicles WHERE plate = ?', {plate}) +end) + +RegisterNetEvent('qb-occasions:server:buyVehicle', function(vehicleData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local result = MySQL.query.await('SELECT * FROM occasion_vehicles WHERE plate = ? AND occasionid = ?',{vehicleData['plate'], vehicleData["oid"]}) + if result[1] and next(result[1]) then + if Player.PlayerData.money.bank >= result[1].price then + local SellerCitizenId = result[1].seller + local SellerData = QBCore.Functions.GetPlayerByCitizenId(SellerCitizenId) + local NewPrice = math.ceil((result[1].price / 100) * 77) + Player.Functions.RemoveMoney('bank', result[1].price) + MySQL.insert( + 'INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, state) VALUES (?, ?, ?, ?, ?, ?, ?)', { + Player.PlayerData.license, + Player.PlayerData.citizenid, result[1]["model"], + GetHashKey(result[1]["model"]), + result[1]["mods"], + result[1]["plate"], + 0 + }) + if SellerData then + SellerData.Functions.AddMoney('bank', NewPrice) + else + local BuyerData = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?',{SellerCitizenId}) + if BuyerData[1] then + local BuyerMoney = json.decode(BuyerData[1].money) + BuyerMoney.bank = BuyerMoney.bank + NewPrice + MySQL.update('UPDATE players SET money = ? WHERE citizenid = ?', {json.encode(BuyerMoney), SellerCitizenId}) + end + end + TriggerEvent("qb-log:server:CreateLog", "vehicleshop", "bought", "green", "**" .. GetPlayerName(src) .. "** has bought for " .. result[1].price .. " (" .. result[1].plate ..") from **" .. SellerCitizenId .. "**") + TriggerClientEvent("qb-occasions:client:BuyFinished", src, result[1]) + TriggerClientEvent('qb-occasion:client:refreshVehicles', -1) + MySQL.query('DELETE FROM occasion_vehicles WHERE plate = ? AND occasionid = ?',{result[1].plate, result[1].occasionid}) + exports['qb-phone']:sendNewMailToOffline(SellerCitizenId, { + sender = Lang:t('mail.sender'), + subject = Lang:t('mail.subject'), + message = Lang:t('mail.message', { value = NewPrice, value2 = QBCore.Shared.Vehicles[result[1].model].name}) + }) + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.not_enough_money'), 'error', 3500) + end + end +end) + +QBCore.Functions.CreateCallback("qb-garage:server:checkVehicleOwner", function(source, cb, plate) + local src = source + local pData = QBCore.Functions.GetPlayer(src) + MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?',{plate, pData.PlayerData.citizenid}, function(result) + if result[1] then + cb(true, result[1].balance) + else + cb(false) + end + end) +end) \ No newline at end of file diff --git a/resources/[qb]/qb-core/.editorconfig b/resources/[qb]/qb-core/.editorconfig new file mode 100644 index 0000000..1e1daab --- /dev/null +++ b/resources/[qb]/qb-core/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = false +indent_style = space +charset = utf-8 +trim_trailing_whitespace = true + +[*.lua] +indent_size = 4 + +[*.js] +indent_size = 2 diff --git a/resources/[qb]/qb-core/.gitignore b/resources/[qb]/qb-core/.gitignore new file mode 100644 index 0000000..3b6a158 --- /dev/null +++ b/resources/[qb]/qb-core/.gitignore @@ -0,0 +1,5 @@ +# Ignore any IDE derived project configs +.idea +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json \ No newline at end of file diff --git a/resources/[qb]/qb-core/.vscode/extensions.json b/resources/[qb]/qb-core/.vscode/extensions.json new file mode 100644 index 0000000..7d4f38c --- /dev/null +++ b/resources/[qb]/qb-core/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "sumneko.lua", + "overextended.cfxlua-vscode", + "ihyajb.qbcore-code-snippets", + "EditorConfig.EditorConfig", + "eamodio.gitlens", + "GitHub.vscode-pull-request-github" + ] +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/.vscode/settings.json b/resources/[qb]/qb-core/.vscode/settings.json new file mode 100644 index 0000000..4d79df9 --- /dev/null +++ b/resources/[qb]/qb-core/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "Lua.runtime.nonstandardSymbol": ["/**/", "`", "+=", "-=", "*=", "/="], + "Lua.runtime.version": "Lua 5.4" +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/LICENSE b/resources/[qb]/qb-core/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/resources/[qb]/qb-core/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[qb]/qb-core/README.md b/resources/[qb]/qb-core/README.md new file mode 100644 index 0000000..8c206b2 --- /dev/null +++ b/resources/[qb]/qb-core/README.md @@ -0,0 +1,21 @@ +# qb-core + +### [Official QBCore Documentation](https://docs.qbcore.org) + +# License + + QBCore Framework + Copyright (C) 2015-2022 ESX (Jérémie N'gadi), Joshua Eger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see diff --git a/resources/[qb]/qb-core/client/drawtext.lua b/resources/[qb]/qb-core/client/drawtext.lua new file mode 100644 index 0000000..ef200a9 --- /dev/null +++ b/resources/[qb]/qb-core/client/drawtext.lua @@ -0,0 +1,60 @@ +local function hideText() + SendNUIMessage({ + action = 'HIDE_TEXT', + }) +end + +local function drawText(text, position) + if type(position) ~= "string" then position = "left" end + + SendNUIMessage({ + action = 'DRAW_TEXT', + data = { + text = text, + position = position + } + }) +end + +local function changeText(text, position) + if type(position) ~= "string" then position = "left" end + + SendNUIMessage({ + action = 'CHANGE_TEXT', + data = { + text = text, + position = position + } + }) +end + +local function keyPressed() + CreateThread(function() -- Not sure if a thread is needed but why not eh? + SendNUIMessage({ + action = 'KEY_PRESSED', + }) + Wait(500) + hideText() + end) +end + +RegisterNetEvent('qb-core:client:DrawText', function(text, position) + drawText(text, position) +end) + +RegisterNetEvent('qb-core:client:ChangeText', function(text, position) + changeText(text, position) +end) + +RegisterNetEvent('qb-core:client:HideText', function() + hideText() +end) + +RegisterNetEvent('qb-core:client:KeyPressed', function() + keyPressed() +end) + +exports('DrawText', drawText) +exports('ChangeText', changeText) +exports('HideText', hideText) +exports('KeyPressed', keyPressed) \ No newline at end of file diff --git a/resources/[qb]/qb-core/client/events.lua b/resources/[qb]/qb-core/client/events.lua new file mode 100644 index 0000000..3d18b1c --- /dev/null +++ b/resources/[qb]/qb-core/client/events.lua @@ -0,0 +1,266 @@ +-- Player load and unload handling +-- New method for checking if logged in across all scripts (optional) +-- if LocalPlayer.state['isLoggedIn'] then +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + ShutdownLoadingScreenNui() + LocalPlayer.state:set('isLoggedIn', true, false) + if not QBConfig.Server.PVP then return end + SetCanAttackFriendly(PlayerPedId(), true, false) + NetworkSetFriendlyFireOption(true) +end) + +RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() + LocalPlayer.state:set('isLoggedIn', false, false) +end) + +RegisterNetEvent('QBCore:Client:PvpHasToggled', function(pvp_state) + SetCanAttackFriendly(PlayerPedId(), pvp_state, false) + NetworkSetFriendlyFireOption(pvp_state) +end) +-- Teleport Commands + +RegisterNetEvent('QBCore:Command:TeleportToPlayer', function(coords) + local ped = PlayerPedId() + SetPedCoordsKeepVehicle(ped, coords.x, coords.y, coords.z) +end) + +RegisterNetEvent('QBCore:Command:TeleportToCoords', function(x, y, z, h) + local ped = PlayerPedId() + SetPedCoordsKeepVehicle(ped, x, y, z) + SetEntityHeading(ped, h or GetEntityHeading(ped)) +end) + +RegisterNetEvent('QBCore:Command:GoToMarker', function() + local PlayerPedId = PlayerPedId + local GetEntityCoords = GetEntityCoords + local GetGroundZFor_3dCoord = GetGroundZFor_3dCoord + + local blipMarker = GetFirstBlipInfoId(8) + if not DoesBlipExist(blipMarker) then + QBCore.Functions.Notify(Lang:t("error.no_waypoint"), "error", 5000) + return 'marker' + end + + -- Fade screen to hide how clients get teleported. + DoScreenFadeOut(650) + while not IsScreenFadedOut() do + Wait(0) + end + + local ped, coords = PlayerPedId(), GetBlipInfoIdCoord(blipMarker) + local vehicle = GetVehiclePedIsIn(ped, false) + local oldCoords = GetEntityCoords(ped) + + -- Unpack coords instead of having to unpack them while iterating. + -- 825.0 seems to be the max a player can reach while 0.0 being the lowest. + local x, y, groundZ, Z_START = coords['x'], coords['y'], 850.0, 950.0 + local found = false + if vehicle > 0 then + FreezeEntityPosition(vehicle, true) + else + FreezeEntityPosition(ped, true) + end + + for i = Z_START, 0, -25.0 do + local z = i + if (i % 2) ~= 0 then + z = Z_START - i + end + + NewLoadSceneStart(x, y, z, x, y, z, 50.0, 0) + local curTime = GetGameTimer() + while IsNetworkLoadingScene() do + if GetGameTimer() - curTime > 1000 then + break + end + Wait(0) + end + NewLoadSceneStop() + SetPedCoordsKeepVehicle(ped, x, y, z) + + while not HasCollisionLoadedAroundEntity(ped) do + RequestCollisionAtCoord(x, y, z) + if GetGameTimer() - curTime > 1000 then + break + end + Wait(0) + end + + -- Get ground coord. As mentioned in the natives, this only works if the client is in render distance. + found, groundZ = GetGroundZFor_3dCoord(x, y, z, false); + if found then + Wait(0) + SetPedCoordsKeepVehicle(ped, x, y, groundZ) + break + end + Wait(0) + end + + -- Remove black screen once the loop has ended. + DoScreenFadeIn(650) + if vehicle > 0 then + FreezeEntityPosition(vehicle, false) + else + FreezeEntityPosition(ped, false) + end + + if not found then + -- If we can't find the coords, set the coords to the old ones. + -- We don't unpack them before since they aren't in a loop and only called once. + SetPedCoordsKeepVehicle(ped, oldCoords['x'], oldCoords['y'], oldCoords['z'] - 1.0) + QBCore.Functions.Notify(Lang:t("error.tp_error"), "error", 5000) + end + + -- If Z coord was found, set coords in found coords. + SetPedCoordsKeepVehicle(ped, x, y, groundZ) + QBCore.Functions.Notify(Lang:t("success.teleported_waypoint"), "success", 5000) +end) + +-- Vehicle Commands + +RegisterNetEvent('QBCore:Command:SpawnVehicle', function(vehName) + local ped = PlayerPedId() + local hash = GetHashKey(vehName) + local veh = GetVehiclePedIsUsing(ped) + if not IsModelInCdimage(hash) then return end + RequestModel(hash) + while not HasModelLoaded(hash) do + Wait(0) + end + + if IsPedInAnyVehicle(ped) then + SetEntityAsMissionEntity(veh, true, true) + DeleteVehicle(veh) + end + + local vehicle = CreateVehicle(hash, GetEntityCoords(ped), GetEntityHeading(ped), true, false) + TaskWarpPedIntoVehicle(ped, vehicle, -1) + SetVehicleNumberPlateText(vehicle, "ADMIN") + SetVehicleNumberPlateTextIndex(vehicle, 5) + SetVehicleFuelLevel(vehicle, 100.0) + SetVehicleDirtLevel(vehicle, 0.0) + SetModelAsNoLongerNeeded(hash) + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(vehicle)) +end) + +RegisterNetEvent('QBCore:Command:DeleteVehicle', function() + local ped = PlayerPedId() + local veh = GetVehiclePedIsUsing(ped) + if veh ~= 0 then + SetEntityAsMissionEntity(veh, true, true) + DeleteVehicle(veh) + else + local pcoords = GetEntityCoords(ped) + local vehicles = GetGamePool('CVehicle') + for _, v in pairs(vehicles) do + if #(pcoords - GetEntityCoords(v)) <= 5.0 then + SetEntityAsMissionEntity(v, true, true) + DeleteVehicle(v) + end + end + end +end) + +RegisterNetEvent('QBCore:Client:VehicleInfo', function(info) + local plate = QBCore.Functions.GetPlate(info.vehicle) + local hasKeys = true + + -- if GetResourceState('qb-vehiclekeys') == 'started' then + -- hasKeys = exports['qb-vehiclekeys']:HasKeys() + -- end + + local data = { + vehicle = info.vehicle, + seat = info.seat, + name = info.modelName, + plate = plate, + driver = GetPedInVehicleSeat(info.vehicle, -1), + inseat = GetPedInVehicleSeat(info.vehicle, info.seat), + haskeys = hasKeys + } + + TriggerEvent('QBCore:Client:'..info.event..'Vehicle', data) +end) + +-- Other stuff + +RegisterNetEvent('QBCore:Player:SetPlayerData', function(val) + QBCore.PlayerData = val +end) + +RegisterNetEvent('QBCore:Player:UpdatePlayerData', function() + TriggerServerEvent('QBCore:UpdatePlayer') +end) + +RegisterNetEvent('QBCore:Notify', function(text, type, length) + QBCore.Functions.Notify(text, type, length) +end) + +-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. +RegisterNetEvent('QBCore:Client:UseItem', function(item) + QBCore.Debug(string.format("%s triggered QBCore:Client:UseItem by ID %s with the following data. This event is deprecated due to exploitation, and will be removed soon. Check ps-inventory for the right use on this event.", GetInvokingResource(), GetPlayerServerId(PlayerId()))) + QBCore.Debug(item) +end) + +-- Callback Events -- + +-- Client Callback +RegisterNetEvent('QBCore:Client:TriggerClientCallback', function(name, ...) + QBCore.Functions.TriggerClientCallback(name, function(...) + TriggerServerEvent('QBCore:Server:TriggerClientCallback', name, ...) + end, ...) +end) + +-- Server Callback +RegisterNetEvent('QBCore:Client:TriggerCallback', function(name, ...) + if QBCore.ServerCallbacks[name] then + QBCore.ServerCallbacks[name](...) + QBCore.ServerCallbacks[name] = nil + end +end) + +-- Me command + +local function Draw3DText(coords, str) + local onScreen, worldX, worldY = World3dToScreen2d(coords.x, coords.y, coords.z) + local camCoords = GetGameplayCamCoord() + local scale = 200 / (GetGameplayCamFov() * #(camCoords - coords)) + if onScreen then + SetTextScale(1.0, 0.5 * scale) + SetTextFont(4) + SetTextColour(255, 255, 255, 255) + SetTextEdge(2, 0, 0, 0, 150) + SetTextProportional(1) + SetTextOutline() + SetTextCentre(1) + BeginTextCommandDisplayText("STRING") + AddTextComponentSubstringPlayerName(str) + EndTextCommandDisplayText(worldX, worldY) + end +end + +RegisterNetEvent('QBCore:Command:ShowMe3D', function(senderId, msg) + local sender = GetPlayerFromServerId(senderId) + CreateThread(function() + local displayTime = 5000 + GetGameTimer() + while displayTime > GetGameTimer() do + local targetPed = GetPlayerPed(sender) + local tCoords = GetEntityCoords(targetPed) + Draw3DText(tCoords, msg) + Wait(0) + end + end) +end) + +-- Listen to Shared being updated +RegisterNetEvent('QBCore:Client:OnSharedUpdate', function(tableName, key, value) + QBCore.Shared[tableName][key] = value + TriggerEvent('QBCore:Client:UpdateObject') +end) + +RegisterNetEvent('QBCore:Client:OnSharedUpdateMultiple', function(tableName, values) + for key, value in pairs(values) do + QBCore.Shared[tableName][key] = value + end + TriggerEvent('QBCore:Client:UpdateObject') +end) diff --git a/resources/[qb]/qb-core/client/functions.lua b/resources/[qb]/qb-core/client/functions.lua new file mode 100644 index 0000000..a986bbb --- /dev/null +++ b/resources/[qb]/qb-core/client/functions.lua @@ -0,0 +1,860 @@ +QBCore.Functions = {} + +-- Player + +function QBCore.Functions.GetPlayerData(cb) + if not cb then + return QBCore.PlayerData + else + cb(QBCore.PlayerData) + end +end + + +function QBCore.Functions.GetCoords(entity) + local coords = GetEntityCoords(entity) + return vector4(coords.x, coords.y, coords.z, GetEntityHeading(entity)) +end + +function QBCore.Functions.HasItem(items, amount) + return exports['ps-inventory']:HasItem(items, amount) +end + +-- Utility + +function QBCore.Functions.DrawText(x, y, width, height, scale, r, g, b, a, text) + -- Use local function instead + SetTextFont(4) + SetTextScale(scale, scale) + SetTextColour(r, g, b, a) + SetTextEntry('STRING') + AddTextComponentString(text) + DrawText(x - width / 2, y - height / 2 + 0.005) +end + +function QBCore.Functions.DrawText3D(x, y, z, text) + -- Use local function instead + SetTextScale(0.35, 0.35) + SetTextFont(4) + SetTextProportional(1) + SetTextColour(255, 255, 255, 215) + SetTextEntry('STRING') + SetTextCentre(true) + AddTextComponentString(text) + SetDrawOrigin(x, y, z, 0) + DrawText(0.0, 0.0) + local factor = (string.len(text)) / 370 + DrawRect(0.0, 0.0 + 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75) + ClearDrawOrigin() +end + +function QBCore.Functions.RequestAnimDict(animDict) + if HasAnimDictLoaded(animDict) then return end + RequestAnimDict(animDict) + while not HasAnimDictLoaded(animDict) do + Wait(0) + end +end + +function QBCore.Functions.PlayAnim(animDict, animName, upperbodyOnly, duration) + local flags = upperbodyOnly and 16 or 0 + local runTime = duration or -1 + QBCore.Functions.RequestAnimDict(animDict) + TaskPlayAnim(PlayerPedId(), animDict, animName, 8.0, 1.0, runTime, flags, 0.0, false, false, true) + RemoveAnimDict(animDict) +end + +function QBCore.Functions.LoadModel(model) + if HasModelLoaded(model) then return end + RequestModel(model) + while not HasModelLoaded(model) do + Wait(0) + end +end + +function QBCore.Functions.LoadAnimSet(animSet) + if HasAnimSetLoaded(animSet) then return end + RequestAnimSet(animSet) + while not HasAnimSetLoaded(animSet) do + Wait(0) + end +end + +RegisterNUICallback('getNotifyConfig', function(_, cb) + cb(QBCore.Config.Notify) +end) + +-- function QBCore.Functions.Notify(text, texttype, length) +-- if type(text) == "table" then +-- local ttext = text.text or 'Placeholder' +-- local caption = text.caption or 'Placeholder' +-- texttype = texttype or 'primary' +-- length = length or 5000 +-- SendNUIMessage({ +-- action = 'notify', +-- type = texttype, +-- length = length, +-- text = ttext, +-- caption = caption +-- }) +-- else +-- texttype = texttype or 'primary' +-- length = length or 5000 +-- SendNUIMessage({ +-- action = 'notify', +-- type = texttype, +-- length = length, +-- text = text +-- }) +-- end +-- end + +function QBCore.Functions.Notify(text, texttype, length) + if texttype ~= 'success' or texttype ~= 'error' or texttype ~= 'warning' or texttype ~= 'info' or texttype ~= 'inform' then + texttype = 'info' + end + local upperCase = texttype:gsub("^%l", string.upper) + exports['hp_hud']:Notification(texttype, upperCase, text) -- Native Notify i HP_HUD + + -- exports['bp_hud']:notifyactive(text, length, texttype) -- BP_HUD Notify + + -- exports['brutal_notify']:SendAlert('Hyperion', text, length, texttype) -- Brutal_Notify +end + + +function QBCore.Debug(resource, obj, depth) + TriggerServerEvent('QBCore:DebugSomething', resource, obj, depth) +end + +-- Callback Functions -- + +-- Client Callback +function QBCore.Functions.CreateClientCallback(name, cb) + QBCore.ClientCallbacks[name] = cb +end + +function QBCore.Functions.TriggerClientCallback(name, cb, ...) + if not QBCore.ClientCallbacks[name] then return end + QBCore.ClientCallbacks[name](cb, ...) +end + +-- Server Callback +function QBCore.Functions.TriggerCallback(name, cb, ...) + QBCore.ServerCallbacks[name] = cb + TriggerServerEvent('QBCore:Server:TriggerCallback', name, ...) +end + +function QBCore.Functions.Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel) + if GetResourceState('progressbar') ~= 'started' then error('progressbar needs to be started in order for QBCore.Functions.Progressbar to work') end + exports['progressbar']:Progress({ + name = name:lower(), + duration = duration, + label = label, + useWhileDead = useWhileDead, + canCancel = canCancel, + controlDisables = disableControls, + animation = animation, + prop = prop, + propTwo = propTwo, + }, function(cancelled) + if not cancelled then + if onFinish then + onFinish() + end + else + if onCancel then + onCancel() + end + end + end) +end + +-- Getters + +function QBCore.Functions.GetVehicles() + return GetGamePool('CVehicle') +end + +function QBCore.Functions.GetObjects() + return GetGamePool('CObject') +end + +function QBCore.Functions.GetPlayers() + return GetActivePlayers() +end + +function QBCore.Functions.GetPeds(ignoreList) + local pedPool = GetGamePool('CPed') + local peds = {} + ignoreList = ignoreList or {} + for i = 1, #pedPool, 1 do + local found = false + for j = 1, #ignoreList, 1 do + if ignoreList[j] == pedPool[i] then + found = true + end + end + if not found then + peds[#peds + 1] = pedPool[i] + end + end + return peds +end + +function QBCore.Functions.GetClosestPed(coords, ignoreList) + local ped = PlayerPedId() + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + ignoreList = ignoreList or {} + local peds = QBCore.Functions.GetPeds(ignoreList) + local closestDistance = -1 + local closestPed = -1 + for i = 1, #peds, 1 do + local pedCoords = GetEntityCoords(peds[i]) + local distance = #(pedCoords - coords) + + if closestDistance == -1 or closestDistance > distance then + closestPed = peds[i] + closestDistance = distance + end + end + return closestPed, closestDistance +end + +function QBCore.Functions.IsWearingGloves() + local ped = PlayerPedId() + local armIndex = GetPedDrawableVariation(ped, 3) + local model = GetEntityModel(ped) + if model == `mp_m_freemode_01` then + if QBCore.Shared.MaleNoGloves[armIndex] then + return false + end + else + if QBCore.Shared.FemaleNoGloves[armIndex] then + return false + end + end + return true +end + +function QBCore.Functions.GetClosestPlayer(coords) + local ped = PlayerPedId() + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + local closestPlayers = QBCore.Functions.GetPlayersFromCoords(coords) + local closestDistance = -1 + local closestPlayer = -1 + for i = 1, #closestPlayers, 1 do + if closestPlayers[i] ~= PlayerId() and closestPlayers[i] ~= -1 then + local pos = GetEntityCoords(GetPlayerPed(closestPlayers[i])) + local distance = #(pos - coords) + + if closestDistance == -1 or closestDistance > distance then + closestPlayer = closestPlayers[i] + closestDistance = distance + end + end + end + return closestPlayer, closestDistance +end + +function QBCore.Functions.GetPlayersFromCoords(coords, distance) + local players = GetActivePlayers() + local ped = PlayerPedId() + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + distance = distance or 5 + local closePlayers = {} + for _, player in pairs(players) do + local target = GetPlayerPed(player) + local targetCoords = GetEntityCoords(target) + local targetdistance = #(targetCoords - coords) + if targetdistance <= distance then + closePlayers[#closePlayers + 1] = player + end + end + return closePlayers +end + +function QBCore.Functions.GetClosestVehicle(coords) + local ped = PlayerPedId() + local vehicles = GetGamePool('CVehicle') + local closestDistance = -1 + local closestVehicle = -1 + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + for i = 1, #vehicles, 1 do + local vehicleCoords = GetEntityCoords(vehicles[i]) + local distance = #(vehicleCoords - coords) + + if closestDistance == -1 or closestDistance > distance then + closestVehicle = vehicles[i] + closestDistance = distance + end + end + return closestVehicle, closestDistance +end + +function QBCore.Functions.GetClosestObject(coords) + local ped = PlayerPedId() + local objects = GetGamePool('CObject') + local closestDistance = -1 + local closestObject = -1 + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + for i = 1, #objects, 1 do + local objectCoords = GetEntityCoords(objects[i]) + local distance = #(objectCoords - coords) + if closestDistance == -1 or closestDistance > distance then + closestObject = objects[i] + closestDistance = distance + end + end + return closestObject, closestDistance +end + +function QBCore.Functions.GetClosestBone(entity, list) + local playerCoords, bone, coords, distance = GetEntityCoords(PlayerPedId()) + for _, element in pairs(list) do + local boneCoords = GetWorldPositionOfEntityBone(entity, element.id or element) + local boneDistance = #(playerCoords - boneCoords) + if not coords then + bone, coords, distance = element, boneCoords, boneDistance + elseif distance > boneDistance then + bone, coords, distance = element, boneCoords, boneDistance + end + end + if not bone then + bone = {id = GetEntityBoneIndexByName(entity, "bodyshell"), type = "remains", name = "bodyshell"} + coords = GetWorldPositionOfEntityBone(entity, bone.id) + distance = #(coords - playerCoords) + end + return bone, coords, distance +end + +function QBCore.Functions.GetBoneDistance(entity, boneType, boneIndex) + local bone + if boneType == 1 then + bone = GetPedBoneIndex(entity, boneIndex) + else + bone = GetEntityBoneIndexByName(entity, boneIndex) + end + local boneCoords = GetWorldPositionOfEntityBone(entity, bone) + local playerCoords = GetEntityCoords(PlayerPedId()) + return #(boneCoords - playerCoords) +end + +function QBCore.Functions.AttachProp(ped, model, boneId, x, y, z, xR, yR, zR, vertex) + local modelHash = type(model) == 'string' and GetHashKey(model) or model + local bone = GetPedBoneIndex(ped, boneId) + QBCore.Functions.LoadModel(modelHash) + local prop = CreateObject(modelHash, 1.0, 1.0, 1.0, 1, 1, 0) + AttachEntityToEntity(prop, ped, bone, x, y, z, xR, yR, zR, 1, 1, 0, 1, not vertex and 2 or 0, 1) + SetModelAsNoLongerNeeded(modelHash) + return prop +end + +-- Vehicle + +function QBCore.Functions.SpawnVehicle(model, cb, coords, isnetworked, teleportInto) + local ped = PlayerPedId() + model = type(model) == 'string' and GetHashKey(model) or model + if not IsModelInCdimage(model) then return end + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(ped) + end + isnetworked = isnetworked == nil or isnetworked + QBCore.Functions.LoadModel(model) + local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, isnetworked, false) + local netid = NetworkGetNetworkIdFromEntity(veh) + SetVehicleHasBeenOwnedByPlayer(veh, true) + SetNetworkIdCanMigrate(netid, true) + SetVehicleNeedsToBeHotwired(veh, false) + SetVehicleFuelLevel(veh, 100.0) + SetModelAsNoLongerNeeded(model) + if teleportInto then TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1) end + TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh)) + if cb then cb(veh) end +end + +function QBCore.Functions.DeleteVehicle(vehicle) + SetEntityAsMissionEntity(vehicle, true, true) + DeleteVehicle(vehicle) +end + +function QBCore.Functions.GetPlate(vehicle) + if vehicle == 0 then return end + return QBCore.Shared.Trim(GetVehicleNumberPlateText(vehicle)) +end + +function QBCore.Functions.GetVehicleLabel(vehicle) + if vehicle == nil or vehicle == 0 then return end + return GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))) +end + +function QBCore.Functions.SpawnClear(coords, radius) + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(PlayerPedId()) + end + local vehicles = GetGamePool('CVehicle') + local closeVeh = {} + for i = 1, #vehicles, 1 do + local vehicleCoords = GetEntityCoords(vehicles[i]) + local distance = #(vehicleCoords - coords) + if distance <= radius then + closeVeh[#closeVeh + 1] = vehicles[i] + end + end + if #closeVeh > 0 then return false end + return true +end + +function QBCore.Functions.GetVehicleProperties(vehicle) + if DoesEntityExist(vehicle) then + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + local colorPrimary, colorSecondary = GetVehicleColours(vehicle) + + if GetVehicleXenonLightsCustomColor(vehicle) == 1 then + local _, r, g, b = GetVehicleXenonLightsCustomColor(vehicle) + headlightColor = { r, g, b } + else + headlightColor = GetVehicleHeadlightsColour(vehicle) + end + if GetIsVehiclePrimaryColourCustom(vehicle) then + local r, g, b = GetVehicleCustomPrimaryColour(vehicle) + colorPrimary = { r, g, b, colorPrimary } + end + if GetIsVehicleSecondaryColourCustom(vehicle) then + local r, g, b = GetVehicleCustomSecondaryColour(vehicle) + colorSecondary = { r, g, b, colorSecondary } + end + local extras = {} + for extraId = 0, 12 do + if DoesExtraExist(vehicle, extraId) then + local state = IsVehicleExtraTurnedOn(vehicle, extraId) == 1 + extras[tostring(extraId)] = state + end + end + local modLivery = GetVehicleMod(vehicle, 48) + if GetVehicleMod(vehicle, 48) == -1 and GetVehicleLivery(vehicle) ~= 0 then modLivery = GetVehicleLivery(vehicle) end + local tireHealth = {} + local tireBurstState = {} + local tireBurstCompletely = {} + for _, id in pairs({0, 1, 2, 3, 4, 5, 45, 47}) do + tireHealth[id] = GetVehicleWheelHealth(vehicle, id, false) + tireBurstState[id] = IsVehicleTyreBurst(vehicle, id, false) + tireBurstCompletely[id] = IsVehicleTyreBurst(vehicle, id, true) + end + local windowStatus = {} + for i = 0, 7 do windowStatus[i] = IsVehicleWindowIntact(vehicle, i) == 1 end + local doorStatus = {} + for i = 0, 5 do doorStatus[i] = IsVehicleDoorDamaged(vehicle, i) == 1 end + return { + model = GetEntityModel(vehicle), + plate = QBCore.Functions.GetPlate(vehicle), + plateIndex = GetVehicleNumberPlateTextIndex(vehicle), + bodyHealth = QBCore.Shared.Round(GetVehicleBodyHealth(vehicle), 0.1), + engineHealth = QBCore.Shared.Round(GetVehicleEngineHealth(vehicle), 0.1), + tankHealth = QBCore.Shared.Round(GetVehiclePetrolTankHealth(vehicle), 0.1), + fuelLevel = QBCore.Shared.Round(GetVehicleFuelLevel(vehicle), 0.1), + dirtLevel = QBCore.Shared.Round(GetVehicleDirtLevel(vehicle), 0.1), + oilLevel = QBCore.Shared.Round(GetVehicleOilLevel(vehicle), 0.1), + color1 = colorPrimary, + color2 = colorSecondary, + pearlescentColor = pearlescentColor, + dashboardColor = GetVehicleDashboardColour(vehicle), + wheelColor = wheelColor, + wheels = GetVehicleWheelType(vehicle), + wheelSize = GetVehicleWheelSize(vehicle), + wheelWidth = GetVehicleWheelWidth(vehicle), + tireHealth = tireHealth, + tireBurstState = tireBurstState, + tireBurstCompletely = tireBurstCompletely, + windowTint = GetVehicleWindowTint(vehicle), + windowStatus = windowStatus, + doorStatus = doorStatus, + headlightColor = headlightColor, + neonEnabled = { + IsVehicleNeonLightEnabled(vehicle, 0), + IsVehicleNeonLightEnabled(vehicle, 1), + IsVehicleNeonLightEnabled(vehicle, 2), + IsVehicleNeonLightEnabled(vehicle, 3) + }, + neonColor = table.pack(GetVehicleNeonLightsColour(vehicle)), + interiorColor = GetVehicleInteriorColour(vehicle), + extras = extras, + tyreSmokeColor = table.pack(GetVehicleTyreSmokeColor(vehicle)), + modSpoilers = GetVehicleMod(vehicle, 0), + modFrontBumper = GetVehicleMod(vehicle, 1), + modRearBumper = GetVehicleMod(vehicle, 2), + modSideSkirt = GetVehicleMod(vehicle, 3), + modExhaust = GetVehicleMod(vehicle, 4), + modFrame = GetVehicleMod(vehicle, 5), + modGrille = GetVehicleMod(vehicle, 6), + modHood = GetVehicleMod(vehicle, 7), + modFender = GetVehicleMod(vehicle, 8), + modRightFender = GetVehicleMod(vehicle, 9), + modRoof = GetVehicleMod(vehicle, 10), + modEngine = GetVehicleMod(vehicle, 11), + modBrakes = GetVehicleMod(vehicle, 12), + modTransmission = GetVehicleMod(vehicle, 13), + modHorns = GetVehicleMod(vehicle, 14), + modSuspension = GetVehicleMod(vehicle, 15), + modArmor = GetVehicleMod(vehicle, 16), + modKit17 = GetVehicleMod(vehicle, 17), + modTurbo = IsToggleModOn(vehicle, 18), + modKit19 = GetVehicleMod(vehicle, 19), + modSmokeEnabled = IsToggleModOn(vehicle, 20), + modKit21 = GetVehicleMod(vehicle, 21), + modXenon = IsToggleModOn(vehicle, 22), + modFrontWheels = GetVehicleMod(vehicle, 23), + modBackWheels = GetVehicleMod(vehicle, 24), + modCustomTiresF = GetVehicleModVariation(vehicle, 23), + modCustomTiresR = GetVehicleModVariation(vehicle, 24), + modPlateHolder = GetVehicleMod(vehicle, 25), + modVanityPlate = GetVehicleMod(vehicle, 26), + modTrimA = GetVehicleMod(vehicle, 27), + modOrnaments = GetVehicleMod(vehicle, 28), + modDashboard = GetVehicleMod(vehicle, 29), + modDial = GetVehicleMod(vehicle, 30), + modDoorSpeaker = GetVehicleMod(vehicle, 31), + modSeats = GetVehicleMod(vehicle, 32), + modSteeringWheel = GetVehicleMod(vehicle, 33), + modShifterLeavers = GetVehicleMod(vehicle, 34), + modAPlate = GetVehicleMod(vehicle, 35), + modSpeakers = GetVehicleMod(vehicle, 36), + modTrunk = GetVehicleMod(vehicle, 37), + modHydrolic = GetVehicleMod(vehicle, 38), + modEngineBlock = GetVehicleMod(vehicle, 39), + modAirFilter = GetVehicleMod(vehicle, 40), + modStruts = GetVehicleMod(vehicle, 41), + modArchCover = GetVehicleMod(vehicle, 42), + modAerials = GetVehicleMod(vehicle, 43), + modTrimB = GetVehicleMod(vehicle, 44), + modTank = GetVehicleMod(vehicle, 45), + modWindows = GetVehicleMod(vehicle, 46), + modKit47 = GetVehicleMod(vehicle, 47), + modLivery = modLivery, + modKit49 = GetVehicleMod(vehicle, 49), + liveryRoof = GetVehicleRoofLivery(vehicle), + modDrift = GetDriftTyresEnabled(vehicle), + modBProofTires = not GetVehicleTyresCanBurst(vehicle), + } + else + return + end +end + +function QBCore.Functions.SetVehicleProperties(vehicle, props) + if DoesEntityExist(vehicle) then + if props.extras then + for id, enabled in pairs(props.extras) do + if enabled then SetVehicleExtra(vehicle, tonumber(id), 0) + else SetVehicleExtra(vehicle, tonumber(id), 1) + end + end + end + local colorPrimary, colorSecondary = GetVehicleColours(vehicle) + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + SetVehicleModKit(vehicle, 0) + if props.plate then SetVehicleNumberPlateText(vehicle, props.plate) end + if props.plateIndex then SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex) end + if props.bodyHealth then SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0) end + if props.engineHealth then SetVehicleEngineHealth(vehicle, props.engineHealth + 0.0) end + if props.tankHealth then SetVehiclePetrolTankHealth(vehicle, props.tankHealth) end + if props.fuelLevel then SetVehicleFuelLevel(vehicle, props.fuelLevel + 0.0) end + if props.dirtLevel then SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0) end + if props.oilLevel then SetVehicleOilLevel(vehicle, props.oilLevel) end + if props.color1 then + if type(props.color1) == "number" then + ClearVehicleCustomPrimaryColour(vehicle) + colorPrimary = props.color1 + SetVehicleColours(vehicle, colorPrimary, colorSecondary) + else + colorPrimary = props.color1[4] + SetVehicleCustomPrimaryColour(vehicle, props.color1[1], props.color1[2], props.color1[3]) + SetVehicleColours(vehicle, props.color1[4], colorSecondary) + end + end + if props.color2 then + if type(props.color2) == "number" then + ClearVehicleCustomSecondaryColour(vehicle) + SetVehicleColours(vehicle, colorPrimary, props.color2) + else + SetVehicleCustomSecondaryColour(vehicle, props.color2[1], props.color2[2], props.color2[3]) + SetVehicleColours(vehicle, colorPrimary, props.color2[4]) + end + end + if props.pearlescentColor then SetVehicleExtraColours(vehicle, props.pearlescentColor, wheelColor) end + if props.interiorColor then SetVehicleInteriorColor(vehicle, props.interiorColor) end + if props.dashboardColor then SetVehicleDashboardColour(vehicle, props.dashboardColor) end + if props.wheelColor then SetVehicleExtraColours(vehicle, props.pearlescentColor or pearlescentColor, props.wheelColor) end + if props.wheels then SetVehicleWheelType(vehicle, props.wheels) end + if props.tireHealth then + for wheelIndex, health in pairs(props.tireHealth) do + SetVehicleWheelHealth(vehicle, wheelIndex, health) + end + end + if props.tireBurstState then + for wheelIndex, burstState in pairs(props.tireBurstState) do + if burstState then + SetVehicleTyreBurst(vehicle, tonumber(wheelIndex), false, 1000.0) + end + end + end + if props.tireBurstCompletely then + for wheelIndex, burstState in pairs(props.tireBurstCompletely) do + if burstState then + SetVehicleTyreBurst(vehicle, tonumber(wheelIndex), true, 1000.0) + end + end + end + if props.windowTint then SetVehicleWindowTint(vehicle, props.windowTint) end + if props.windowStatus then + for windowIndex, smashWindow in pairs(props.windowStatus) do + if not smashWindow then SmashVehicleWindow(vehicle, windowIndex) end + end + end + if props.doorStatus then + for doorIndex, breakDoor in pairs(props.doorStatus) do + if breakDoor then + SetVehicleDoorBroken(vehicle, tonumber(doorIndex), true) + end + end + end + if props.neonEnabled then + SetVehicleNeonLightEnabled(vehicle, 0, props.neonEnabled[1]) + SetVehicleNeonLightEnabled(vehicle, 1, props.neonEnabled[2]) + SetVehicleNeonLightEnabled(vehicle, 2, props.neonEnabled[3]) + SetVehicleNeonLightEnabled(vehicle, 3, props.neonEnabled[4]) + end + if props.neonColor then SetVehicleNeonLightsColour(vehicle, props.neonColor[1], props.neonColor[2], props.neonColor[3]) end + if props.headlightColor then + if type(props.headlightColor) == "number" then ClearVehicleXenonLightsCustomColor(vehicle) SetVehicleXenonLightsColor(vehicle, props.headlightColor) + else SetVehicleXenonLightsCustomColor(vehicle, props.headlightColor[1], props.headlightColor[2], props.headlightColor[3]) SetVehicleXenonLightsColor(vehicle, -1) end + end + if props.interiorColor then SetVehicleInteriorColour(vehicle, props.interiorColor) end + if props.wheelSize then SetVehicleWheelSize(vehicle, props.wheelSize) end + if props.wheelWidth then SetVehicleWheelWidth(vehicle, props.wheelWidth) end + if props.tyreSmokeColor then SetVehicleTyreSmokeColor(vehicle, props.tyreSmokeColor[1], props.tyreSmokeColor[2], props.tyreSmokeColor[3]) end + if props.modSpoilers then SetVehicleMod(vehicle, 0, props.modSpoilers, false) end + if props.modFrontBumper then SetVehicleMod(vehicle, 1, props.modFrontBumper, false) end + if props.modRearBumper then SetVehicleMod(vehicle, 2, props.modRearBumper, false) end + if props.modSideSkirt then SetVehicleMod(vehicle, 3, props.modSideSkirt, false) end + if props.modExhaust then SetVehicleMod(vehicle, 4, props.modExhaust, false) end + if props.modFrame then SetVehicleMod(vehicle, 5, props.modFrame, false) end + if props.modGrille then SetVehicleMod(vehicle, 6, props.modGrille, false) end + if props.modHood then SetVehicleMod(vehicle, 7, props.modHood, false) end + if props.modFender then SetVehicleMod(vehicle, 8, props.modFender, false) end + if props.modRightFender then SetVehicleMod(vehicle, 9, props.modRightFender, false) end + if props.modRoof then SetVehicleMod(vehicle, 10, props.modRoof, false) end + if props.modEngine then SetVehicleMod(vehicle, 11, props.modEngine, false) end + if props.modBrakes then SetVehicleMod(vehicle, 12, props.modBrakes, false) end + if props.modTransmission then SetVehicleMod(vehicle, 13, props.modTransmission, false) end + if props.modHorns then SetVehicleMod(vehicle, 14, props.modHorns, false) end + if props.modSuspension then SetVehicleMod(vehicle, 15, props.modSuspension, false) end + if props.modArmor then SetVehicleMod(vehicle, 16, props.modArmor, false) end + if props.modKit17 then SetVehicleMod(vehicle, 17, props.modKit17, false) end + if props.modTurbo then ToggleVehicleMod(vehicle, 18, props.modTurbo) end + if props.modKit19 then SetVehicleMod(vehicle, 19, props.modKit19, false) end + if props.modSmokeEnabled then ToggleVehicleMod(vehicle, 20, props.modSmokeEnabled) end + if props.modKit21 then SetVehicleMod(vehicle, 21, props.modKit21, false) end + if props.modXenon then ToggleVehicleMod(vehicle, 22, props.modXenon) end + if props.modFrontWheels then SetVehicleMod(vehicle, 23, props.modFrontWheels, false) end + if props.modBackWheels then SetVehicleMod(vehicle, 24, props.modBackWheels, false) end + if props.modCustomTiresF then SetVehicleMod(vehicle, 23, props.modFrontWheels, props.modCustomTiresF) end + if props.modCustomTiresR then SetVehicleMod(vehicle, 24, props.modBackWheels, props.modCustomTiresR) end + if props.modPlateHolder then SetVehicleMod(vehicle, 25, props.modPlateHolder, false) end + if props.modVanityPlate then SetVehicleMod(vehicle, 26, props.modVanityPlate, false) end + if props.modTrimA then SetVehicleMod(vehicle, 27, props.modTrimA, false) end + if props.modOrnaments then SetVehicleMod(vehicle, 28, props.modOrnaments, false) end + if props.modDashboard then SetVehicleMod(vehicle, 29, props.modDashboard, false) end + if props.modDial then SetVehicleMod(vehicle, 30, props.modDial, false) end + if props.modDoorSpeaker then SetVehicleMod(vehicle, 31, props.modDoorSpeaker, false) end + if props.modSeats then SetVehicleMod(vehicle, 32, props.modSeats, false) end + if props.modSteeringWheel then SetVehicleMod(vehicle, 33, props.modSteeringWheel, false) end + if props.modShifterLeavers then SetVehicleMod(vehicle, 34, props.modShifterLeavers, false) end + if props.modAPlate then SetVehicleMod(vehicle, 35, props.modAPlate, false) end + if props.modSpeakers then SetVehicleMod(vehicle, 36, props.modSpeakers, false) end + if props.modTrunk then SetVehicleMod(vehicle, 37, props.modTrunk, false) end + if props.modHydrolic then SetVehicleMod(vehicle, 38, props.modHydrolic, false) end + if props.modEngineBlock then SetVehicleMod(vehicle, 39, props.modEngineBlock, false) end + if props.modAirFilter then SetVehicleMod(vehicle, 40, props.modAirFilter, false) end + if props.modStruts then SetVehicleMod(vehicle, 41, props.modStruts, false) end + if props.modArchCover then SetVehicleMod(vehicle, 42, props.modArchCover, false) end + if props.modAerials then SetVehicleMod(vehicle, 43, props.modAerials, false) end + if props.modTrimB then SetVehicleMod(vehicle, 44, props.modTrimB, false) end + if props.modTank then SetVehicleMod(vehicle, 45, props.modTank, false) end + if props.modWindows then SetVehicleMod(vehicle, 46, props.modWindows, false) end + if props.modKit47 then SetVehicleMod(vehicle, 47, props.modKit47, false) end + if props.modLivery then SetVehicleMod(vehicle, 48, props.modLivery, false) SetVehicleLivery(vehicle, props.modLivery) end + if props.modKit49 then SetVehicleMod(vehicle, 49, props.modKit49, false) end + if props.liveryRoof then SetVehicleRoofLivery(vehicle, props.liveryRoof) end + if props.modDrift then SetDriftTyresEnabled(vehicle, true) end + SetVehicleTyresCanBurst(vehicle, not props.modBProofTires) + TriggerServerEvent('jim-mechanic:server:loadStatus', props, VehToNet(vehicle)) + end +end + +function QBCore.Functions.LoadParticleDictionary(dictionary) + if HasNamedPtfxAssetLoaded(dictionary) then return end + RequestNamedPtfxAsset(dictionary) + while not HasNamedPtfxAssetLoaded(dictionary) do + Wait(0) + end +end + +function QBCore.Functions.StartParticleAtCoord(dict, ptName, looped, coords, rot, scale, alpha, color, duration) + if coords then + coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords + else + coords = GetEntityCoords(PlayerPedId()) + end + QBCore.Functions.LoadParticleDictionary(dict) + UseParticleFxAssetNextCall(dict) + SetPtfxAssetNextCall(dict) + local particleHandle + if looped then + particleHandle = StartParticleFxLoopedAtCoord(ptName, coords.x, coords.y, coords.z, rot.x, rot.y, rot.z, scale or 1.0) + if color then + SetParticleFxLoopedColour(particleHandle, color.r, color.g, color.b, false) + end + SetParticleFxLoopedAlpha(particleHandle, alpha or 10.0) + if duration then + Wait(duration) + StopParticleFxLooped(particleHandle, 0) + end + else + SetParticleFxNonLoopedAlpha(alpha or 10.0) + if color then + SetParticleFxNonLoopedColour(color.r, color.g, color.b) + end + StartParticleFxNonLoopedAtCoord(ptName, coords.x, coords.y, coords.z, rot.x, rot.y, rot.z, scale or 1.0) + end + return particleHandle +end + +function QBCore.Functions.StartParticleOnEntity(dict, ptName, looped, entity, bone, offset, rot, scale, alpha, color, evolution, duration) + QBCore.Functions.LoadParticleDictionary(dict) + UseParticleFxAssetNextCall(dict) + local particleHandle, boneID + if bone and GetEntityType(entity) == 1 then + boneID = GetPedBoneIndex(entity, bone) + elseif bone then + boneID = GetEntityBoneIndexByName(entity, bone) + end + if looped then + if bone then + particleHandle = StartParticleFxLoopedOnEntityBone(ptName, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, boneID, scale) + else + particleHandle = StartParticleFxLoopedOnEntity(ptName, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, scale) + end + if evolution then + SetParticleFxLoopedEvolution(particleHandle, evolution.name, evolution.amount, false) + end + if color then + SetParticleFxLoopedColour(particleHandle, color.r, color.g, color.b, false) + end + SetParticleFxLoopedAlpha(particleHandle, alpha) + if duration then + Wait(duration) + StopParticleFxLooped(particleHandle, 0) + end + else + SetParticleFxNonLoopedAlpha(alpha or 10.0) + if color then + SetParticleFxNonLoopedColour(color.r, color.g, color.b) + end + if bone then + StartParticleFxNonLoopedOnPedBone(ptName, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, boneID, scale) + else + StartParticleFxNonLoopedOnEntity(ptName, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, scale) + end + end + return particleHandle +end + +function QBCore.Functions.GetStreetNametAtCoords(coords) + local streetname1, streetname2 = GetStreetNameAtCoord(coords.x, coords.y, coords.z) + return { main = GetStreetNameFromHashKey(streetname1), cross = GetStreetNameFromHashKey(streetname2) } +end + +function QBCore.Functions.GetZoneAtCoords(coords) + return GetLabelText(GetNameOfZone(coords)) +end + +function QBCore.Functions.GetCardinalDirection(entity) + entity = DoesEntityExist(entity) and entity or PlayerPedId() + if DoesEntityExist(entity) then + local heading = GetEntityHeading(entity) + if ((heading >= 0 and heading < 45) or (heading >= 315 and heading < 360)) then + return "North" + elseif (heading >= 45 and heading < 135) then + return "West" + elseif (heading >= 135 and heading < 225) then + return "South" + elseif (heading >= 225 and heading < 315) then + return "East" + end + else + return "Cardinal Direction Error" + end +end + +function QBCore.Functions.GetCurrentTime() + local obj = {} + obj.min = GetClockMinutes() + obj.hour = GetClockHours() + + if obj.hour <= 12 then + obj.ampm = "AM" + elseif obj.hour >= 13 then + obj.ampm = "PM" + obj.formattedHour = obj.hour - 12 + end + + if obj.min <= 9 then + obj.formattedMin = "0" .. obj.min + end + + return obj +end + +function QBCore.Functions.GetGroundZCoord(coords) + if not coords then return end + + local retval, groundZ = GetGroundZFor_3dCoord(coords.x, coords.y, coords.z, 0) + if retval then + return vector3(coords.x, coords.y, groundZ) + else + print('Couldn\'t find Ground Z Coordinates given 3D Coordinates') + print(coords) + return coords + end +end + +function QBCore.Functions.GetGroundHash(entity) + local coords = GetEntityCoords(entity) + local num = StartShapeTestCapsule(coords.x, coords.y, coords.z + 4, coords.x, coords.y, coords.z - 2.0, 1, 1, entity, 7) + local retval, success, endCoords, surfaceNormal, materialHash, entityHit = GetShapeTestResultEx(num) + return materialHash, entityHit, surfaceNormal, endCoords, success, retval +end \ No newline at end of file diff --git a/resources/[qb]/qb-core/client/loops.lua b/resources/[qb]/qb-core/client/loops.lua new file mode 100644 index 0000000..6f3770d --- /dev/null +++ b/resources/[qb]/qb-core/client/loops.lua @@ -0,0 +1,24 @@ +CreateThread(function() + while true do + local sleep = 0 + if LocalPlayer.state.isLoggedIn then + sleep = (1000 * 60) * QBCore.Config.UpdateInterval + TriggerServerEvent('QBCore:UpdatePlayer') + end + Wait(sleep) + end +end) + +CreateThread(function() + while true do + if LocalPlayer.state.isLoggedIn then + if (QBCore.PlayerData.metadata['hunger'] <= 0 or QBCore.PlayerData.metadata['thirst'] <= 0) and not (QBCore.PlayerData.metadata['isdead'] or QBCore.PlayerData.metadata["inlaststand"]) then + local ped = PlayerPedId() + local currentHealth = GetEntityHealth(ped) + local decreaseThreshold = math.random(5, 10) + SetEntityHealth(ped, currentHealth - decreaseThreshold) + end + end + Wait(QBCore.Config.StatusInterval) + end +end) diff --git a/resources/[qb]/qb-core/client/main.lua b/resources/[qb]/qb-core/client/main.lua new file mode 100644 index 0000000..7407a6d --- /dev/null +++ b/resources/[qb]/qb-core/client/main.lua @@ -0,0 +1,14 @@ +QBCore = {} +QBCore.PlayerData = {} +QBCore.Config = QBConfig +QBCore.Shared = QBShared +QBCore.ClientCallbacks = {} +QBCore.ServerCallbacks = {} + +exports('GetCoreObject', function() + return QBCore +end) + +-- To use this export in a script instead of manifest method +-- Just put this line of code below at the very top of the script +-- local QBCore = exports['qb-core']:GetCoreObject() diff --git a/resources/[qb]/qb-core/config.lua b/resources/[qb]/qb-core/config.lua new file mode 100644 index 0000000..0adcbb9 --- /dev/null +++ b/resources/[qb]/qb-core/config.lua @@ -0,0 +1,64 @@ +QBConfig = {} + +QBConfig.MaxPlayers = GetConvarInt('sv_maxclients', 48) -- Gets max players from config file, default 48 +QBConfig.DefaultSpawn = vector4(297.95, -587.53, 49.75, 71.92) +QBConfig.UpdateInterval = 5 -- how often to update player data in minutes +QBConfig.StatusInterval = 5000 -- how often to check hunger/thirst status in milliseconds + +QBConfig.Money = {} +QBConfig.Money.MoneyTypes = { cash = 500, bank = 5000, crypto = 0 } -- type = startamount - Add or remove money types for your server (for ex. blackmoney = 0), remember once added it will not be removed from the database! +QBConfig.Money.DontAllowMinus = { 'cash', 'crypto', 'bank' } -- Money that is not allowed going in minus +QBConfig.Money.PayCheckTimeOut = 10 -- The time in minutes that it will give the paycheck +QBConfig.Money.PayCheckSociety = true -- If true paycheck will come from the society account that the player is employed at, requires qb-management + +QBConfig.Player = {} +QBConfig.Player.HungerRate = 7.2 -- Rate at which hunger goes down. +QBConfig.Player.ThirstRate = 6.8 -- Rate at which thirst goes down. +QBConfig.Player.Bloodtypes = { + "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-", +} + +QBConfig.Server = {} -- General server config +QBConfig.Server.Closed = false -- Set server closed (no one can join except people with ace permission 'qbadmin.join') +QBConfig.Server.ClosedReason = "Server Closed" -- Reason message to display when people can't join the server +QBConfig.Server.Uptime = 0 -- Time the server has been up. +QBConfig.Server.Whitelist = false -- Enable or disable whitelist on the server +QBConfig.Server.WhitelistPermission = 'admin' -- Permission that's able to enter the server when the whitelist is on +QBConfig.Server.PVP = true -- Enable or disable pvp on the server (Ability to shoot other players) +QBConfig.Server.Discord = "discord.gg/4d3NCeH3hW" -- Discord invite link +QBConfig.Server.CheckDuplicateLicense = true -- Check for duplicate rockstar license on join +QBConfig.Server.Permissions = { 'god', 'admin', 'mod' } -- Add as many groups as you want here after creating them in your server.cfg + +QBConfig.Notify = {} + +QBConfig.Notify.NotificationStyling = { + group = false, -- Allow notifications to stack with a badge instead of repeating + position = "right", -- top-left | top-right | bottom-left | bottom-right | top | bottom | left | right | center + progress = true -- Display Progress Bar +} + +-- These are how you define different notification variants +-- The "color" key is background of the notification +-- The "icon" key is the css-icon code, this project uses `Material Icons` & `Font Awesome` +QBConfig.Notify.VariantDefinitions = { + success = { + classes = 'success', + icon = 'done' + }, + primary = { + classes = 'primary', + icon = 'info' + }, + error = { + classes = 'error', + icon = 'dangerous' + }, + police = { + classes = 'police', + icon = 'local_police' + }, + ambulance = { + classes = 'ambulance', + icon = 'fas fa-ambulance' + } +} diff --git a/resources/[qb]/qb-core/fxmanifest.lua b/resources/[qb]/qb-core/fxmanifest.lua new file mode 100644 index 0000000..c397379 --- /dev/null +++ b/resources/[qb]/qb-core/fxmanifest.lua @@ -0,0 +1,51 @@ +fx_version 'cerulean' +game 'gta5' + +version 'V1.0' + +shared_scripts { + 'config.lua', + 'shared/locale.lua', + 'locale/en.lua', + 'locale/*.lua', + 'shared/main.lua', + 'shared/items.lua', + 'shared/jobs.lua', + 'shared/vehicles.lua', + 'shared/gangs.lua', + 'shared/weapons.lua', + 'shared/locations.lua', + '@ox_lib/init.lua', +} + +client_scripts { + 'client/main.lua', + 'client/functions.lua', + 'client/loops.lua', + 'client/events.lua', + 'client/drawtext.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server/main.lua', + 'server/functions.lua', + 'server/player.lua', + 'server/events.lua', + 'server/commands.lua', + 'server/exports.lua', + 'server/debug.lua' +} + +ui_page 'html/index.html' + +files { + 'html/index.html', + 'html/css/style.css', + 'html/css/drawtext.css', + 'html/js/*.js' +} + +dependency 'oxmysql' + +lua54 'yes' diff --git a/resources/[qb]/qb-core/html/css/drawtext.css b/resources/[qb]/qb-core/html/css/drawtext.css new file mode 100644 index 0000000..5fbecdb --- /dev/null +++ b/resources/[qb]/qb-core/html/css/drawtext.css @@ -0,0 +1,98 @@ +@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap"); + +:root { + --primary-bg: rgba(23, 23, 23, 90%); + --active-bg: #dc143c; + --font-color: white; +} + +#drawtext-container { + display: none; + width: 100%; + height: 100%; + overflow: hidden; + padding: 0; + margin: 0; + font-family: "Poppins", sans-serif !important; + font-weight: 300; + border-radius: 15px; +} + +.text { + position: absolute; + background: var(--primary-bg); + color: var(--font-color); + margin-top: 0.5rem; + padding: 0.45rem; + border-radius: 0.15rem; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; +} + +@media (width: 3840px) and (height: 2160px) { + #drawtext-container { + display: none; + width: 100%; + height: 100%; + overflow: hidden; + padding: 0; + margin: 0; + font-family: "Poppins", sans-serif !important; + font-weight: 300; + font-size: 1.5vh; + } +} + +.text.pressed { + background: var(--active-bg); +} + +.top { + left: 45vw; + top: -100px; +} + +.top.show { + transition: 0.5s; + top: 10px; + opacity: 1; +} + +.top.hide { + transition: 0.5s; + top: -100px; + opacity: 0; +} + +.right { + top: 50%; + right: -100px; +} + +.right.show { + transition: 0.5s; + right: 10px; + opacity: 1; +} + +.right.hide { + transition: 0.5s; + right: -100px; + opacity: 0; +} + +.left { + top: 50%; + left: -100px; +} + +.left.show { + transition: 0.5s; + left: 10px; + opacity: 1; +} + +.left.hide { + transition: 0.5s; + left: -100px; + opacity: 0; +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/html/css/style.css b/resources/[qb]/qb-core/html/css/style.css new file mode 100644 index 0000000..357b04e --- /dev/null +++ b/resources/[qb]/qb-core/html/css/style.css @@ -0,0 +1,81 @@ +html::-webkit-scrollbar { + display: none; +} + +@media (width: 3840px) and (height: 2160px) { + .success { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 0.5rem solid #20bb44; + font-size: 1.5vh; + } + + .primary { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #1c75d2; + font-size: 1.5vh; + } + + .error { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #c10114; + font-size: 1.5vh; + } + + .police { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #2197f2; + font-size: 1.5vh; + } + + .ambulance { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #f44236; + font-size: 1.5vh; + } + +} + +.success { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 0.5rem solid #20bb44; +} + +.primary { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #1c75d2; +} + +.error { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #c10114; +} + +.police { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #2197f2; +} + +.ambulance { + background-color: rgba(23, 23, 23, 90%); + border-radius: 10px; + box-shadow: 0rem 0rem 0.1rem 0.05rem #000000; + border-left: 5px solid #f44236; +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/html/index.html b/resources/[qb]/qb-core/html/index.html new file mode 100644 index 0000000..ee1875f --- /dev/null +++ b/resources/[qb]/qb-core/html/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/resources/[qb]/qb-core/html/js/app.js b/resources/[qb]/qb-core/html/js/app.js new file mode 100644 index 0000000..d13562e --- /dev/null +++ b/resources/[qb]/qb-core/html/js/app.js @@ -0,0 +1,65 @@ +import { registerWindowMethods } from "./testing.js"; +import { isEnvBrowser } from "./utils.js"; +import { + determineStyleFromVariant, + DEV_MODE, + fetchNotifyConfig, + NOTIFY_CONFIG, +} from "./config.js"; + +const { useQuasar } = Quasar; +const { onMounted, onUnmounted } = Vue; + +const app = Vue.createApp({ + setup() { + const $q = useQuasar(); + + const showNotif = async ({ data }) => { + // Otherwise we process any old MessageEvent with a data property + if (data?.action !== "notify") return; + + const { text, length, type, caption } = data; + const { classes, icon } = determineStyleFromVariant(type); + + // Make sure we have sucessfully fetched out config properly + if (!NOTIFY_CONFIG) { + console.error( + "The notification config did not load properly, trying again for next time" + ); + // Lets check again to see if it exists + await fetchNotifyConfig(); + // If we have a config lets re-run notification with same data, this + // isn't recursive though. + if (NOTIFY_CONFIG) return showNotif({ data }); + } + + $q.notify({ + message: text, + multiLine: text.length > 100, + // If our text is larger than a 100 characters, + // we should use multiline notifications + group: NOTIFY_CONFIG.NotificationStyling.group ?? false, + progress: NOTIFY_CONFIG.NotificationStyling.progress ?? true, + position: NOTIFY_CONFIG.NotificationStyling.position ?? "right", + timeout: length, + caption, + classes, + icon, + }); + }; + onMounted(() => { + window.addEventListener("message", showNotif); + }); + onUnmounted(() => { + window.removeEventListener("message", showNotif); + }); + return {}; + }, +}); + +app.use(Quasar, { config: {} }); +app.mount("#q-app"); + +if (DEV_MODE || isEnvBrowser()) { + registerWindowMethods(); +} diff --git a/resources/[qb]/qb-core/html/js/config.js b/resources/[qb]/qb-core/html/js/config.js new file mode 100644 index 0000000..32fa978 --- /dev/null +++ b/resources/[qb]/qb-core/html/js/config.js @@ -0,0 +1,46 @@ +import { fetchNui, isEnvBrowser } from "./utils.js"; +import { BrowserMockConfigData } from "./testing.js"; + +export const DEV_MODE = false; + +/** + * @typedef NotiVariantData + * @property {string} icon + * @property {string} color + **/ + +/** + * Will hold config statically outside of Vue state + * @property {Record} VariantDefinitions + * @property {Record} NotificationStyling + **/ +export let NOTIFY_CONFIG = null; + +/** + * Pure function taking a notification type and returning an object + * with style details + * @param {string} variant + * @returns NotiVariantData + **/ +export const determineStyleFromVariant = (variant) => { + const variantData = NOTIFY_CONFIG.VariantDefinitions[variant]; + if (!variantData) + throw new Error(`Style of type: ${variant}, does not exist in the config`); + return variantData; +}; + +// Fetch and set NOTIFY_CONFIG from client script callback +export const fetchNotifyConfig = async () => { + NOTIFY_CONFIG = await fetchNui("getNotifyConfig", {}, BrowserMockConfigData); + if (isEnvBrowser() || DEV_MODE) { + console.log("Fetched Config:"); + console.dir(NOTIFY_CONFIG); + } +}; + +// We specifically wait for all other files to load +// just in case of a race condition between client handlers +// and NUI fetch call +window.addEventListener("load", async () => { + await fetchNotifyConfig(); +}); diff --git a/resources/[qb]/qb-core/html/js/drawtext.js b/resources/[qb]/qb-core/html/js/drawtext.js new file mode 100644 index 0000000..975d6e1 --- /dev/null +++ b/resources/[qb]/qb-core/html/js/drawtext.js @@ -0,0 +1,124 @@ +let direction = null; + +const drawText = async (textData) => { + const text = document.getElementById("text"); + let {position} = textData; + switch (textData.position) { + case "left": + addClass(text, position); + direction = "left"; + break; + case "top": + addClass(text, position); + direction = "top"; + break; + case "right": + addClass(text, position); + direction = "right"; + break; + default: + addClass(text, "left"); + direction = "left"; + break; + } + + text.innerHTML = textData.text; + document.getElementById("drawtext-container").style.display = "block"; + await sleep(100); + addClass(text, "show"); +}; + +const changeText = async (textData) => { + const text = document.getElementById("text"); + let {position} = textData; + + removeClass(text, "show"); + addClass(text, "pressed"); + addClass(text, "hide"); + + await sleep(500); + removeClass(text, "left"); + removeClass(text, "right"); + removeClass(text, "top"); + removeClass(text, "bottom"); + removeClass(text, "hide"); + removeClass(text, "pressed"); + + switch (textData.position) { + case "left": + addClass(text, position); + direction = "left"; + break; + case "top": + addClass(text, position); + direction = "top"; + break; + case "right": + addClass(text, position); + direction = "right"; + break; + default: + addClass(text, "left"); + direction = "left"; + break; + } + text.innerHTML = textData.text; + + await sleep(100); + text.classList.add("show"); +}; + +const hideText = async () => { + const text = document.getElementById("text"); + removeClass(text, "show"); + addClass(text, "hide"); + + setTimeout(() => { + removeClass(text, "left"); + removeClass(text, "right"); + removeClass(text, "top"); + removeClass(text, "bottom"); + removeClass(text, "hide"); + removeClass(text, "pressed"); + document.getElementById("drawtext-container").style.display = "none"; + }, 1000); +}; + +const keyPressed = () => { + const text = document.getElementById("text"); + addClass(text, "pressed"); +}; + +window.addEventListener("message", (event) => { + const data = event.data; + const action = data.action; + const textData = data.data; + switch (action) { + case "DRAW_TEXT": + return drawText(textData); + case "CHANGE_TEXT": + return changeText(textData); + case "HIDE_TEXT": + return hideText(); + case "KEY_PRESSED": + return keyPressed(); + default: + return; + } +}); + +const sleep = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +const removeClass = (element, name) => { + if (element.classList.contains(name)) { + element.classList.remove(name); + } +}; + +const addClass = (element, name) => { + if (!element.classList.contains(name)) { + element.classList.add(name); + } +}; diff --git a/resources/[qb]/qb-core/html/js/testing.js b/resources/[qb]/qb-core/html/js/testing.js new file mode 100644 index 0000000..5181f57 --- /dev/null +++ b/resources/[qb]/qb-core/html/js/testing.js @@ -0,0 +1,44 @@ +// Will register dev utilities on window +export const registerWindowMethods = () => { + window.SendNotification = (data) => { + window.dispatchEvent( + new MessageEvent("message", { + data: { + action: "notify", + ...data, + }, + }) + ); + }; +}; + +// Used for browser env handling +export const BrowserMockConfigData = { + NotificationStyling: { + group: true, + position: "top-right", + progress: true, + }, + VariantDefinitions: { + success: { + classes: "success", + icon: "done", + }, + primary: { + classes: "primary", + icon: "info", + }, + error: { + classes: "error", + icon: "dangerous", + }, + police: { + classes: "police", + icon: "local_police", + }, + ambulance: { + classes: "ambulance", + icon: "fas fa-ambulance", + }, + }, +}; diff --git a/resources/[qb]/qb-core/html/js/utils.js b/resources/[qb]/qb-core/html/js/utils.js new file mode 100644 index 0000000..bf2fb8c --- /dev/null +++ b/resources/[qb]/qb-core/html/js/utils.js @@ -0,0 +1,27 @@ +// Returns whether we are in browser or not +export const isEnvBrowser = () => !window.invokeNative; + +/** + * Real simple wrapper around fetch api for NUI focus + * it will return the mockData param if we are in browser. So we don't + * make a useless request to a hostname that doesn't exist. + * @param evName {string} - The callback event name/type + * @param data {any} - Optional `body` data JSON stringified & passed with the request + * @param mockData {any} - Mock data to return if this is running in browser + * @return Promise + **/ +export const fetchNui = async (evName, data, mockData = null) => { + if (isEnvBrowser()) return mockData; + + const resourceName = window.GetParentResourceName(); + + const rawResp = await fetch(`https://${resourceName}/${evName}`, { + body: JSON.stringify(data), + headers: { + "Content-Type": "application/json; charset=UTF8", + }, + method: "POST", + }); + + return await rawResp.json(); +}; diff --git a/resources/[qb]/qb-core/locale/da.lua b/resources/[qb]/qb-core/locale/da.lua new file mode 100644 index 0000000..c6d1ec3 --- /dev/null +++ b/resources/[qb]/qb-core/locale/da.lua @@ -0,0 +1,129 @@ +local Translations = { + error = { + not_online = 'Spiller er ikke i byen', + wrong_format = 'Forkert format', + missing_args = 'Du mangler nogle argumenter (x, y, z)', + missing_args2 = 'Alle argumenter skal skrives ind!', + no_access = 'Du har ikke adgang til denne kommando', + company_too_poor = 'Din chef er fattig', + item_not_exist = 'Ting findes ikke', + too_heavy = 'Tasken er fyldt', + location_not_exist = 'Lokation eksisterer ikke', + duplicate_license = 'Duplicate Rockstar License Found', + no_valid_license = 'Intet gyldig Rockstar-licens fundet', + not_whitelisted = 'Du er ikke allowlistet på denne server', + server_already_open = 'Serveren er allerede åben', + server_already_closed = 'Serveren er allerede lukket', + no_permission = 'Du har ikke tilladelse til dette..', + no_waypoint = 'Ingen waypoint sat.', + tp_error = 'Fejl under teleportering.', + connecting_database_error = 'Der opstod en databasefejl under forbindelse til serveren. (Er SQL-serveren tændt?)', + connecting_database_timeout = 'Forbindelse til database udløbet. (Er SQL-serveren tændt?)', + }, + success = { + server_opened = 'Serveren blev åbnet', + server_closed = 'Serveren blev lukket', + teleported_waypoint = 'Teleporteret til waypoint.', + }, + info = { + received_paycheck = 'Du modtog din lønseddel på %{value},-', + job_info = 'Job: %{value} | Grad: %{value2} | Status: %{value3}', + gang_info = 'Bande: %{value} | Grad: %{value2}', + on_duty = 'Du er nu på vagt!', + off_duty = 'Du har nu fri!', + checking_ban = 'Hej %s. Vi kontrollerer, om du er bannet.', + join_server = 'Velkommen %s til {Server Name}.', + checking_whitelisted = 'Hej %s. Vi tjekker om du er allowlistet.', + exploit_banned = 'Du er blevet bannet for snyd. Tjek vores Discord for mere information: %{discord}', + exploit_dropped = 'Du er blevet kicket for snyd', + }, + command = { + tp = { + help = 'TP til spiller eller koordinater (Admin)', + params = { + x = { name = 'id/x', help = 'ID eller X koordinat'}, + y = { name = 'y', help = 'Y koordinat'}, + z = { name = 'z', help = 'Z koordinat'}, + }, + }, + tpm = { help = 'TP til markør (Admin)' }, + togglepvp = { help = 'Toggle PVP (Admin)' }, + addpermission = { + help = 'Giv spiller-permissions (God)', + params = { + id = { name = 'id', help = 'ID på spiller' }, + permission = { name = 'permission', help = 'Permission level' }, + }, + }, + removepermission = { + help = 'Fjern spiller-permissions (God)', + params = { + id = { name = 'id', help = 'ID på spiller' }, + permission = { name = 'permission', help = 'Permission level' }, + }, + }, + openserver = { help = 'Åben serveren for all (Admin)' }, + closeserver = { + help = 'Luk serveren for folk uden tilladelse (Admin)', + params = { + reason = { name = 'årset', help = 'Angiv en årsag' }, + }, + }, + car = { + help = 'Spawn køretøj (Admin)', + params = { + model = { name = 'model', help = 'Model-navn på køretøj' }, + }, + }, + dv = { help = 'Slet køretøj (Admin)' }, + givemoney = { + help = 'Giv spiller penge (Admin)', + params = { + id = { name = 'id', help = 'Player ID' }, + moneytype = { name = 'moneytype', help = 'Type of money (cash, bank, crypto)' }, + amount = { name = 'amount', help = 'Amount of money' }, + }, + }, + setmoney = { + help = 'Sæt spillers penge (Admin)', + params = { + id = { name = 'id', help = 'Spiller ID' }, + moneytype = { name = 'pengetype', help = 'cash, bank, crypto' }, + amount = { name = 'balance', help = 'Ny balance' }, + }, + }, + job = { help = 'Se dit job' }, + setjob = { + help = 'Sæt spillers job (Admin)', + params = { + id = { name = 'id', help = 'Spiller ID' }, + job = { name = 'job', help = 'Job navn' }, + grade = { name = 'grad', help = 'Job grad' }, + }, + }, + gang = { help = 'Se din bande' }, + setgang = { + help = 'Sæt spillers bande (Admin)', + params = { + id = { name = 'id', help = 'Spiller ID' }, + gang = { name = 'gang', help = 'Bange navn' }, + grade = { name = 'grad', help = 'Bande grad' }, + }, + }, + ooc = { help = 'OOC chat besked' }, + me = { + help = 'Vis lokal handling', + params = { + message = { name = 'handling', help = 'Beskriv hvad du gør' } + }, + }, + }, +} + +if GetConvar('qb_locale', 'en') == 'da' then + Lang = Locale:new({ + phrases = Translations, + warnOnMissing = true, + fallbackLang = Lang, + }) +end diff --git a/resources/[qb]/qb-core/locale/en.lua b/resources/[qb]/qb-core/locale/en.lua new file mode 100644 index 0000000..a8b4a5a --- /dev/null +++ b/resources/[qb]/qb-core/locale/en.lua @@ -0,0 +1,126 @@ +local Translations = { + error = { + not_online = 'Player not online', + wrong_format = 'Incorrect format', + missing_args = 'Not every argument has been entered (x, y, z)', + missing_args2 = 'All arguments must be filled out!', + no_access = 'No access to this command', + company_too_poor = 'Your employer is broke', + item_not_exist = 'Item does not exist', + too_heavy = 'Inventory too full', + location_not_exist = 'Location does not exist', + duplicate_license = 'Duplicate Rockstar License Found', + no_valid_license = 'No Valid Rockstar License Found', + not_whitelisted = 'You\'re not whitelisted for this server', + server_already_open = 'The server is already open', + server_already_closed = 'The server is already closed', + no_permission = 'You don\'t have permissions for this..', + no_waypoint = 'No Waypoint Set.', + tp_error = 'Error While Teleporting.', + connecting_database_error = 'A database error occurred while connecting to the server. (Is the SQL server on?)', + connecting_database_timeout = 'Connection to database timed out. (Is the SQL server on?)', + }, + success = { + server_opened = 'The server has been opened', + server_closed = 'The server has been closed', + teleported_waypoint = 'Teleported To Waypoint.', + }, + info = { + received_paycheck = 'You received your paycheck of $%{value}', + job_info = 'Job: %{value} | Grade: %{value2} | Duty: %{value3}', + gang_info = 'Gang: %{value} | Grade: %{value2}', + on_duty = 'You are now on duty!', + off_duty = 'You are now off duty!', + checking_ban = 'Hello %s. We are checking if you are banned.', + join_server = 'Welcome %s to {Server Name}.', + checking_whitelisted = 'Hello %s. We are checking your allowance.', + exploit_banned = 'You have been banned for cheating. Check our Discord for more information: %{discord}', + exploit_dropped = 'You Have Been Kicked For Exploitation', + }, + command = { + tp = { + help = 'TP To Player or Coords (Admin Only)', + params = { + x = { name = 'id/x', help = 'ID of player or X position'}, + y = { name = 'y', help = 'Y position'}, + z = { name = 'z', help = 'Z position'}, + }, + }, + tpm = { help = 'TP To Marker (Admin Only)' }, + togglepvp = { help = 'Toggle PVP on the server (Admin Only)' }, + addpermission = { + help = 'Give Player Permissions (God Only)', + params = { + id = { name = 'id', help = 'ID of player' }, + permission = { name = 'permission', help = 'Permission level' }, + }, + }, + removepermission = { + help = 'Remove Player Permissions (God Only)', + params = { + id = { name = 'id', help = 'ID of player' }, + permission = { name = 'permission', help = 'Permission level' }, + }, + }, + openserver = { help = 'Open the server for everyone (Admin Only)' }, + closeserver = { + help = 'Close the server for people without permissions (Admin Only)', + params = { + reason = { name = 'reason', help = 'Reason for closing (optional)' }, + }, + }, + car = { + help = 'Spawn Vehicle (Admin Only)', + params = { + model = { name = 'model', help = 'Model name of the vehicle' }, + }, + }, + dv = { help = 'Delete Vehicle (Admin Only)' }, + givemoney = { + help = 'Give A Player Money (Admin Only)', + params = { + id = { name = 'id', help = 'Player ID' }, + moneytype = { name = 'moneytype', help = 'Type of money (cash, bank, crypto)' }, + amount = { name = 'amount', help = 'Amount of money' }, + }, + }, + setmoney = { + help = 'Set Players Money Amount (Admin Only)', + params = { + id = { name = 'id', help = 'Player ID' }, + moneytype = { name = 'moneytype', help = 'Type of money (cash, bank, crypto)' }, + amount = { name = 'amount', help = 'Amount of money' }, + }, + }, + job = { help = 'Check Your Job' }, + setjob = { + help = 'Set A Players Job (Admin Only)', + params = { + id = { name = 'id', help = 'Player ID' }, + job = { name = 'job', help = 'Job name' }, + grade = { name = 'grade', help = 'Job grade' }, + }, + }, + gang = { help = 'Check Your Gang' }, + setgang = { + help = 'Set A Players Gang (Admin Only)', + params = { + id = { name = 'id', help = 'Player ID' }, + gang = { name = 'gang', help = 'Gang name' }, + grade = { name = 'grade', help = 'Gang grade' }, + }, + }, + ooc = { help = 'OOC Chat Message' }, + me = { + help = 'Show local message', + params = { + message = { name = 'message', help = 'Message to send' } + }, + }, + }, +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +}) diff --git a/resources/[qb]/qb-core/qbcore.sql b/resources/[qb]/qb-core/qbcore.sql new file mode 100644 index 0000000..ee0d6d8 --- /dev/null +++ b/resources/[qb]/qb-core/qbcore.sql @@ -0,0 +1,44 @@ +CREATE TABLE IF NOT EXISTS `players` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) NOT NULL, + `cid` int(11) DEFAULT NULL, + `license` varchar(255) NOT NULL, + `name` varchar(255) NOT NULL, + `money` text NOT NULL, + `charinfo` text DEFAULT NULL, + `job` text NOT NULL, + `gang` text DEFAULT NULL, + `position` text NOT NULL, + `metadata` text NOT NULL, + `inventory` longtext DEFAULT NULL, + `last_updated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + PRIMARY KEY (`citizenid`), + KEY `id` (`id`), + KEY `last_updated` (`last_updated`), + KEY `license` (`license`) +) ENGINE=InnoDB AUTO_INCREMENT=1; + +CREATE TABLE IF NOT EXISTS `bans` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(50) DEFAULT NULL, + `license` varchar(50) DEFAULT NULL, + `discord` varchar(50) DEFAULT NULL, + `ip` varchar(50) DEFAULT NULL, + `reason` text DEFAULT NULL, + `expire` int(11) DEFAULT NULL, + `bannedby` varchar(255) NOT NULL DEFAULT 'LeBanhammer', + PRIMARY KEY (`id`), + KEY `license` (`license`), + KEY `discord` (`discord`), + KEY `ip` (`ip`) +) ENGINE=InnoDB AUTO_INCREMENT=1; + +CREATE TABLE IF NOT EXISTS `player_contacts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `citizenid` varchar(50) DEFAULT NULL, + `name` varchar(50) DEFAULT NULL, + `number` varchar(50) DEFAULT NULL, + `iban` varchar(50) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `citizenid` (`citizenid`) +) ENGINE=InnoDB AUTO_INCREMENT=1; diff --git a/resources/[qb]/qb-core/server/commands.lua b/resources/[qb]/qb-core/server/commands.lua new file mode 100644 index 0000000..5db8ef4 --- /dev/null +++ b/resources/[qb]/qb-core/server/commands.lua @@ -0,0 +1,295 @@ +QBCore.Commands = {} +QBCore.Commands.List = {} +QBCore.Commands.IgnoreList = { -- Ignore old perm levels while keeping backwards compatibility + ['god'] = true, -- We don't need to create an ace because god is allowed all commands + ['user'] = true -- We don't need to create an ace because builtin.everyone +} + +CreateThread(function() -- Add ace to node for perm checking + local permissions = QBConfig.Server.Permissions + for i=1, #permissions do + local permission = permissions[i] + ExecuteCommand(('add_ace qbcore.%s %s allow'):format(permission, permission)) + end +end) + +-- Register & Refresh Commands + +function QBCore.Commands.Add(name, help, arguments, argsrequired, callback, permission, ...) + local restricted = true -- Default to restricted for all commands + if not permission then permission = 'user' end -- some commands don't pass permission level + if permission == 'user' then restricted = false end -- allow all users to use command + + RegisterCommand(name, function(source, args, rawCommand) -- Register command within fivem + if argsrequired and #args < #arguments then + return TriggerClientEvent('chat:addMessage', source, { + color = {255, 0, 0}, + multiline = true, + args = {"System", Lang:t("error.missing_args2")} + }) + end + callback(source, args, rawCommand) + end, restricted) + + local extraPerms = ... and table.pack(...) or nil + if extraPerms then + extraPerms[extraPerms.n + 1] = permission -- The `n` field is the number of arguments in the packed table + extraPerms.n += 1 + permission = extraPerms + for i = 1, permission.n do + if not QBCore.Commands.IgnoreList[permission[i]] then -- only create aces for extra perm levels + ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission[i], name)) + end + end + permission.n = nil + else + permission = tostring(permission:lower()) + if not QBCore.Commands.IgnoreList[permission] then -- only create aces for extra perm levels + ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission, name)) + end + end + + QBCore.Commands.List[name:lower()] = { + name = name:lower(), + permission = permission, + help = help, + arguments = arguments, + argsrequired = argsrequired, + callback = callback + } +end + +function QBCore.Commands.Refresh(source) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local suggestions = {} + if Player then + for command, info in pairs(QBCore.Commands.List) do + local hasPerm = IsPlayerAceAllowed(tostring(src), 'command.'..command) + if hasPerm then + suggestions[#suggestions + 1] = { + name = '/' .. command, + help = info.help, + params = info.arguments + } + else + TriggerClientEvent('chat:removeSuggestion', src, '/'..command) + end + end + TriggerClientEvent('chat:addSuggestions', src, suggestions) + end +end + +-- Teleport +QBCore.Commands.Add('tp', Lang:t("command.tp.help"), { { name = Lang:t("command.tp.params.x.name"), help = Lang:t("command.tp.params.x.help") }, { name = Lang:t("command.tp.params.y.name"), help = Lang:t("command.tp.params.y.help") }, { name = Lang:t("command.tp.params.z.name"), help = Lang:t("command.tp.params.z.help") } }, false, function(source, args) + if args[1] and not args[2] and not args[3] then + if tonumber(args[1]) then + local target = GetPlayerPed(tonumber(args[1])) + if target ~= 0 then + local coords = GetEntityCoords(target) + TriggerClientEvent('QBCore:Command:TeleportToPlayer', source, coords) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end + else + local location = QBShared.Locations[args[1]] + if location then + TriggerClientEvent('QBCore:Command:TeleportToCoords', source, location.x, location.y, location.z, location.w) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.location_not_exist'), 'error') + end + end + else + if args[1] and args[2] and args[3] then + local x = tonumber((args[1]:gsub(",",""))) + .0 + local y = tonumber((args[2]:gsub(",",""))) + .0 + local z = tonumber((args[3]:gsub(",",""))) + .0 + if x ~= 0 and y ~= 0 and z ~= 0 then + TriggerClientEvent('QBCore:Command:TeleportToCoords', source, x, y, z) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.wrong_format'), 'error') + end + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.missing_args'), 'error') + end + end +end, 'admin') + +QBCore.Commands.Add('tpm', Lang:t("command.tpm.help"), {}, false, function(source) + TriggerClientEvent('QBCore:Command:GoToMarker', source) +end, 'admin') + +QBCore.Commands.Add('togglepvp', Lang:t("command.togglepvp.help"), {}, false, function() + QBConfig.Server.PVP = not QBConfig.Server.PVP + TriggerClientEvent('QBCore:Client:PvpHasToggled', -1, QBConfig.Server.PVP) +end, 'admin') + +-- Permissions + +QBCore.Commands.Add('addpermission', Lang:t("command.addpermission.help"), { { name = Lang:t("command.addpermission.params.id.name"), help = Lang:t("command.addpermission.params.id.help") }, { name = Lang:t("command.addpermission.params.permission.name"), help = Lang:t("command.addpermission.params.permission.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + local permission = tostring(args[2]):lower() + if Player then + QBCore.Functions.AddPermission(Player.PlayerData.source, permission) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'god') + +QBCore.Commands.Add('removepermission', Lang:t("command.removepermission.help"), { { name = Lang:t("command.removepermission.params.id.name"), help = Lang:t("command.removepermission.params.id.help") }, { name = Lang:t("command.removepermission.params.permission.name"), help = Lang:t("command.removepermission.params.permission.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + local permission = tostring(args[2]):lower() + if Player then + QBCore.Functions.RemovePermission(Player.PlayerData.source, permission) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'god') + +-- Open & Close Server + +QBCore.Commands.Add('openserver', Lang:t("command.openserver.help"), {}, false, function(source) + if not QBCore.Config.Server.Closed then + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.server_already_open'), 'error') + return + end + if QBCore.Functions.HasPermission(source, 'admin') then + QBCore.Config.Server.Closed = false + TriggerClientEvent('QBCore:Notify', source, Lang:t('success.server_opened'), 'success') + else + QBCore.Functions.Kick(source, Lang:t("error.no_permission"), nil, nil) + end +end, 'admin') + +QBCore.Commands.Add('closeserver', Lang:t("command.closeserver.help"), {{ name = Lang:t("command.closeserver.params.reason.name"), help = Lang:t("command.closeserver.params.reason.help")}}, false, function(source, args) + if QBCore.Config.Server.Closed then + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.server_already_closed'), 'error') + return + end + if QBCore.Functions.HasPermission(source, 'admin') then + local reason = args[1] or 'No reason specified' + QBCore.Config.Server.Closed = true + QBCore.Config.Server.ClosedReason = reason + for k in pairs(QBCore.Players) do + if not QBCore.Functions.HasPermission(k, QBCore.Config.Server.WhitelistPermission) then + QBCore.Functions.Kick(k, reason, nil, nil) + end + end + TriggerClientEvent('QBCore:Notify', source, Lang:t('success.server_closed'), 'success') + else + QBCore.Functions.Kick(source, Lang:t("error.no_permission"), nil, nil) + end +end, 'admin') + +-- Vehicle + +QBCore.Commands.Add('car', Lang:t("command.car.help"), {{ name = Lang:t("command.car.params.model.name"), help = Lang:t("command.car.params.model.help") }}, true, function(source, args) + TriggerClientEvent('QBCore:Command:SpawnVehicle', source, args[1]) +end, 'admin') + +QBCore.Commands.Add('dv', Lang:t("command.dv.help"), {}, false, function(source) + TriggerClientEvent('QBCore:Command:DeleteVehicle', source) +end, 'admin') + +-- Money + +QBCore.Commands.Add('givemoney', Lang:t("command.givemoney.help"), { { name = Lang:t("command.givemoney.params.id.name"), help = Lang:t("command.givemoney.params.id.help") }, { name = Lang:t("command.givemoney.params.moneytype.name"), help = Lang:t("command.givemoney.params.moneytype.help") }, { name = Lang:t("command.givemoney.params.amount.name"), help = Lang:t("command.givemoney.params.amount.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + Player.Functions.AddMoney(tostring(args[2]), tonumber(args[3])) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'admin') + +QBCore.Commands.Add('setmoney', Lang:t("command.setmoney.help"), { { name = Lang:t("command.setmoney.params.id.name"), help = Lang:t("command.setmoney.params.id.help") }, { name = Lang:t("command.setmoney.params.moneytype.name"), help = Lang:t("command.setmoney.params.moneytype.help") }, { name = Lang:t("command.setmoney.params.amount.name"), help = Lang:t("command.setmoney.params.amount.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + Player.Functions.SetMoney(tostring(args[2]), tonumber(args[3])) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'admin') + +-- Job + +QBCore.Commands.Add('job', Lang:t("command.job.help"), {}, false, function(source) + local PlayerJob = QBCore.Functions.GetPlayer(source).PlayerData.job + TriggerClientEvent('QBCore:Notify', source, Lang:t('info.job_info', {value = PlayerJob.label, value2 = PlayerJob.grade.name, value3 = PlayerJob.onduty})) +end, 'user') + +QBCore.Commands.Add('setjob', Lang:t("command.setjob.help"), { { name = Lang:t("command.setjob.params.id.name"), help = Lang:t("command.setjob.params.id.help") }, { name = Lang:t("command.setjob.params.job.name"), help = Lang:t("command.setjob.params.job.help") }, { name = Lang:t("command.setjob.params.grade.name"), help = Lang:t("command.setjob.params.grade.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + Player.Functions.SetJob(tostring(args[2]), tonumber(args[3])) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'admin') + +-- Gang + +QBCore.Commands.Add('gang', Lang:t("command.gang.help"), {}, false, function(source) + local PlayerGang = QBCore.Functions.GetPlayer(source).PlayerData.gang + TriggerClientEvent('QBCore:Notify', source, Lang:t('info.gang_info', {value = PlayerGang.label, value2 = PlayerGang.grade.name})) +end, 'user') + +QBCore.Commands.Add('setgang', Lang:t("command.setgang.help"), { { name = Lang:t("command.setgang.params.id.name"), help = Lang:t("command.setgang.params.id.help") }, { name = Lang:t("command.setgang.params.gang.name"), help = Lang:t("command.setgang.params.gang.help") }, { name = Lang:t("command.setgang.params.grade.name"), help = Lang:t("command.setgang.params.grade.help") } }, true, function(source, args) + local Player = QBCore.Functions.GetPlayer(tonumber(args[1])) + if Player then + Player.Functions.SetGang(tostring(args[2]), tonumber(args[3])) + else + TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error') + end +end, 'admin') + +-- Out of Character Chat + +QBCore.Commands.Add('ooc', Lang:t("command.ooc.help"), {}, false, function(source, args) + local message = table.concat(args, ' ') + local Players = QBCore.Functions.GetPlayers() + local Player = QBCore.Functions.GetPlayer(source) + local playerCoords = GetEntityCoords(GetPlayerPed(source)) + for _, v in pairs(Players) do + if v == source then + TriggerClientEvent('chat:addMessage', v, { + color = { 229, 111, 27}, + multiline = true, + args = {'OOC | '.. GetPlayerName(source), message} + }) + elseif #(playerCoords - GetEntityCoords(GetPlayerPed(v))) < 20.0 then + TriggerClientEvent('chat:addMessage', v, { + color = { 229, 111, 27}, + multiline = true, + args = {'OOC | '.. GetPlayerName(source), message} + }) + elseif QBCore.Functions.HasPermission(v, 'admin') then + if QBCore.Functions.IsOptin(v) then + TriggerClientEvent('chat:addMessage', v, { + color = { 229, 111, 27}, + multiline = true, + args = {'Proxmity OOC | '.. GetPlayerName(source), message} + }) + TriggerEvent('qb-log:server:CreateLog', 'ooc', 'OOC', 'white', '**' .. GetPlayerName(source) .. '** (CitizenID: ' .. Player.PlayerData.citizenid .. ' | ID: ' .. source .. ') **Message:** ' .. message, false) + end + end + end +end, 'user') + +-- Me command + +QBCore.Commands.Add('me', Lang:t("command.me.help"), {{name = Lang:t("command.me.params.message.name"), help = Lang:t("command.me.params.message.help")}}, false, function(source, args) + if #args < 1 then TriggerClientEvent('QBCore:Notify', source, Lang:t('error.missing_args2'), 'error') return end + local ped = GetPlayerPed(source) + local pCoords = GetEntityCoords(ped) + local msg = table.concat(args, ' '):gsub('[~<].-[>~]', '') + local Players = QBCore.Functions.GetPlayers() + for i=1, #Players do + local Player = Players[i] + local target = GetPlayerPed(Player) + local tCoords = GetEntityCoords(target) + if target == ped or #(pCoords - tCoords) < 20 then + TriggerClientEvent('QBCore:Command:ShowMe3D', Player, source, msg) + end + end +end, 'user') \ No newline at end of file diff --git a/resources/[qb]/qb-core/server/debug.lua b/resources/[qb]/qb-core/server/debug.lua new file mode 100644 index 0000000..ecfba64 --- /dev/null +++ b/resources/[qb]/qb-core/server/debug.lua @@ -0,0 +1,45 @@ +local function tPrint(tbl, indent) + indent = indent or 0 + if type(tbl) == 'table' then + for k, v in pairs(tbl) do + local tblType = type(v) + local formatting = ("%s ^3%s:^0"):format(string.rep(" ", indent), k) + + if tblType == "table" then + print(formatting) + tPrint(v, indent + 1) + elseif tblType == 'boolean' then + print(("%s^1 %s ^0"):format(formatting, v)) + elseif tblType == "function" then + print(("%s^9 %s ^0"):format(formatting, v)) + elseif tblType == 'number' then + print(("%s^5 %s ^0"):format(formatting, v)) + elseif tblType == 'string' then + print(("%s ^2'%s' ^0"):format(formatting, v)) + else + print(("%s^2 %s ^0"):format(formatting, v)) + end + end + else + print(("%s ^0%s"):format(string.rep(" ", indent), tbl)) + end +end + +RegisterServerEvent('QBCore:DebugSomething', function(tbl, indent) + local resource = GetInvokingResource() or "qb-core" + print(('\x1b[4m\x1b[36m[ %s : DEBUG]\x1b[0m'):format(resource)) + tPrint(tbl, indent) + print('\x1b[4m\x1b[36m[ END DEBUG ]\x1b[0m') +end) + +function QBCore.Debug(tbl, indent) + TriggerEvent('QBCore:DebugSomething', tbl, indent) +end + +function QBCore.ShowError(resource, msg) + print('\x1b[31m[' .. resource .. ':ERROR]\x1b[0m ' .. msg) +end + +function QBCore.ShowSuccess(resource, msg) + print('\x1b[32m[' .. resource .. ':LOG]\x1b[0m ' .. msg) +end diff --git a/resources/[qb]/qb-core/server/events.lua b/resources/[qb]/qb-core/server/events.lua new file mode 100644 index 0000000..fa59828 --- /dev/null +++ b/resources/[qb]/qb-core/server/events.lua @@ -0,0 +1,343 @@ +-- Event Handler + +AddEventHandler('chatMessage', function(_, _, message) + if string.sub(message, 1, 1) == '/' then + CancelEvent() + return + end +end) + +AddEventHandler('playerDropped', function(reason) + local src = source + + if not QBCore.Players[src] then return end + local Player = QBCore.Players[src] + TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Dropped', 'red', '**' .. GetPlayerName(src) .. '** (' .. Player.PlayerData.license .. ') left..' ..'\n **Reason:** ' .. reason) + Player.Functions.Save() + local citizenid = Player.PlayerData.citizenid + local query = 'SELECT * FROM duty_logs WHERE citizenid = ? AND end_time IS NULL' + exports.oxmysql:execute(query, {citizenid}, function(result) + if result[1] then + local endTime = os.time() + local duration = endTime - result[1].start_time + exports.oxmysql:execute('UPDATE duty_logs SET end_time = ?, duration = ? WHERE citizenid = ? AND end_time IS NULL', {endTime, duration, citizenid}) + end + end) + QBCore.Player_Buckets[Player.PlayerData.license] = nil + QBCore.Players[src] = nil +end) + +-- Player Connecting + +local function onPlayerConnecting(name, _, deferrals) + local src = source + local license + local identifiers = GetPlayerIdentifiers(src) + deferrals.defer() + + -- Mandatory wait + Wait(0) + + if QBCore.Config.Server.Closed then + if not IsPlayerAceAllowed(src, 'qbadmin.join') then + deferrals.done(QBCore.Config.Server.ClosedReason) + end + end + + for _, v in pairs(identifiers) do + if string.find(v, 'license') then + license = v + break + end + end + + if GetConvarInt("sv_fxdkMode", false) then + license = 'license:AAAAAAAAAAAAAAAA' -- Dummy License + end + + if not license then + deferrals.done(Lang:t('error.no_valid_license')) + elseif QBCore.Config.Server.CheckDuplicateLicense and QBCore.Functions.IsLicenseInUse(license) then + deferrals.done(Lang:t('error.duplicate_license')) + end + + local databaseTime = os.clock() + local databasePromise = promise.new() + + -- conduct database-dependant checks + CreateThread(function() + deferrals.update(string.format(Lang:t('info.checking_ban'), name)) + local databaseSuccess, databaseError = pcall(function() + local isBanned, Reason = QBCore.Functions.IsPlayerBanned(src) + if isBanned then + deferrals.done(Reason) + end + end) + + if QBCore.Config.Server.Whitelist then + deferrals.update(string.format(Lang:t('info.checking_whitelisted'), name)) + databaseSuccess, databaseError = pcall(function() + if not QBCore.Functions.IsWhitelisted(src) then + deferrals.done(Lang:t('error.not_whitelisted')) + end + end) + end + + if not databaseSuccess then + databasePromise:reject(databaseError) + end + databasePromise:resolve() + end) + + -- wait for database to finish + databasePromise:next(function() + deferrals.update(string.format(Lang:t('info.join_server'), name)) + deferrals.done() + end, function (databaseError) + deferrals.done(Lang:t('error.connecting_database_error')) + print('^1' .. databaseError) + end) + + -- if conducting checks for too long then raise error + while databasePromise.state == 0 do + if os.clock() - databaseTime > 30 then + deferrals.done(Lang:t('error.connecting_database_timeout')) + error(Lang:t('error.connecting_database_timeout')) + break + end + Wait(1000) + end + + -- Add any additional defferals you may need! +end + +AddEventHandler('playerConnecting', onPlayerConnecting) + +-- Open & Close Server (prevents players from joining) + +RegisterNetEvent('QBCore:Server:CloseServer', function(reason) + local src = source + if QBCore.Functions.HasPermission(src, 'admin') then + reason = reason or 'No reason specified' + QBCore.Config.Server.Closed = true + QBCore.Config.Server.ClosedReason = reason + for k in pairs(QBCore.Players) do + if not QBCore.Functions.HasPermission(k, QBCore.Config.Server.WhitelistPermission) then + QBCore.Functions.Kick(k, reason, nil, nil) + end + end + else + QBCore.Functions.Kick(src, Lang:t("error.no_permission"), nil, nil) + end +end) + +RegisterNetEvent('QBCore:Server:OpenServer', function() + local src = source + if QBCore.Functions.HasPermission(src, 'admin') then + QBCore.Config.Server.Closed = false + else + QBCore.Functions.Kick(src, Lang:t("error.no_permission"), nil, nil) + end +end) + +-- Callback Events -- + +-- Client Callback +RegisterNetEvent('QBCore:Server:TriggerClientCallback', function(name, ...) + if QBCore.ClientCallbacks[name] then + QBCore.ClientCallbacks[name](...) + QBCore.ClientCallbacks[name] = nil + end +end) + +-- Server Callback +RegisterNetEvent('QBCore:Server:TriggerCallback', function(name, ...) + local src = source + QBCore.Functions.TriggerCallback(name, src, function(...) + TriggerClientEvent('QBCore:Client:TriggerCallback', src, name, ...) + end, ...) +end) + +-- Player + +RegisterNetEvent('QBCore:UpdatePlayer', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if not Player then return end + local newHunger = Player.PlayerData.metadata['hunger'] - QBCore.Config.Player.HungerRate + local newThirst = Player.PlayerData.metadata['thirst'] - QBCore.Config.Player.ThirstRate + if newHunger <= 0 then + newHunger = 0 + end + if newThirst <= 0 then + newThirst = 0 + end + Player.Functions.SetMetaData('thirst', newThirst) + Player.Functions.SetMetaData('hunger', newHunger) + TriggerClientEvent('hud:client:UpdateNeeds', src, newHunger, newThirst) + Player.Functions.Save() +end) + +RegisterNetEvent('QBCore:ToggleDuty', function() + local src = source + local Player = QBCore.Functions.GetPlayer(src) + local playerId = source + local player = QBCore.Functions.GetPlayer(playerId) + local citizenid = player.PlayerData.citizenid + local query = 'SELECT * FROM duty_logs WHERE citizenid = ? AND end_time IS NULL' + + if not Player then return end + if Player.PlayerData.job.onduty then + Player.Functions.SetJobDuty(false) + local query = 'SELECT * FROM duty_logs WHERE citizenid = ? AND end_time IS NULL' + exports.oxmysql:execute(query, {citizenid}, function(result) + if result[1] then + local endTime = os.time() + local duration = endTime - result[1].start_time + exports.oxmysql:execute('UPDATE duty_logs SET end_time = ?, duration = ? WHERE citizenid = ? AND end_time IS NULL', {endTime, duration, citizenid}) + TriggerClientEvent('chat:addMessage', playerId, { args = { '^1Duty Logs', '^7You are now off duty.' } }) + -- TriggerClientEvent('chat:addMessage', -1, { args = { '^1Duty Logs', citizenid..' Just Clocked out' } }) + else + TriggerClientEvent('chat:addMessage', playerId, { args = { '^1Duty Logs', '^7You are not on duty.' } }) + end + end) + TriggerClientEvent('QBCore:Notify', src, Lang:t('info.off_duty')) + else + Player.Functions.SetJobDuty(true) + local query = 'SELECT * FROM duty_logs WHERE citizenid = ? AND end_time IS NULL' + exports.oxmysql:execute(query, {citizenid}, function(result) + if result[1] then + local startTime = os.time() + exports.oxmysql:execute('UPDATE duty_logs SET start_time = ? WHERE citizenid = ?', {startTime, citizenid}) + TriggerClientEvent('chat:addMessage', playerId, { args = { '^1Duty Logs', '^7You are already on duty.' } }) + else + local startTime = os.time() + exports.oxmysql:execute('INSERT INTO duty_logs (start_time, citizenid) VALUES (?, ?)', {startTime, citizenid}) + TriggerClientEvent('chat:addMessage', playerId, { args = { '^1Duty Logs', '^7You are now on duty.' } }) + -- TriggerClientEvent('chat:addMessage', -1, { args = { '^1Duty Logs', citizenid..' Just Clocked In' } }) + end + end) + TriggerClientEvent('QBCore:Notify', src, Lang:t('info.on_duty')) + end + TriggerEvent('QBCore:Server:SetDuty', src, Player.PlayerData.job.onduty) + TriggerClientEvent('QBCore:Client:SetDuty', src, Player.PlayerData.job.onduty) +end) + +-- BaseEvents + +-- Vehicles +RegisterServerEvent('baseevents:enteringVehicle', function(veh,seat,modelName) + local src = source + local data = { + vehicle = veh, + seat = seat, + name = modelName, + event = 'Entering' + } + TriggerClientEvent('QBCore:Client:VehicleInfo', src, data) +end) + +RegisterServerEvent('baseevents:enteredVehicle', function(veh,seat,modelName) + local src = source + local data = { + vehicle = veh, + seat = seat, + name = modelName, + event = 'Entered' + } + TriggerClientEvent('QBCore:Client:VehicleInfo', src, data) +end) + +RegisterServerEvent('baseevents:enteringAborted', function() + local src = source + TriggerClientEvent('QBCore:Client:AbortVehicleEntering', src) +end) + +RegisterServerEvent('baseevents:leftVehicle', function(veh,seat,modelName) + local src = source + local data = { + vehicle = veh, + seat = seat, + name = modelName, + event = 'Left' + } + TriggerClientEvent('QBCore:Client:VehicleInfo', src, data) +end) + +-- Items + +-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. +RegisterNetEvent('QBCore:Server:UseItem', function(item) + print(string.format("%s triggered QBCore:Server:UseItem by ID %s with the following data. This event is deprecated due to exploitation, and will be removed soon. Check ps-inventory for the right use on this event.", GetInvokingResource(), source)) + QBCore.Debug(item) +end) + +-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot) +RegisterNetEvent('QBCore:Server:RemoveItem', function(itemName, amount) + local src = source + print(string.format("%s triggered QBCore:Server:RemoveItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.", GetInvokingResource(), src, amount, itemName)) +end) + +-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot, info) +RegisterNetEvent('QBCore:Server:AddItem', function(itemName, amount) + local src = source + print(string.format("%s triggered QBCore:Server:AddItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.", GetInvokingResource(), src, amount, itemName)) +end) + +-- Non-Chat Command Calling (ex: qb-adminmenu) + +RegisterNetEvent('QBCore:CallCommand', function(command, args) + local src = source + if not QBCore.Commands.List[command] then return end + local Player = QBCore.Functions.GetPlayer(src) + if not Player then return end + local hasPerm = QBCore.Functions.HasPermission(src, "command."..QBCore.Commands.List[command].name) + if hasPerm then + if QBCore.Commands.List[command].argsrequired and #QBCore.Commands.List[command].arguments ~= 0 and not args[#QBCore.Commands.List[command].arguments] then + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.missing_args2'), 'error') + else + QBCore.Commands.List[command].callback(src, args) + end + else + TriggerClientEvent('QBCore:Notify', src, Lang:t('error.no_access'), 'error') + end +end) + + +-- Use this for player vehicle spawning +-- Vehicle server-side spawning callback (netId) +-- use the netid on the client with the NetworkGetEntityFromNetworkId native +-- convert it to a vehicle via the NetToVeh native +QBCore.Functions.CreateCallback('QBCore:Server:SpawnVehicle', function(source, cb, model, coords, warp) + local ped = GetPlayerPed(source) + model = type(model) == 'string' and joaat(model) or model + if not coords then coords = GetEntityCoords(ped) end + local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, true) + while not DoesEntityExist(veh) do Wait(0) end + if warp then + while GetVehiclePedIsIn(ped) ~= veh do + Wait(0) + TaskWarpPedIntoVehicle(ped, veh, -1) + end + end + while NetworkGetEntityOwner(veh) ~= source do Wait(0) end + cb(NetworkGetNetworkIdFromEntity(veh)) +end) + +-- Use this for long distance vehicle spawning +-- vehicle server-side spawning callback (netId) +-- use the netid on the client with the NetworkGetEntityFromNetworkId native +-- convert it to a vehicle via the NetToVeh native +QBCore.Functions.CreateCallback('QBCore:Server:CreateVehicle', function(source, cb, model, coords, warp) + model = type(model) == 'string' and GetHashKey(model) or model + if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end + local CreateAutomobile = GetHashKey("CREATE_AUTOMOBILE") + local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, coords.w, true, true) + while not DoesEntityExist(veh) do Wait(0) end + if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end + cb(NetworkGetNetworkIdFromEntity(veh)) +end) + +--QBCore.Functions.CreateCallback('QBCore:HasItem', function(source, cb, items, amount) +-- https://github.com/qbcore-framework/ps-inventory/blob/e4ef156d93dd1727234d388c3f25110c350b3bcf/server/main.lua#L2066 +--end) \ No newline at end of file diff --git a/resources/[qb]/qb-core/server/exports.lua b/resources/[qb]/qb-core/server/exports.lua new file mode 100644 index 0000000..9bb0fe8 --- /dev/null +++ b/resources/[qb]/qb-core/server/exports.lua @@ -0,0 +1,335 @@ +-- Add or change (a) method(s) in the QBCore.Functions table +local function SetMethod(methodName, handler) + if type(methodName) ~= "string" then + return false, "invalid_method_name" + end + + QBCore.Functions[methodName] = handler + + TriggerEvent('QBCore:Server:UpdateObject') + + return true, "success" +end + +QBCore.Functions.SetMethod = SetMethod +exports("SetMethod", SetMethod) + +-- Add or change (a) field(s) in the QBCore table +local function SetField(fieldName, data) + if type(fieldName) ~= "string" then + return false, "invalid_field_name" + end + + QBCore[fieldName] = data + + TriggerEvent('QBCore:Server:UpdateObject') + + return true, "success" +end + +QBCore.Functions.SetField = SetField +exports("SetField", SetField) + +-- Single add job function which should only be used if you planning on adding a single job +local function AddJob(jobName, job) + if type(jobName) ~= "string" then + return false, "invalid_job_name" + end + + if QBCore.Shared.Jobs[jobName] then + return false, "job_exists" + end + + QBCore.Shared.Jobs[jobName] = job + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, job) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.AddJob = AddJob +exports('AddJob', AddJob) + +-- Multiple Add Jobs +local function AddJobs(jobs) + local shouldContinue = true + local message = "success" + local errorItem = nil + + for key, value in pairs(jobs) do + if type(key) ~= "string" then + message = 'invalid_job_name' + shouldContinue = false + errorItem = jobs[key] + break + end + + if QBCore.Shared.Jobs[key] then + message = 'job_exists' + shouldContinue = false + errorItem = jobs[key] + break + end + + QBCore.Shared.Jobs[key] = value + end + + if not shouldContinue then return false, message, errorItem end + TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Jobs', jobs) + TriggerEvent('QBCore:Server:UpdateObject') + return true, message, nil +end + +QBCore.Functions.AddJobs = AddJobs +exports('AddJobs', AddJobs) + +-- Single Remove Job +local function RemoveJob(jobName) + if type(jobName) ~= "string" then + return false, "invalid_job_name" + end + + if not QBCore.Shared.Jobs[jobName] then + return false, "job_not_exists" + end + + QBCore.Shared.Jobs[jobName] = nil + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, nil) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.RemoveJob = RemoveJob +exports('RemoveJob', RemoveJob) + +-- Single Update Job +local function UpdateJob(jobName, job) + if type(jobName) ~= "string" then + return false, "invalid_job_name" + end + + if not QBCore.Shared.Jobs[jobName] then + return false, "job_not_exists" + end + + QBCore.Shared.Jobs[jobName] = job + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, job) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.UpdateJob = UpdateJob +exports('UpdateJob', UpdateJob) + +-- Single add item +local function AddItem(itemName, item) + if type(itemName) ~= "string" then + return false, "invalid_item_name" + end + + if QBCore.Shared.Items[itemName] then + return false, "item_exists" + end + + QBCore.Shared.Items[itemName] = item + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, item) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.AddItem = AddItem +exports('AddItem', AddItem) + +-- Single update item +local function UpdateItem(itemName, item) + if type(itemName) ~= "string" then + return false, "invalid_item_name" + end + if not QBCore.Shared.Items[itemName] then + return false, "item_not_exists" + end + QBCore.Shared.Items[itemName] = item + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, item) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.UpdateItem = UpdateItem +exports('UpdateItem', UpdateItem) + +-- Multiple Add Items +local function AddItems(items) + local shouldContinue = true + local message = "success" + local errorItem = nil + + for key, value in pairs(items) do + if type(key) ~= "string" then + message = "invalid_item_name" + shouldContinue = false + errorItem = items[key] + break + end + + if QBCore.Shared.Items[key] then + message = "item_exists" + shouldContinue = false + errorItem = items[key] + break + end + + QBCore.Shared.Items[key] = value + end + + if not shouldContinue then return false, message, errorItem end + TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Items', items) + TriggerEvent('QBCore:Server:UpdateObject') + return true, message, nil +end + +QBCore.Functions.AddItems = AddItems +exports('AddItems', AddItems) + +-- Single Remove Item +local function RemoveItem(itemName) + if type(itemName) ~= "string" then + return false, "invalid_item_name" + end + + if not QBCore.Shared.Items[itemName] then + return false, "item_not_exists" + end + + QBCore.Shared.Items[itemName] = nil + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Items', itemName, nil) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.RemoveItem = RemoveItem +exports('RemoveItem', RemoveItem) + +-- Single Add Gang +local function AddGang(gangName, gang) + if type(gangName) ~= "string" then + return false, "invalid_gang_name" + end + + if QBCore.Shared.Gangs[gangName] then + return false, "gang_exists" + end + + QBCore.Shared.Gangs[gangName] = gang + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, gang) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.AddGang = AddGang +exports('AddGang', AddGang) + +-- Multiple Add Gangs +local function AddGangs(gangs) + local shouldContinue = true + local message = "success" + local errorItem = nil + + for key, value in pairs(gangs) do + if type(key) ~= "string" then + message = "invalid_gang_name" + shouldContinue = false + errorItem = gangs[key] + break + end + + if QBCore.Shared.Gangs[key] then + message = "gang_exists" + shouldContinue = false + errorItem = gangs[key] + break + end + + QBCore.Shared.Gangs[key] = value + end + + if not shouldContinue then return false, message, errorItem end + TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Gangs', gangs) + TriggerEvent('QBCore:Server:UpdateObject') + return true, message, nil +end + +QBCore.Functions.AddGangs = AddGangs +exports('AddGangs', AddGangs) + +-- Single Remove Gang +local function RemoveGang(gangName) + if type(gangName) ~= "string" then + return false, "invalid_gang_name" + end + + if not QBCore.Shared.Gangs[gangName] then + return false, "gang_not_exists" + end + + QBCore.Shared.Gangs[gangName] = nil + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, nil) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.RemoveGang = RemoveGang +exports('RemoveGang', RemoveGang) + +-- Single Update Gang +local function UpdateGang(gangName, gang) + if type(gangName) ~= "string" then + return false, "invalid_gang_name" + end + + if not QBCore.Shared.Gangs[gangName] then + return false, "gang_not_exists" + end + + QBCore.Shared.Gangs[gangName] = gang + + TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Gangs', gangName, gang) + TriggerEvent('QBCore:Server:UpdateObject') + return true, "success" +end + +QBCore.Functions.UpdateGang = UpdateGang +exports('UpdateGang', UpdateGang) + +local function GetCoreVersion(InvokingResource) + local resourceVersion = GetResourceMetadata(GetCurrentResourceName(), 'version') + if InvokingResource and InvokingResource ~= '' then + print(("%s called qbcore version check: %s"):format(InvokingResource or 'Unknown Resource', resourceVersion)) + end + return resourceVersion +end + +QBCore.Functions.GetCoreVersion = GetCoreVersion +exports('GetCoreVersion', GetCoreVersion) + +local function ExploitBan(playerId, origin) + local name = GetPlayerName(playerId) + MySQL.insert('INSERT INTO bans (name, license, discord, ip, reason, expire, bannedby) VALUES (?, ?, ?, ?, ?, ?, ?)', { + name, + QBCore.Functions.GetIdentifier(playerId, 'license'), + QBCore.Functions.GetIdentifier(playerId, 'discord'), + '0.0.0.0', + origin, + 2147483647, + 'Anti Cheat' + }) + DropPlayer(playerId, Lang:t('info.exploit_banned', {discord = QBCore.Config.Server.Discord})) + TriggerEvent("qb-log:server:CreateLog", "anticheat", "Anti-Cheat", "red", name .. " has been banned for exploiting " .. origin) +end + +exports('ExploitBan', ExploitBan) diff --git a/resources/[qb]/qb-core/server/functions.lua b/resources/[qb]/qb-core/server/functions.lua new file mode 100644 index 0000000..c52c5c3 --- /dev/null +++ b/resources/[qb]/qb-core/server/functions.lua @@ -0,0 +1,564 @@ +QBCore.Functions = {} +QBCore.Player_Buckets = {} +QBCore.Entity_Buckets = {} +QBCore.UsableItems = {} + +-- Getters +-- Get your player first and then trigger a function on them +-- ex: local player = QBCore.Functions.GetPlayer(source) +-- ex: local example = player.Functions.functionname(parameter) + +---Gets the coordinates of an entity +---@param entity number +---@return vector4 +function QBCore.Functions.GetCoords(entity) + local coords = GetEntityCoords(entity, false) + local heading = GetEntityHeading(entity) + return vector4(coords.x, coords.y, coords.z, heading) +end + +---Gets player identifier of the given type +---@param source any +---@param idtype string +---@return string? +function QBCore.Functions.GetIdentifier(source, idtype) + local identifiers = GetPlayerIdentifiers(source) + for _, identifier in pairs(identifiers) do + if string.find(identifier, idtype) then + return identifier + end + end + return nil +end + +---Gets a players server id (source). Returns 0 if no player is found. +---@param identifier string +---@return number +function QBCore.Functions.GetSource(identifier) + for src, _ in pairs(QBCore.Players) do + local idens = GetPlayerIdentifiers(src) + for _, id in pairs(idens) do + if identifier == id then + return src + end + end + end + return 0 +end + +---Get player with given server id (source) +---@param source any +---@return table +function QBCore.Functions.GetPlayer(source) + if type(source) == 'number' then + return QBCore.Players[source] + else + return QBCore.Players[QBCore.Functions.GetSource(source)] + end +end + +---Get player by citizen id +---@param citizenid string +---@return table? +function QBCore.Functions.GetPlayerByCitizenId(citizenid) + for src in pairs(QBCore.Players) do + if QBCore.Players[src].PlayerData.citizenid == citizenid then + return QBCore.Players[src] + end + end + return nil +end + +---Get offline player by citizen id +---@param citizenid string +---@return table? +function QBCore.Functions.GetOfflinePlayerByCitizenId(citizenid) + return QBCore.Player.GetOfflinePlayer(citizenid) +end + +---Get player by phone number +---@param number number +---@return table? +function QBCore.Functions.GetPlayerByPhone(number) + for src in pairs(QBCore.Players) do + if QBCore.Players[src].PlayerData.charinfo.phone == number then + return QBCore.Players[src] + end + end + return nil +end + +---Get all players. Returns the server ids of all players. +---@return table +function QBCore.Functions.GetPlayers() + local sources = {} + for k in pairs(QBCore.Players) do + sources[#sources+1] = k + end + return sources +end + +---Will return an array of QB Player class instances +---unlike the GetPlayers() wrapper which only returns IDs +---@return table +function QBCore.Functions.GetQBPlayers() + return QBCore.Players +end + +---Gets a list of all on duty players of a specified job and the number +---@param job string +---@return table, number +function QBCore.Functions.GetPlayersOnDuty(job) + local players = {} + local count = 0 + for src, Player in pairs(QBCore.Players) do + if Player.PlayerData.job.name == job then + if Player.PlayerData.job.onduty then + players[#players + 1] = src + count += 1 + end + end + end + return players, count +end + +---Returns only the amount of players on duty for the specified job +---@param job any +---@return number +function QBCore.Functions.GetDutyCount(job) + local count = 0 + for _, Player in pairs(QBCore.Players) do + if Player.PlayerData.job.name == job then + if Player.PlayerData.job.onduty then + count += 1 + end + end + end + return count +end + +-- Routing buckets (Only touch if you know what you are doing) + +---Returns the objects related to buckets, first returned value is the player buckets, second one is entity buckets +---@return table, table +function QBCore.Functions.GetBucketObjects() + return QBCore.Player_Buckets, QBCore.Entity_Buckets +end + +---Will set the provided player id / source into the provided bucket id +---@param source any +---@param bucket any +---@return boolean +function QBCore.Functions.SetPlayerBucket(source, bucket) + if source and bucket then + local plicense = QBCore.Functions.GetIdentifier(source, 'license') + SetPlayerRoutingBucket(source, bucket) + QBCore.Player_Buckets[plicense] = {id = source, bucket = bucket} + return true + else + return false + end +end + +---Will set any entity into the provided bucket, for example peds / vehicles / props / etc. +---@param entity number +---@param bucket number +---@return boolean +function QBCore.Functions.SetEntityBucket(entity, bucket) + if entity and bucket then + SetEntityRoutingBucket(entity, bucket) + QBCore.Entity_Buckets[entity] = {id = entity, bucket = bucket} + return true + else + return false + end +end + +---Will return an array of all the player ids inside the current bucket +---@param bucket number +---@return table|boolean +function QBCore.Functions.GetPlayersInBucket(bucket) + local curr_bucket_pool = {} + if QBCore.Player_Buckets and next(QBCore.Player_Buckets) then + for _, v in pairs(QBCore.Player_Buckets) do + if v.bucket == bucket then + curr_bucket_pool[#curr_bucket_pool + 1] = v.id + end + end + return curr_bucket_pool + else + return false + end +end + +---Will return an array of all the entities inside the current bucket +---(not for player entities, use GetPlayersInBucket for that) +---@param bucket number +---@return table|boolean +function QBCore.Functions.GetEntitiesInBucket(bucket) + local curr_bucket_pool = {} + if QBCore.Entity_Buckets and next(QBCore.Entity_Buckets) then + for _, v in pairs(QBCore.Entity_Buckets) do + if v.bucket == bucket then + curr_bucket_pool[#curr_bucket_pool + 1] = v.id + end + end + return curr_bucket_pool + else + return false + end +end + +---Server side vehicle creation with optional callback +---the CreateVehicle RPC still uses the client for creation so players must be near +---@param source any +---@param model any +---@param coords vector +---@param warp boolean +---@return number +function QBCore.Functions.SpawnVehicle(source, model, coords, warp) + local ped = GetPlayerPed(source) + model = type(model) == 'string' and joaat(model) or model + if not coords then coords = GetEntityCoords(ped) end + local heading = coords.w and coords.w or 0.0 + local veh = CreateVehicle(model, coords.x, coords.y, coords.z, heading, true, true) + while not DoesEntityExist(veh) do Wait(0) end + if warp then + while GetVehiclePedIsIn(ped) ~= veh do + Wait(0) + TaskWarpPedIntoVehicle(ped, veh, -1) + end + end + while NetworkGetEntityOwner(veh) ~= source do Wait(0) end + return veh +end + +---Server side vehicle creation with optional callback +---the CreateAutomobile native is still experimental but doesn't use client for creation +---doesn't work for all vehicles! +---comment +---@param source any +---@param model any +---@param coords vector +---@param warp boolean +---@return number +function QBCore.Functions.CreateAutomobile(source, model, coords, warp) + model = type(model) == 'string' and joaat(model) or model + if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end + local heading = coords.w and coords.w or 0.0 + local CreateAutomobile = `CREATE_AUTOMOBILE` + local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, heading, true, true) + while not DoesEntityExist(veh) do Wait(0) end + if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end + return veh +end + +--- New & more reliable server side native for creating vehicles +---comment +---@param source any +---@param model any +---@param vehtype any +-- The appropriate vehicle type for the model info. +-- Can be one of automobile, bike, boat, heli, plane, submarine, trailer, and (potentially), train. +-- This should be the same type as the type field in vehicles.meta. +---@param coords vector +---@param warp boolean +---@return number +function QBCore.Functions.CreateVehicle(source, model, vehtype, coords, warp) + model = type(model) == 'string' and joaat(model) or model + vehtype = type(vehtype) == 'string' and tostring(vehtype) or vehtype + if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end + local heading = coords.w and coords.w or 0.0 + local veh = CreateVehicleServerSetter(model, vehtype, coords, heading) + while not DoesEntityExist(veh) do Wait(0) end + if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end + return veh +end + +---Paychecks (standalone - don't touch) +function PaycheckInterval() + if next(QBCore.Players) then + for _, Player in pairs(QBCore.Players) do + if Player then + local payment = QBShared.Jobs[Player.PlayerData.job.name]['grades'][tostring(Player.PlayerData.job.grade.level)].payment + if not payment then payment = Player.PlayerData.job.payment end + if Player.PlayerData.job and payment > 0 and (QBShared.Jobs[Player.PlayerData.job.name].offDutyPay or Player.PlayerData.job.onduty) then + if QBCore.Config.Money.PayCheckSociety then + local account = exports['qb-management']:GetAccount(Player.PlayerData.job.name) + if account ~= 0 then -- Checks if player is employed by a society + if account < payment then -- Checks if company has enough money to pay society + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('error.company_too_poor'), 'error') + else + Player.Functions.AddMoney('bank', payment, 'paycheck') + exports['qb-management']:RemoveMoney(Player.PlayerData.job.name, payment) + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment})) + end + else + Player.Functions.AddMoney('bank', payment, 'paycheck') + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment})) + end + else + Player.Functions.AddMoney('bank', payment, 'paycheck') + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', {value = payment})) + end + end + end + end + end + SetTimeout(QBCore.Config.Money.PayCheckTimeOut * (60 * 1000), PaycheckInterval) +end + +-- Callback Functions -- + +---Trigger Client Callback +---@param name string +---@param source any +---@param cb function +---@param ... any +function QBCore.Functions.TriggerClientCallback(name, source, cb, ...) + QBCore.ClientCallbacks[name] = cb + TriggerClientEvent('QBCore:Client:TriggerClientCallback', source, name, ...) +end + +---Create Server Callback +---@param name string +---@param cb function +function QBCore.Functions.CreateCallback(name, cb) + QBCore.ServerCallbacks[name] = cb +end + +---Trigger Serv er Callback +---@param name string +---@param source any +---@param cb function +---@param ... any +function QBCore.Functions.TriggerCallback(name, source, cb, ...) + if not QBCore.ServerCallbacks[name] then return end + QBCore.ServerCallbacks[name](source, cb, ...) +end + +-- Items + +---Create a usable item +---@param item string +---@param data function +function QBCore.Functions.CreateUseableItem(item, data) + QBCore.UsableItems[item] = data +end + +---Checks if the given item is usable +---@param item string +---@return any +function QBCore.Functions.CanUseItem(item) + return QBCore.UsableItems[item] +end + +---Use item +---@param source any +---@param item string +function QBCore.Functions.UseItem(source, item) + if GetResourceState('ps-inventory') == 'missing' then return end + exports['ps-inventory']:UseItem(source, item) +end + +---Kick Player +---@param source any +---@param reason string +---@param setKickReason boolean +---@param deferrals boolean +function QBCore.Functions.Kick(source, reason, setKickReason, deferrals) + reason = '\n' .. reason .. '\n🔸 Du blev kicked. For mere information, henven dig på Discorden: ' .. QBCore.Config.Server.Discord + if setKickReason then + setKickReason(reason) + end + CreateThread(function() + if deferrals then + deferrals.update(reason) + Wait(2500) + end + if source then + -- DropPlayer(source, reason) + end + for _ = 0, 4 do + while true do + if source then + if GetPlayerPing(source) >= 0 then + break + end + Wait(100) + CreateThread(function() + -- DropPlayer(source, reason) + end) + end + end + Wait(5000) + end + end) +end + +---Check if player is whitelisted, kept like this for backwards compatibility or future plans +---@param source any +---@return boolean +function QBCore.Functions.IsWhitelisted(source) + if not QBCore.Config.Server.Whitelist then return true end + if QBCore.Functions.HasPermission(source, QBCore.Config.Server.WhitelistPermission) then return true end + return false +end + +-- Setting & Removing Permissions + +---Add permission for player +---@param source any +---@param permission string +function QBCore.Functions.AddPermission(source, permission) + if not IsPlayerAceAllowed(source, permission) then + ExecuteCommand(('add_principal player.%s qbcore.%s'):format(source, permission)) + QBCore.Commands.Refresh(source) + end +end + +---Remove permission from player +---@param source any +---@param permission string +function QBCore.Functions.RemovePermission(source, permission) + if permission then + if IsPlayerAceAllowed(source, permission) then + ExecuteCommand(('remove_principal player.%s qbcore.%s'):format(source, permission)) + QBCore.Commands.Refresh(source) + end + else + for _, v in pairs(QBCore.Config.Server.Permissions) do + if IsPlayerAceAllowed(source, v) then + ExecuteCommand(('remove_principal player.%s qbcore.%s'):format(source, v)) + QBCore.Commands.Refresh(source) + end + end + end +end + +-- Checking for Permission Level + +---Check if player has permission +---@param source any +---@param permission string +---@return boolean +function QBCore.Functions.HasPermission(source, permission) + if type(permission) == "string" then + if IsPlayerAceAllowed(source, permission) then return true end + elseif type(permission) == "table" then + for _, permLevel in pairs(permission) do + if IsPlayerAceAllowed(source, permLevel) then return true end + end + end + + return false +end + +---Get the players permissions +---@param source any +---@return table +function QBCore.Functions.GetPermission(source) + local src = source + local perms = {} + for _, v in pairs (QBCore.Config.Server.Permissions) do + if IsPlayerAceAllowed(src, v) then + perms[v] = true + end + end + return perms +end + +---Get admin messages opt-in state for player +---@param source any +---@return boolean +function QBCore.Functions.IsOptin(source) + local license = QBCore.Functions.GetIdentifier(source, 'license') + if not license or not QBCore.Functions.HasPermission(source, 'admin') then return false end + local Player = QBCore.Functions.GetPlayer(source) + return Player.PlayerData.optin +end + +---Toggle opt-in to admin messages +---@param source any +function QBCore.Functions.ToggleOptin(source) + local license = QBCore.Functions.GetIdentifier(source, 'license') + if not license or not QBCore.Functions.HasPermission(source, 'admin') then return end + local Player = QBCore.Functions.GetPlayer(source) + Player.PlayerData.optin = not Player.PlayerData.optin + Player.Functions.SetPlayerData('optin', Player.PlayerData.optin) +end + +---Check if player is banned +---@param source any +---@return boolean, string? +function QBCore.Functions.IsPlayerBanned(source) + local plicense = QBCore.Functions.GetIdentifier(source, 'license') + local result = MySQL.single.await('SELECT * FROM bans WHERE license = ?', { plicense }) + if not result then return false end + if os.time() < result.expire then + local timeTable = os.date('*t', tonumber(result.expire)) + return true, '\n\nDu er banned fra serveren:\n' + ..result.reason.. + '\nDit ban udløber: '..timeTable.day ..'/'..timeTable.month..'/'..timeTable.year..' '.. timeTable.hour ..':'.. timeTable.min .. + '\n\nMener du at der er sket en fejl, så kontakt os på vores Discord: '..QBCore.Config.Server.Discord..'\n' + else + MySQL.query('DELETE FROM bans WHERE id = ?', { result.id }) + end + return false +end + +---Check for duplicate license +---@param license any +---@return boolean +function QBCore.Functions.IsLicenseInUse(license) + local players = GetPlayers() + for _, player in pairs(players) do + local identifiers = GetPlayerIdentifiers(player) + for _, id in pairs(identifiers) do + if string.find(id, 'license') then + if id == license then + return true + end + end + end + end + return false +end + +-- Utility functions + +---Check if a player has an item [deprecated] +---@param source any +---@param items table|string +---@param amount number +---@return boolean +function QBCore.Functions.HasItem(source, items, amount) + if GetResourceState('ps-inventory') == 'missing' then return end + return exports['ps-inventory']:HasItem(source, items, amount) +end + +---Notify +---@param source any +---@param text string +---@param type string +---@param length number +function QBCore.Functions.Notify(source, text, type, length) + TriggerClientEvent('QBCore:Notify', source, text, type, length) +end + +---???? ... ok +---@param source any +---@param data any +---@param pattern any +---@return boolean +function QBCore.Functions.PrepForSQL(source, data, pattern) + data = tostring(data) + local src = source + local player = QBCore.Functions.GetPlayer(src) + local result = string.match(data, pattern) + if not result or string.len(result) ~= string.len(data) then + TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'SQL Exploit Attempted', 'red', string.format('%s attempted to exploit SQL!', player.PlayerData.license)) + return false + end + return true +end \ No newline at end of file diff --git a/resources/[qb]/qb-core/server/main.lua b/resources/[qb]/qb-core/server/main.lua new file mode 100644 index 0000000..368dc05 --- /dev/null +++ b/resources/[qb]/qb-core/server/main.lua @@ -0,0 +1,13 @@ +QBCore = {} +QBCore.Config = QBConfig +QBCore.Shared = QBShared +QBCore.ClientCallbacks = {} +QBCore.ServerCallbacks = {} + +exports('GetCoreObject', function() + return QBCore +end) + +-- To use this export in a script instead of manifest method +-- Just put this line of code below at the very top of the script +-- local QBCore = exports['qb-core']:GetCoreObject() diff --git a/resources/[qb]/qb-core/server/player.lua b/resources/[qb]/qb-core/server/player.lua new file mode 100644 index 0000000..bb7cec2 --- /dev/null +++ b/resources/[qb]/qb-core/server/player.lua @@ -0,0 +1,720 @@ +QBCore.Players = {} +QBCore.Player = {} + +-- On player login get their data or set defaults +-- Don't touch any of this unless you know what you are doing +-- Will cause major issues! + +function QBCore.Player.Login(source, citizenid, newData) + if source and source ~= '' then + if citizenid then + local license = QBCore.Functions.GetIdentifier(source, 'license') + local isOnline = QBCore.Functions.GetPlayerByCitizenId(citizenid) + local PlayerData = MySQL.prepare.await('SELECT * FROM players where citizenid = ?', { citizenid }) + if isOnline then exports['qb-core']:ExploitBan(source, 'You Have Been Banned For Exploitation') return end + if PlayerData and license == PlayerData.license then + PlayerData.money = json.decode(PlayerData.money) + PlayerData.job = json.decode(PlayerData.job) + PlayerData.position = json.decode(PlayerData.position) + PlayerData.metadata = json.decode(PlayerData.metadata) + PlayerData.charinfo = json.decode(PlayerData.charinfo) + if PlayerData.gang then + PlayerData.gang = json.decode(PlayerData.gang) + else + PlayerData.gang = {} + end + PlayerData.phoneNumber = PlayerData.phone_number + QBCore.Player.CheckPlayerData(source, PlayerData) + else + DropPlayer(source, Lang:t("info.exploit_dropped")) + TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'white', string.format("%s Has Been Dropped For Character Joining Exploit", GetPlayerName(source)), false) + end + else + QBCore.Player.CheckPlayerData(source, newData) + end + return true + else + QBCore.ShowError(GetCurrentResourceName(), 'ERROR QBCORE.PLAYER.LOGIN - NO SOURCE GIVEN!') + return false + end +end + +function QBCore.Player.GetOfflinePlayer(citizenid) + if citizenid then + local PlayerData = MySQL.Sync.prepare('SELECT * FROM players where citizenid = ?', {citizenid}) + if PlayerData then + PlayerData.money = json.decode(PlayerData.money) + PlayerData.job = json.decode(PlayerData.job) + PlayerData.position = json.decode(PlayerData.position) + PlayerData.metadata = json.decode(PlayerData.metadata) + PlayerData.charinfo = json.decode(PlayerData.charinfo) + if PlayerData.gang then + PlayerData.gang = json.decode(PlayerData.gang) + else + PlayerData.gang = {} + end + PlayerData.phoneNumber = PlayerData.phone_number + return QBCore.Player.CheckPlayerData(nil, PlayerData) + end + end + return nil +end + +function QBCore.Player.CheckPlayerData(source, PlayerData) + PlayerData = PlayerData or {} + local Offline = true + if source then + PlayerData.source = source + PlayerData.license = PlayerData.license or QBCore.Functions.GetIdentifier(source, 'license') + PlayerData.name = GetPlayerName(source) + Offline = false + end + + PlayerData.citizenid = PlayerData.citizenid or QBCore.Player.CreateCitizenId() + PlayerData.cid = PlayerData.cid or 1 + PlayerData.money = PlayerData.money or {} + PlayerData.optin = PlayerData.optin or true + for moneytype, startamount in pairs(QBCore.Config.Money.MoneyTypes) do + PlayerData.money[moneytype] = PlayerData.money[moneytype] or startamount + end + + -- Charinfo + PlayerData.charinfo = PlayerData.charinfo or {} + PlayerData.charinfo.firstname = PlayerData.charinfo.firstname or 'Fornavn' + PlayerData.charinfo.lastname = PlayerData.charinfo.lastname or 'Efternavn' + PlayerData.charinfo.birthdate = PlayerData.charinfo.birthdate or '19/07/1998' + PlayerData.charinfo.gender = PlayerData.charinfo.gender or 0 + PlayerData.charinfo.backstory = PlayerData.charinfo.backstory or 'Baghistorie' + PlayerData.charinfo.nationality = PlayerData.charinfo.nationality or 'Danmark' + PlayerData.charinfo.phone = PlayerData.charinfo.phone or QBCore.Functions.CreatePhoneNumber() + PlayerData.charinfo.account = PlayerData.charinfo.account or QBCore.Functions.CreateAccountNumber() + -- Metadata + PlayerData.metadata = PlayerData.metadata or {} + PlayerData.metadata['hunger'] = PlayerData.metadata['hunger'] or 100 + PlayerData.metadata['thirst'] = PlayerData.metadata['thirst'] or 100 + PlayerData.metadata['stress'] = PlayerData.metadata['stress'] or 0 + PlayerData.metadata['isdead'] = PlayerData.metadata['isdead'] or false + PlayerData.metadata['inlaststand'] = PlayerData.metadata['inlaststand'] or false + PlayerData.metadata['armor'] = PlayerData.metadata['armor'] or 0 + PlayerData.metadata['ishandcuffed'] = PlayerData.metadata['ishandcuffed'] or false + PlayerData.metadata['tracker'] = PlayerData.metadata['tracker'] or false + PlayerData.metadata['injail'] = PlayerData.metadata['injail'] or 0 + PlayerData.metadata['jailitems'] = PlayerData.metadata['jailitems'] or {} + PlayerData.metadata['status'] = PlayerData.metadata['status'] or {} + PlayerData.metadata['phone'] = PlayerData.metadata['phone'] or {} + PlayerData.metadata['fitbit'] = PlayerData.metadata['fitbit'] or {} + PlayerData.metadata['commandbinds'] = PlayerData.metadata['commandbinds'] or {} + PlayerData.metadata['bloodtype'] = PlayerData.metadata['bloodtype'] or QBCore.Config.Player.Bloodtypes[math.random(1, #QBCore.Config.Player.Bloodtypes)] + PlayerData.metadata['dealerrep'] = PlayerData.metadata['dealerrep'] or 0 + PlayerData.metadata['craftingrep'] = PlayerData.metadata['craftingrep'] or 0 + PlayerData.metadata['attachmentcraftingrep'] = PlayerData.metadata['attachmentcraftingrep'] or 0 + PlayerData.metadata['reporep'] = PlayerData.metadata['reporep'] or 0 + PlayerData.metadata['currentapartment'] = PlayerData.metadata['currentapartment'] or nil + PlayerData.metadata['jobrep'] = PlayerData.metadata['jobrep'] or {} + PlayerData.metadata['garbage'] = PlayerData.metadata['garbage'] or 0 + PlayerData.metadata['delivery'] = PlayerData.metadata['delivery'] or 0 + PlayerData.metadata['jobrep']['tow'] = PlayerData.metadata['jobrep']['tow'] or 0 + PlayerData.metadata['jobrep']['trucker'] = PlayerData.metadata['jobrep']['trucker'] or 0 + PlayerData.metadata['jobrep']['taxi'] = PlayerData.metadata['jobrep']['taxi'] or 0 + PlayerData.metadata['jobrep']['hotdog'] = PlayerData.metadata['jobrep']['hotdog'] or 0 + PlayerData.metadata['callsign'] = PlayerData.metadata['callsign'] or 'NO CALLSIGN' + PlayerData.metadata['fingerprint'] = PlayerData.metadata['fingerprint'] or QBCore.Player.CreateFingerId() + PlayerData.metadata['walletid'] = PlayerData.metadata['walletid'] or QBCore.Player.CreateWalletId() + PlayerData.metadata['health'] = PlayerData.metadata['health'] or 200 + PlayerData.metadata['criminalrecord'] = PlayerData.metadata['criminalrecord'] or { + ['hasRecord'] = false, + ['date'] = nil + } + PlayerData.metadata['crypto'] = PlayerData.metadata['crypto'] or { + ["shung"] = 0, + ["gne"] = 0, + ["xcoin"] = 0, + ["lme"] = 0 + } + PlayerData.metadata['licences'] = PlayerData.metadata['licences'] or { + ['driver'] = true, + ['business'] = false, + ['weapon'] = false + } + PlayerData.metadata['inside'] = PlayerData.metadata['inside'] or { + house = nil, + apartment = { + apartmentType = nil, + apartmentId = nil, + } + } + PlayerData.metadata['phonedata'] = PlayerData.metadata['phonedata'] or { + SerialNumber = QBCore.Player.CreateSerialNumber(), + InstalledApps = {}, + } + -- Job + if PlayerData.job and PlayerData.job.name and not QBCore.Shared.Jobs[PlayerData.job.name] then PlayerData.job = nil end + PlayerData.job = PlayerData.job or {} + PlayerData.job.name = PlayerData.job.name or 'unemployed' + PlayerData.job.label = PlayerData.job.label or 'Civil' + PlayerData.job.payment = PlayerData.job.payment or 10 + PlayerData.job.type = PlayerData.job.type or 'none' + if QBCore.Shared.ForceJobDefaultDutyAtLogin or PlayerData.job.onduty == nil then + PlayerData.job.onduty = QBCore.Shared.Jobs[PlayerData.job.name].defaultDuty + end + PlayerData.job.isboss = PlayerData.job.isboss or false + PlayerData.job.grade = PlayerData.job.grade or {} + PlayerData.job.grade.name = PlayerData.job.grade.name or 'Arbejdsløs' + PlayerData.job.grade.level = PlayerData.job.grade.level or 0 + -- Gang + if PlayerData.gang and PlayerData.gang.name and not QBCore.Shared.Gangs[PlayerData.gang.name] then PlayerData.gang = nil end + PlayerData.gang = PlayerData.gang or {} + PlayerData.gang.name = PlayerData.gang.name or 'Ingen bande' + PlayerData.gang.label = PlayerData.gang.label or 'Ingen banderelationer' + PlayerData.gang.isboss = PlayerData.gang.isboss or false + PlayerData.gang.grade = PlayerData.gang.grade or {} + PlayerData.gang.grade.name = PlayerData.gang.grade.name or 'Ingen stilling' + PlayerData.gang.grade.level = PlayerData.gang.grade.level or 0 + -- Other + PlayerData.playtime = PlayerData.playtime or 0 + PlayerData.position = PlayerData.position or QBConfig.DefaultSpawn + PlayerData.playerPhone = PlayerData.playerPhone or PlayerData.charinfo.phone + PlayerData.items = GetResourceState('ps-inventory') ~= 'missing' and exports['ps-inventory']:LoadInventory(PlayerData.source, PlayerData.citizenid) or {} + return QBCore.Player.CreatePlayer(PlayerData, Offline) +end + +-- On player logout + +function QBCore.Player.Logout(source) + TriggerClientEvent('QBCore:Client:OnPlayerUnload', source) + TriggerEvent('QBCore:Server:OnPlayerUnload', source) + TriggerClientEvent('QBCore:Player:UpdatePlayerData', source) + Wait(200) + QBCore.Players[source] = nil +end + +-- Create a new character +-- Don't touch any of this unless you know what you are doing +-- Will cause major issues! + +function QBCore.Player.CreatePlayer(PlayerData, Offline) + local self = {} + self.Functions = {} + self.PlayerData = PlayerData + self.Offline = Offline + + function self.Functions.UpdatePlayerData() + if self.Offline then return end -- Unsupported for Offline Players + TriggerEvent('QBCore:Player:SetPlayerData', self.PlayerData) + TriggerClientEvent('QBCore:Player:SetPlayerData', self.PlayerData.source, self.PlayerData) + end + + function self.Functions.SetJob(job, grade) + job = job:lower() + grade = tostring(grade) or '0' + if not QBCore.Shared.Jobs[job] then return false end + self.PlayerData.job.name = job + self.PlayerData.job.label = QBCore.Shared.Jobs[job].label + self.PlayerData.job.onduty = QBCore.Shared.Jobs[job].defaultDuty + self.PlayerData.job.type = QBCore.Shared.Jobs[job].type or 'none' + if QBCore.Shared.Jobs[job].grades[grade] then + local jobgrade = QBCore.Shared.Jobs[job].grades[grade] + self.PlayerData.job.grade = {} + self.PlayerData.job.grade.name = jobgrade.name + self.PlayerData.job.grade.level = tonumber(grade) + self.PlayerData.job.payment = jobgrade.payment or 30 + self.PlayerData.job.isboss = jobgrade.isboss or false + else + self.PlayerData.job.grade = {} + self.PlayerData.job.grade.name = 'Ingen stilling' + self.PlayerData.job.grade.level = 0 + self.PlayerData.job.payment = 30 + self.PlayerData.job.isboss = false + end + + if not self.Offline then + self.Functions.UpdatePlayerData() + TriggerEvent('QBCore:Server:OnJobUpdate', self.PlayerData.source, self.PlayerData.job) + TriggerClientEvent('QBCore:Client:OnJobUpdate', self.PlayerData.source, self.PlayerData.job) + end + + return true + end + + function self.Functions.UpdateNumber(newnumber) + self.PlayerData.charinfo.phone = newnumber + self.PlayerData.playerPhone = newnumber + self.Functions.UpdatePlayerData() + end + + function self.Functions.SetGang(gang, grade) + gang = gang:lower() + grade = tostring(grade) or '0' + if not QBCore.Shared.Gangs[gang] then return false end + self.PlayerData.gang.name = gang + self.PlayerData.gang.label = QBCore.Shared.Gangs[gang].label + if QBCore.Shared.Gangs[gang].grades[grade] then + local ganggrade = QBCore.Shared.Gangs[gang].grades[grade] + self.PlayerData.gang.grade = {} + self.PlayerData.gang.grade.name = ganggrade.name + self.PlayerData.gang.grade.level = tonumber(grade) + self.PlayerData.gang.isboss = ganggrade.isboss or false + else + self.PlayerData.gang.grade = {} + self.PlayerData.gang.grade.name = 'Ingen grad' + self.PlayerData.gang.grade.level = 0 + self.PlayerData.gang.isboss = false + end + + if not self.Offline then + self.Functions.UpdatePlayerData() + TriggerEvent('QBCore:Server:OnGangUpdate', self.PlayerData.source, self.PlayerData.gang) + TriggerClientEvent('QBCore:Client:OnGangUpdate', self.PlayerData.source, self.PlayerData.gang) + end + + return true + end + + function self.Functions.SetJobDuty(onDuty) + self.PlayerData.job.onduty = not not onDuty -- Make sure the value is a boolean if nil is sent + TriggerEvent('QBCore:Server:OnJobUpdate', self.PlayerData.source, self.PlayerData.job) + TriggerClientEvent('QBCore:Client:OnJobUpdate', self.PlayerData.source, self.PlayerData.job) + self.Functions.UpdatePlayerData() + end + + function self.Functions.SetPlayerData(key, val) + if not key or type(key) ~= 'string' then return end + self.PlayerData[key] = val + self.Functions.UpdatePlayerData() + end + + function self.Functions.SetMetaData(meta, val) + if not meta or type(meta) ~= 'string' then return end + if meta == 'hunger' or meta == 'thirst' then + val = val > 100 and 100 or val + end + self.PlayerData.metadata[meta] = val + self.Functions.UpdatePlayerData() + end + + function self.Functions.GetMetaData(meta) + if not meta or type(meta) ~= 'string' then return end + return self.PlayerData.metadata[meta] + end + + function self.Functions.AddJobReputation(amount) + if not amount then return end + amount = tonumber(amount) + self.PlayerData.metadata['jobrep'][self.PlayerData.job.name] = self.PlayerData.metadata['jobrep'][self.PlayerData.job.name] + amount + self.Functions.UpdatePlayerData() + end + + + function self.Functions.GetMoney(moneytype) + if not moneytype then + return false + end + + moneytype = moneytype:lower() + + return self.PlayerData.money[moneytype] or 0 -- Return 0 if the moneytype is not found + end + + + function self.Functions.AddMoney(moneytype, amount, reason) + reason = reason or 'unknown' + moneytype = moneytype:lower() + amount = tonumber(amount) + if amount < 0 then return end + if not self.PlayerData.money[moneytype] then return false end + self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] + amount + + if not self.Offline then + self.Functions.UpdatePlayerData() + TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'AddMoney', 'lightgreen', string.format("** %s (citizenid: %s | id: %s) ** $%s (%s) added, new %s balance: %s reason: %s",GetPlayerName(self.PlayerData.source),self.PlayerData.citizenid,self.PlayerData.source,amount,moneytype,moneytype,self.PlayerData.money[moneytype],reason)) + TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, false) + TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, "add", reason) + TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, "add", reason) + end + + return true + end + + function self.Functions.RemoveMoney(moneytype, amount, reason) + reason = reason or 'unknown' + moneytype = moneytype:lower() + amount = tonumber(amount) + if amount < 0 then return end + if not self.PlayerData.money[moneytype] then return false end + for _, mtype in pairs(QBCore.Config.Money.DontAllowMinus) do + if mtype == moneytype then + if (self.PlayerData.money[moneytype] - amount) < 0 then + return false + end + end + end + self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] - amount + + if not self.Offline then + self.Functions.UpdatePlayerData() + TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'RemoveMoney', 'red', string.format("** %s (citizenid: %s | id: %s)** $%s (%s) removed, new %s balance: %s reason: %s",GetPlayerName(self.PlayerData.source),self.PlayerData.citizenid,self.PlayerData.source,amount,moneytype,moneytype,self.PlayerData.money[moneytype],reason)) + TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, true) + if moneytype == 'bank' then + TriggerClientEvent('qb-phone:client:RemoveBankMoney', self.PlayerData.source, amount) + end + TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, "remove", reason) + TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, "remove", reason) + end + + return true + end + + function self.Functions.SetMoney(moneytype, amount, reason) + reason = reason or 'unknown' + moneytype = moneytype:lower() + amount = tonumber(amount) + if amount < 0 then return false end + if not self.PlayerData.money[moneytype] then return false end + local difference = amount - self.PlayerData.money[moneytype] + self.PlayerData.money[moneytype] = amount + + if not self.Offline then + self.Functions.UpdatePlayerData() + TriggerEvent('qb-log:server:CreateLog', 'playermoney', 'SetMoney', 'green', string.format("** %s (citizenid: %s | id: %s)** $%s (%s) set, new %s balance: %s reason: %s",GetPlayerName(self.PlayerData.source),self.PlayerData.citizenid,self.PlayerData.source,amount,moneytype,moneytype,self.PlayerData.money[moneytype],reason)) + TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, math.abs(difference), difference < 0) + TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, "set", reason) + TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, "set", reason) + end + + return true + end + + function self.Functions.SetCreditCard(cardNumber) + self.PlayerData.charinfo.card = cardNumber + self.Functions.UpdatePlayerData() + end + + function self.Functions.GetCardSlot(cardNumber, cardType) + local item = tostring(cardType):lower() + local slots = exports['ps-inventory']:GetSlotsByItem(self.PlayerData.items, item) + for _, slot in pairs(slots) do + if slot then + if self.PlayerData.items[slot].info.cardNumber == cardNumber then + return slot + end + end + end + return nil + end + + function self.Functions.Save() + if self.Offline then + QBCore.Player.SaveOffline(self.PlayerData) + else + QBCore.Player.Save(self.PlayerData.source) + end + end + + function self.Functions.Logout() + if self.Offline then return end -- Unsupported for Offline Players + QBCore.Player.Logout(self.PlayerData.source) + end + + function self.Functions.AddMethod(methodName, handler) + self.Functions[methodName] = handler + end + + function self.Functions.AddField(fieldName, data) + self[fieldName] = data + end + + if self.Offline then + return self + else + QBCore.Players[self.PlayerData.source] = self + QBCore.Player.Save(self.PlayerData.source) + + -- At this point we are safe to emit new instance to third party resource for load handling + TriggerEvent('QBCore:Server:PlayerLoaded', self) + self.Functions.UpdatePlayerData() + end +end + +-- Add a new function to the Functions table of the player class +-- Use-case: +--[[ + AddEventHandler('QBCore:Server:PlayerLoaded', function(Player) + QBCore.Functions.AddPlayerMethod(Player.PlayerData.source, "functionName", function(oneArg, orMore) + -- do something here + end) + end) +]] + +function QBCore.Functions.AddPlayerMethod(ids, methodName, handler) + local idType = type(ids) + if idType == "number" then + if ids == -1 then + for _, v in pairs(QBCore.Players) do + v.Functions.AddMethod(methodName, handler) + end + else + if not QBCore.Players[ids] then return end + + QBCore.Players[ids].Functions.AddMethod(methodName, handler) + end + elseif idType == "table" and table.type(ids) == "array" then + for i = 1, #ids do + QBCore.Functions.AddPlayerMethod(ids[i], methodName, handler) + end + end +end + +-- Add a new field table of the player class +-- Use-case: +--[[ + AddEventHandler('QBCore:Server:PlayerLoaded', function(Player) + QBCore.Functions.AddPlayerField(Player.PlayerData.source, "fieldName", "fieldData") + end) +]] + +function QBCore.Functions.AddPlayerField(ids, fieldName, data) + local idType = type(ids) + if idType == "number" then + if ids == -1 then + for _, v in pairs(QBCore.Players) do + v.Functions.AddField(fieldName, data) + end + else + if not QBCore.Players[ids] then return end + + QBCore.Players[ids].Functions.AddField(fieldName, data) + end + elseif idType == "table" and table.type(ids) == "array" then + for i = 1, #ids do + QBCore.Functions.AddPlayerField(ids[i], fieldName, data) + end + end +end + +-- Save player info to database (make sure citizenid is the primary key in your database) + +function QBCore.Player.Save(source) + local ped = GetPlayerPed(source) + local pcoords = GetEntityCoords(ped) + local PlayerData = QBCore.Players[source].PlayerData + if PlayerData then + MySQL.insert('INSERT INTO players (citizenid, cid, license, name, money, charinfo, job, gang, position, metadata, playtime) VALUES (:citizenid, :cid, :license, :name, :money, :charinfo, :job, :gang, :position, :metadata, :playtime) ON DUPLICATE KEY UPDATE cid = :cid, name = :name, money = :money, charinfo = :charinfo, job = :job, gang = :gang, position = :position, metadata = :metadata, playtime = :playtime', { + citizenid = PlayerData.citizenid, + cid = tonumber(PlayerData.cid), + license = PlayerData.license, + name = PlayerData.name, + money = json.encode(PlayerData.money), + charinfo = json.encode(PlayerData.charinfo), + job = json.encode(PlayerData.job), + gang = json.encode(PlayerData.gang), + position = json.encode(pcoords), + metadata = json.encode(PlayerData.metadata), + playtime = PlayerData.playtime + }) + if GetResourceState('ps-inventory') ~= 'missing' then exports['ps-inventory']:SaveInventory(source) end + -- QBCore.ShowSuccess(GetCurrentResourceName(), PlayerData.name .. ' PLAYER SAVED!') + else + QBCore.ShowError(GetCurrentResourceName(), 'ERROR QBCORE.PLAYER.SAVE - PLAYERDATA IS EMPTY!') + end +end + +function QBCore.Player.SaveOffline(PlayerData) + if PlayerData then + MySQL.Async.insert('INSERT INTO players (citizenid, cid, license, name, money, charinfo, job, gang, position, metadata, playtime) VALUES (:citizenid, :cid, :license, :name, :money, :charinfo, :job, :gang, :position, :metadata, :playtime) ON DUPLICATE KEY UPDATE cid = :cid, name = :name, money = :money, charinfo = :charinfo, job = :job, gang = :gang, position = :position, metadata = :metadata, playtime = :playtime', { + citizenid = PlayerData.citizenid, + cid = tonumber(PlayerData.cid), + license = PlayerData.license, + name = PlayerData.name, + money = json.encode(PlayerData.money), + charinfo = json.encode(PlayerData.charinfo), + job = json.encode(PlayerData.job), + gang = json.encode(PlayerData.gang), + position = json.encode(PlayerData.position), + metadata = json.encode(PlayerData.metadata), + playtime = PlayerData.playtime + }) + if GetResourceState('ps-inventory') ~= 'missing' then exports['ps-inventory']:SaveInventory(PlayerData, true) end + -- QBCore.ShowSuccess(GetCurrentResourceName(), PlayerData.name .. ' OFFLINE PLAYER SAVED!') + else + QBCore.ShowError(GetCurrentResourceName(), 'ERROR QBCORE.PLAYER.SAVEOFFLINE - PLAYERDATA IS EMPTY!') + end +end + +-- Delete character + +local playertables = { -- Add tables as needed + { table = 'players' }, + { table = 'apartments' }, + { table = 'bank_accounts' }, + { table = 'crypto_transactions' }, + { table = 'phone_invoices' }, + { table = 'phone_messages' }, + { table = 'playerskins' }, + { table = 'player_contacts' }, + { table = 'player_houses' }, + { table = 'player_mails' }, + { table = 'player_outfits' }, + { table = 'player_vehicles' } +} + +function QBCore.Player.DeleteCharacter(source, citizenid) + local license = QBCore.Functions.GetIdentifier(source, 'license') + local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { citizenid }) + if license == result then + local query = "DELETE FROM %s WHERE citizenid = ?" + local tableCount = #playertables + local queries = table.create(tableCount, 0) + + for i = 1, tableCount do + local v = playertables[i] + queries[i] = {query = query:format(v.table), values = { citizenid }} + end + + MySQL.transaction(queries, function(result2) + if result2 then + TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Deleted', 'red', string.format("** %s ** %s deleted ** %s **",GetPlayerName(source),license,citizenid)) + end + end) + else + DropPlayer(source, Lang:t("info.exploit_dropped")) + riggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'white', string.format("%s Has Been Dropped For Character Deletion Exploit",GetPlayerName(source))) + end +end + +function QBCore.Player.ForceDeleteCharacter(citizenid) + local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { citizenid }) + if result then + local query = "DELETE FROM %s WHERE citizenid = ?" + local tableCount = #playertables + local queries = table.create(tableCount, 0) + local Player = QBCore.Functions.GetPlayerByCitizenId(citizenid) + + if Player then + DropPlayer(Player.PlayerData.source, "An admin deleted the character which you are currently using") + end + for i = 1, tableCount do + local v = playertables[i] + queries[i] = {query = query:format(v.table), values = { citizenid }} + end + + MySQL.transaction(queries, function(result2) + if result2 then + TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Force Deleted', 'red', string.format("Character ** %s ** got deleted",citizenid)) + end + end) + end +end + +-- Inventory Backwards Compatibility + +function QBCore.Player.SaveInventory(source) + if GetResourceState('ps-inventory') == 'missing' then return end + exports['ps-inventory']:SaveInventory(source, false) +end + +function QBCore.Player.SaveOfflineInventory(PlayerData) + if GetResourceState('ps-inventory') == 'missing' then return end + exports['ps-inventory']:SaveInventory(PlayerData, true) +end + +function QBCore.Player.GetTotalWeight(items) + if GetResourceState('ps-inventory') == 'missing' then return end + return exports['ps-inventory']:GetTotalWeight(items) +end + +function QBCore.Player.GetSlotsByItem(items, itemName) + if GetResourceState('ps-inventory') == 'missing' then return end + return exports['ps-inventory']:GetSlotsByItem(items, itemName) +end + +function QBCore.Player.GetFirstSlotByItem(items, itemName) + if GetResourceState('ps-inventory') == 'missing' then return end + return exports['ps-inventory']:GetFirstSlotByItem(items, itemName) +end + +-- Util Functions + +function QBCore.Player.CreateCitizenId() + local UniqueFound = false + local CitizenId = nil + while not UniqueFound do + CitizenId = tostring(QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(5)):upper() + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM players WHERE citizenid = ?', { CitizenId }) + if result == 0 then + UniqueFound = true + end + end + return CitizenId +end + +function QBCore.Functions.CreateAccountNumber() + local UniqueFound = false + local AccountNumber = nil + while not UniqueFound do + AccountNumber = 'DK0' .. math.random(1, 9) .. 'HPReb' .. math.random(1111, 9999) .. math.random(1111, 9999) .. math.random(11, 99) + local query = '%' .. AccountNumber .. '%' + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM players WHERE charinfo LIKE ?', { query }) + if result == 0 then + UniqueFound = true + end + end + return AccountNumber +end + +function QBCore.Functions.CreatePhoneNumber() + local UniqueFound = false + local PhoneNumber = nil + while not UniqueFound do + PhoneNumber = "45"..math.random(10000000,99999999) + local query = '%' .. PhoneNumber .. '%' + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM players WHERE charinfo LIKE ?', { query }) + if result == 0 then + UniqueFound = true + end + end + return PhoneNumber +end + +function QBCore.Player.CreateFingerId() + local UniqueFound = false + local FingerId = nil + while not UniqueFound do + FingerId = tostring(QBCore.Shared.RandomStr(2) .. QBCore.Shared.RandomInt(3) .. QBCore.Shared.RandomStr(1) .. QBCore.Shared.RandomInt(2) .. QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(4)) + local query = '%' .. FingerId .. '%' + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM `players` WHERE `metadata` LIKE ?', { query }) + if result == 0 then + UniqueFound = true + end + end + return FingerId +end + +function QBCore.Player.CreateWalletId() + local UniqueFound = false + local WalletId = nil + while not UniqueFound do + WalletId = 'HP-' .. math.random(11111111, 99999999) + local query = '%' .. WalletId .. '%' + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM players WHERE metadata LIKE ?', { query }) + if result == 0 then + UniqueFound = true + end + end + return WalletId +end + +function QBCore.Player.CreateSerialNumber() + local UniqueFound = false + local SerialNumber = nil + while not UniqueFound do + SerialNumber = math.random(11111111, 99999999) + local query = '%' .. SerialNumber .. '%' + local result = MySQL.prepare.await('SELECT COUNT(*) as count FROM players WHERE metadata LIKE ?', { query }) + if result == 0 then + UniqueFound = true + end + end + return SerialNumber +end + +PaycheckInterval() -- This starts the paycheck system diff --git a/resources/[qb]/qb-core/shared/gangs.lua b/resources/[qb]/qb-core/shared/gangs.lua new file mode 100644 index 0000000..3598962 --- /dev/null +++ b/resources/[qb]/qb-core/shared/gangs.lua @@ -0,0 +1,96 @@ +QBShared = QBShared or {} +QBShared.Gangs = { + ['none'] = { + label = 'Ingen bande', + grades = { + ['0'] = { + name = 'Uaffilieret' + }, + }, + }, + ['lostmc'] = { + label = 'The Lost MC', + grades = { + ['0'] = { + name = 'Rekrut' + }, + ['1'] = { + name = 'Enforcer' + }, + ['2'] = { + name = 'Shot Caller' + }, + ['3'] = { + name = 'Boss', + }, + }, + }, + ['ballas'] = { + label = 'Ballas', + grades = { + ['0'] = { + name = 'Rekrut' + }, + ['1'] = { + name = 'Enforcer' + }, + ['2'] = { + name = 'Shot Caller' + }, + ['3'] = { + name = 'Boss', + }, + }, + }, + ['vagos'] = { + label = 'Vagos', + grades = { + ['0'] = { + name = 'Rekrut' + }, + ['1'] = { + name = 'Enforcer' + }, + ['2'] = { + name = 'Shot Caller' + }, + ['3'] = { + name = 'Boss', + }, + }, + }, + ['families'] = { + label = 'Families', + grades = { + ['0'] = { + name = 'Rekrut' + }, + ['1'] = { + name = 'Enforcer' + }, + ['2'] = { + name = 'Shot Caller' + }, + ['3'] = { + name = 'Boss', + }, + }, + }, + ['marabunta'] = { + label = 'Marabunta', + grades = { + ['0'] = { + name = 'Rekrut' + }, + ['1'] = { + name = 'Enforcer' + }, + ['2'] = { + name = 'Shot Caller' + }, + ['3'] = { + name = 'Boss', + }, + }, + } +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/shared/items.lua b/resources/[qb]/qb-core/shared/items.lua new file mode 100644 index 0000000..defb562 --- /dev/null +++ b/resources/[qb]/qb-core/shared/items.lua @@ -0,0 +1,3403 @@ +QBShared = QBShared or {} +QBShared.Items = { + + -- ['cash'] = {['name'] = 'cash', ['label'] = 'Cash', ['weight'] = 0, ['type'] = 'item', ['image'] = 'cash.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'cash'}, + -- WEAPONS + + -- Melee + ['weapon_unarmed'] = {['name'] = 'weapon_unarmed', ['label'] = 'Fists', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'placeholder.png', ['unique'] = true, ['useable'] = false, ['description'] = 'Fisticuffs'}, + ['weapon_dagger'] = {['name'] = 'weapon_dagger', ['label'] = 'Dagger', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_dagger.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A short knife with a pointed and edged blade, used as a weapon'}, + ['weapon_bat'] = {['name'] = 'weapon_bat', ['label'] = 'Bat', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_bat.png', ['unique'] = true, ['useable'] = false, ['description'] = 'Used for hitting a ball in sports (or other things)'}, + ['weapon_bottle'] = {['name'] = 'weapon_bottle', ['label'] = 'Broken Bottle', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_bottle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A broken bottle'}, + ['weapon_crowbar'] = {['name'] = 'weapon_crowbar', ['label'] = 'Crowbar', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_crowbar.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An iron bar with a flattened end, used as a lever'}, + ['weapon_flashlight'] = {['name'] = 'weapon_flashlight', ['label'] = 'Flashlight', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_flashlight.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A battery-operated portable light'}, + ['weapon_golfclub'] = {['name'] = 'weapon_golfclub', ['label'] = 'Golfclub', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_golfclub.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A club used to hit the ball in golf'}, + ['weapon_hammer'] = {['name'] = 'weapon_hammer', ['label'] = 'Hammer', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_hammer.png', ['unique'] = true, ['useable'] = false, ['description'] = 'Used for jobs such as breaking things (legs) and driving in nails'}, + ['weapon_hatchet'] = {['name'] = 'weapon_hatchet', ['label'] = 'Hatchet', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_hatchet.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A small axe with a short handle for use in one hand'}, + ['weapon_knuckle'] = {['name'] = 'weapon_knuckle', ['label'] = 'Knuckle', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_knuckle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A metal guard worn over the knuckles in fighting, especially to increase the effect of the blows'}, + ['weapon_knife'] = {['name'] = 'weapon_knife', ['label'] = 'Knife', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_knife.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An instrument composed of a blade fixed into a handle, used for cutting or as a weapon'}, + ['weapon_machete'] = {['name'] = 'weapon_machete', ['label'] = 'Machete', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_machete.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A broad, heavy knife used as a weapon'}, + ['weapon_switchblade'] = {['name'] = 'weapon_switchblade', ['label'] = 'Switchblade', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_switchblade.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A knife with a blade that springs out from the handle when a button is pressed'}, + ['weapon_nightstick'] = {['name'] = 'weapon_nightstick', ['label'] = 'Nightstick', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_nightstick.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A police officer\'s club or billy'}, + ['weapon_wrench'] = {['name'] = 'weapon_wrench', ['label'] = 'Wrench', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_wrench.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A tool used for gripping and turning nuts, bolts, pipes, etc'}, + ['weapon_battleaxe'] = {['name'] = 'weapon_battleaxe', ['label'] = 'Battle Axe', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_battleaxe.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A large broad-bladed axe used in ancient warfare'}, + ['weapon_poolcue'] = {['name'] = 'weapon_poolcue', ['label'] = 'Poolcue', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_poolcue.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A stick used to strike a ball, usually the cue ball (or other things)'}, + ['weapon_briefcase'] = {['name'] = 'weapon_briefcase', ['label'] = 'Briefcase', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_briefcase.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A briefcase for storing important documents'}, + ['weapon_briefcase_02'] = {['name'] = 'weapon_briefcase_02', ['label'] = 'Suitcase', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_briefcase2.png', ['unique'] = true, ['useable'] = false, ['description'] = 'Wonderfull for nice vacation to Liberty City'}, + ['weapon_garbagebag'] = {['name'] = 'weapon_garbagebag', ['label'] = 'Garbage Bag', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_garbagebag.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A garbage bag'}, + ['weapon_handcuffs'] = {['name'] = 'weapon_handcuffs', ['label'] = 'Handcuffs', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_handcuffs.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A pair of lockable linked metal rings for securing a prisoner\'s wrists'}, + ['weapon_bread'] = {['name'] = 'weapon_bread', ['label'] = 'Baquette', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'baquette.png', ['unique'] = true, ['useable'] = false, ['description'] = 'Bread...?'}, + ['weapon_shoe'] = {['name'] = 'weapon_shoe', ['label'] = 'Shoe', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_shoe.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A shoe'}, + ['weapon_stone_hatchet'] = {['name'] = 'weapon_stone_hatchet', ['label'] = 'Stone Hatchet', ['weight'] = 100, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_stone_hatchet.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Stone ax'}, + + -- Melee + ['weapon_candycane'] = {['name'] = 'weapon_candycane', ['label'] = 'Candy Cane', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_candycane.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Candy Cane'}, + -- Pistols + ['weapon_pistolxm3'] = {['name'] = 'weapon_pistolxm3', ['label'] = 'Pistol XM3', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_pistolxm3.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Pistol XM3'}, + --Heavy Weapons + ['weapon_railgunxm3'] = {['name'] = 'weapon_railgunxm3', ['label'] = 'Railgun XM3', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_railgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A weapon that uses electromagnetic force to launch high velocity projectiles'}, + + -- Handguns + ['weapon_pistol'] = {['name'] = 'weapon_pistol', ['label'] = 'Walther P99', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_pistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A small firearm designed to be held in one hand'}, + ['weapon_pistol_mk2'] = {['name'] = 'weapon_pistol_mk2', ['label'] = 'Pistol Mk II', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_pistol_mk2.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An upgraded small firearm designed to be held in one hand'}, + ['weapon_combatpistol'] = {['name'] = 'weapon_combatpistol', ['label'] = 'Combat Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_combatpistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A combat version small firearm designed to be held in one hand'}, + ['weapon_appistol'] = {['name'] = 'weapon_appistol', ['label'] = 'AP Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_appistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A small firearm designed to be held in one hand that is automatic'}, + ['weapon_stungun'] = {['name'] = 'weapon_stungun', ['label'] = 'Taser', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_stungun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A weapon firing barbs attached by wires to batteries, causing temporary paralysis'}, + ['weapon_pistol50'] = {['name'] = 'weapon_pistol50', ['label'] = 'Pistol .50', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_pistol50.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A .50 caliber firearm designed to be held with both hands'}, + ['weapon_snspistol'] = {['name'] = 'weapon_snspistol', ['label'] = 'SNS Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_snspistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A very small firearm designed to be easily concealed'}, + ['weapon_heavypistol'] = {['name'] = 'weapon_heavypistol', ['label'] = 'Heavy Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_heavypistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A hefty firearm designed to be held in one hand (or attempted)'}, + ['weapon_vintagepistol'] = {['name'] = 'weapon_vintagepistol', ['label'] = 'Vintage Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_vintagepistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An antique firearm designed to be held in one hand'}, + ['weapon_flaregun'] = {['name'] = 'weapon_flaregun', ['label'] = 'Flare Gun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_FLARE', ['image'] = 'weapon_flaregun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A handgun for firing signal rockets'}, + ['weapon_marksmanpistol'] = {['name'] = 'weapon_marksmanpistol', ['label'] = 'Marksman Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_marksmanpistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A very accurate small firearm designed to be held in one hand'}, + ['weapon_revolver'] = {['name'] = 'weapon_revolver', ['label'] = 'Revolver', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_revolver.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A pistol with revolving chambers enabling several shots to be fired without reloading'}, + ['weapon_revolver_mk2'] = {['name'] = 'weapon_revolver_mk2', ['label'] = 'Violence', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_revolver_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'da Violence'}, + ['weapon_doubleaction'] = {['name'] = 'weapon_doubleaction', ['label'] = 'Double Action Revolver', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_doubleaction.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Double Action Revolver'}, + ['weapon_snspistol_mk2'] = {['name'] = 'weapon_snspistol_mk2', ['label'] = 'SNS Pistol Mk II', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_snspistol_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'SNS Pistol MK2'}, + ['weapon_raypistol'] = {['name'] = 'weapon_raypistol', ['label'] = 'Up-n-Atomizer', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_raypistol.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Raypistol'}, + ['weapon_ceramicpistol'] = {['name'] = 'weapon_ceramicpistol', ['label'] = 'Ceramic Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_ceramicpistol.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Ceramicpistol'}, + ['weapon_navyrevolver'] = {['name'] = 'weapon_navyrevolver', ['label'] = 'Navy Revolver', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_navyrevolver.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Navyrevolver'}, + ['weapon_gadgetpistol'] = {['name'] = 'weapon_gadgetpistol', ['label'] = 'Perico Pistol', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_gadgetpistol.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Gadgetpistol'}, + + -- Submachine Guns + ['weapon_microsmg'] = {['name'] = 'weapon_microsmg', ['label'] = 'Micro SMG', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_microsmg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A handheld lightweight machine gun'}, + ['weapon_smg'] = {['name'] = 'weapon_smg', ['label'] = 'SMG', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_smg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A handheld lightweight machine gun'}, + ['weapon_smg_mk2'] = {['name'] = 'weapon_smg_mk2', ['label'] = 'SMG Mk II', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_smg_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'SMG MK2'}, + ['weapon_assaultsmg'] = {['name'] = 'weapon_assaultsmg', ['label'] = 'Assault SMG', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_assaultsmg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An assault version of a handheld lightweight machine gun'}, + ['weapon_combatpdw'] = {['name'] = 'weapon_combatpdw', ['label'] = 'Combat PDW', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_combatpdw.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A combat version of a handheld lightweight machine gun'}, + ['weapon_machinepistol'] = {['name'] = 'weapon_machinepistol', ['label'] = 'Tec-9', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PISTOL', ['image'] = 'weapon_machinepistol.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A self-loading pistol capable of burst or fully automatic fire'}, + ['weapon_minismg'] = {['name'] = 'weapon_minismg', ['label'] = 'Mini SMG', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_minismg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A mini handheld lightweight machine gun'}, + ['weapon_raycarbine'] = {['name'] = 'weapon_raycarbine', ['label'] = 'Unholy Hellbringer', ['weight'] = 800, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SMG', ['image'] = 'weapon_raycarbine.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Raycarbine'}, + + -- Shotguns + ['weapon_pumpshotgun'] = {['name'] = 'weapon_pumpshotgun', ['label'] = 'Pump Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_pumpshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A pump-action smoothbore gun for firing small shot at short range'}, + ['weapon_sawnoffshotgun'] = {['name'] = 'weapon_sawnoffshotgun', ['label'] = 'Sawn-off Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_sawnoffshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A sawn-off smoothbore gun for firing small shot at short range'}, + ['weapon_assaultshotgun'] = {['name'] = 'weapon_assaultshotgun', ['label'] = 'Assault Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_assaultshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An assault version of asmoothbore gun for firing small shot at short range'}, + ['weapon_bullpupshotgun'] = {['name'] = 'weapon_bullpupshotgun', ['label'] = 'Bullpup Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_bullpupshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A compact smoothbore gun for firing small shot at short range'}, + ['weapon_musket'] = {['name'] = 'weapon_musket', ['label'] = 'Musket', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_musket.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An infantryman\'s light gun with a long barrel, typically smooth-bored, muzzleloading, and fired from the shoulder'}, + ['weapon_heavyshotgun'] = {['name'] = 'weapon_heavyshotgun', ['label'] = 'Heavy Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_heavyshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A large smoothbore gun for firing small shot at short range'}, + ['weapon_dbshotgun'] = {['name'] = 'weapon_dbshotgun', ['label'] = 'Double-barrel Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_dbshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A shotgun with two parallel barrels, allowing two single shots to be fired in quick succession'}, + ['weapon_autoshotgun'] = {['name'] = 'weapon_autoshotgun', ['label'] = 'Auto Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_autoshotgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A shotgun capable of rapid continous fire'}, + ['weapon_pumpshotgun_mk2'] = {['name'] = 'weapon_pumpshotgun_mk2', ['label'] = 'Pumpshotgun Mk II', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_pumpshotgun_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Pumpshotgun MK2'}, + ['weapon_combatshotgun'] = {['name'] = 'weapon_combatshotgun', ['label'] = 'Combat Shotgun', ['weight'] = 600, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SHOTGUN', ['image'] = 'weapon_combatshotgun.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Combatshotgun'}, + + -- Assault Rifles + ['weapon_assaultrifle'] = {['name'] = 'weapon_assaultrifle', ['label'] = 'Assault Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_assaultrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A rapid-fire, magazine-fed automatic rifle designed for infantry use'}, + ['weapon_assaultrifle_mk2'] = {['name'] = 'weapon_assaultrifle_mk2', ['label'] = 'Assault Rifle Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_assaultrifle_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Assault Rifle MK2'}, + ['weapon_tacticalrifle'] = {['name'] = 'weapon_tacticalrifle', ['label'] = 'Service Carbine', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_tacticalrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A M16-based service rifle'}, + ['weapon_carbinerifle'] = {['name'] = 'weapon_carbinerifle', ['label'] = 'Carbine Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_carbinerifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A lightweight automatic rifle'}, + ['weapon_carbinerifle_mk2'] = {['name'] = 'weapon_carbinerifle_mk2', ['label'] = 'Carbine Rifle Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_carbinerifle_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Carbine Rifle MK2'}, + ['weapon_advancedrifle'] = {['name'] = 'weapon_advancedrifle', ['label'] = 'Advanced Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_advancedrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An assault version of a rapid-fire, magazine-fed automatic rifle designed for infantry use'}, + ['weapon_specialcarbine'] = {['name'] = 'weapon_specialcarbine', ['label'] = 'Special Carbine', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_specialcarbine.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An extremely versatile assault rifle for any combat situation'}, + ['weapon_bullpuprifle'] = {['name'] = 'weapon_bullpuprifle', ['label'] = 'Bullpup Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_bullpuprifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A compact automatic assault rifle'}, + ['weapon_compactrifle'] = {['name'] = 'weapon_compactrifle', ['label'] = 'Compact Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_compactrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A compact version of an assault rifle'}, + ['weapon_specialcarbine_mk2'] = {['name'] = 'weapon_specialcarbine_mk2', ['label'] = 'Special Carbine Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_specialcarbine_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Wpecialcarbine MK2'}, + ['weapon_bullpuprifle_mk2'] = {['name'] = 'weapon_bullpuprifle_mk2', ['label'] = 'Bullpup Rifle Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_bullpuprifle_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Bull Puprifle MK2'}, + ['weapon_militaryrifle'] = {['name'] = 'weapon_militaryrifle', ['label'] = 'Military Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RIFLE', ['image'] = 'weapon_militaryrifle.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Militaryrifle'}, + + -- Light Machine Guns + ['weapon_mg'] = {['name'] = 'weapon_mg', ['label'] = 'Machinegun', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MG', ['image'] = 'weapon_mg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An automatic gun that fires bullets in rapid succession for as long as the trigger is pressed'}, + ['weapon_combatmg'] = {['name'] = 'weapon_combatmg', ['label'] = 'Combat MG', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MG', ['image'] = 'weapon_combatmg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A combat version of an automatic gun that fires bullets in rapid succession for as long as the trigger is pressed'}, + ['weapon_gusenberg'] = {['name'] = 'weapon_gusenberg', ['label'] = 'Thompson SMG', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MG', ['image'] = 'weapon_gusenberg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An automatic rifle commonly referred to as a tommy gun'}, + ['weapon_combatmg_mk2'] = {['name'] = 'weapon_combatmg_mk2', ['label'] = 'Combat MG Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MG', ['image'] = 'weapon_combatmg_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Combatmg MK2'}, + + -- Sniper Rifles + ['weapon_sniperrifle'] = {['name'] = 'weapon_sniperrifle', ['label'] = 'Sniper Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER', ['image'] = 'weapon_sniperrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A high-precision, long-range rifle'}, + ['weapon_heavysniper'] = {['name'] = 'weapon_heavysniper', ['label'] = 'Heavy Sniper', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER', ['image'] = 'weapon_heavysniper.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An upgraded high-precision, long-range rifle'}, + ['weapon_marksmanrifle'] = {['name'] = 'weapon_marksmanrifle', ['label'] = 'Marksman Rifle', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER', ['image'] = 'weapon_marksmanrifle.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A very accurate single-fire rifle'}, + ['weapon_remotesniper'] = {['name'] = 'weapon_remotesniper', ['label'] = 'Remote Sniper', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER_REMOTE', ['image'] = 'weapon_remotesniper.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A portable high-precision, long-range rifle'}, + ['weapon_heavysniper_mk2'] = {['name'] = 'weapon_heavysniper_mk2', ['label'] = 'Heavy Sniper Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER', ['image'] = 'weapon_heavysniper_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Heavysniper MK2'}, + ['weapon_marksmanrifle_mk2'] = {['name'] = 'weapon_marksmanrifle_mk2', ['label'] = 'Marksman Rifle Mk II', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_SNIPER', ['image'] = 'weapon_marksmanrifle_mk2.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Marksmanrifle MK2'}, + + -- Heavy Weapons + ['weapon_rpg'] = {['name'] = 'weapon_rpg', ['label'] = 'RPG', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_RPG', ['image'] = 'weapon_rpg.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A rocket-propelled grenade launcher'}, + ['weapon_grenadelauncher'] = {['name'] = 'weapon_grenadelauncher', ['label'] = 'Grenade Launcher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_GRENADELAUNCHER', ['image'] = 'weapon_grenadelauncher.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A weapon that fires a specially-designed large-caliber projectile, often with an explosive, smoke or gas warhead'}, + ['weapon_grenadelauncher_smoke'] = {['name'] = 'weapon_grenadelauncher_smoke', ['label'] = 'Smoke Grenade Launcher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_GRENADELAUNCHER', ['image'] = 'weapon_smokegrenade.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A bomb that produces a lot of smoke when it explodes'}, + ['weapon_minigun'] = {['name'] = 'weapon_minigun', ['label'] = 'Minigun', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MINIGUN', ['image'] = 'weapon_minigun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A portable machine gun consisting of a rotating cluster of six barrels and capable of variable rates of fire of up to 6,000 rounds per minute'}, + ['weapon_firework'] = {['name'] = 'weapon_firework', ['label'] = 'Firework Launcher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_firework.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A device containing gunpowder and other combustible chemicals that causes a spectacular explosion when ignited'}, + ['weapon_railgun'] = {['name'] = 'weapon_railgun', ['label'] = 'Railgun', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_railgun.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A weapon that uses electromagnetic force to launch high velocity projectiles'}, + ['weapon_hominglauncher'] = {['name'] = 'weapon_hominglauncher', ['label'] = 'Homing Launcher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_STINGER', ['image'] = 'weapon_hominglauncher.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A weapon fitted with an electronic device that enables it to find and hit a target'}, + ['weapon_compactlauncher'] = {['name'] = 'weapon_compactlauncher', ['label'] = 'Compact Launcher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_compactlauncher.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A compact grenade launcher'}, + ['weapon_rayminigun'] = {['name'] = 'weapon_rayminigun', ['label'] = 'Widowmaker', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_MINIGUN', ['image'] = 'weapon_rayminigun.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Rayminigun'}, + + -- Throwables + ['weapon_grenade'] = {['name'] = 'weapon_grenade', ['label'] = 'Grenade', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_grenade.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A handheld throwable bomb'}, + ['weapon_bzgas'] = {['name'] = 'weapon_bzgas', ['label'] = 'BZ Gas', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_bzgas.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A cannister of gas that causes extreme pain'}, + ['weapon_molotov'] = {['name'] = 'weapon_molotov', ['label'] = 'Molotov', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_molotov.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A crude bomb made of a bottle filled with a flammable liquid and fitted with a wick for lighting'}, + ['weapon_stickybomb'] = {['name'] = 'weapon_stickybomb', ['label'] = 'C4', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_stickybomb.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An explosive charge covered with an adhesive that when thrown against an object sticks until it explodes'}, + ['weapon_proxmine'] = {['name'] = 'weapon_proxmine', ['label'] = 'Proxmine Grenade', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_proximitymine.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A bomb placed on the ground that detonates when going within its proximity'}, + ['weapon_snowball'] = {['name'] = 'weapon_snowball', ['label'] = 'Snowball', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_snowball.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A ball of packed snow, especially one made for throwing at other people for fun'}, + ['weapon_pipebomb'] = {['name'] = 'weapon_pipebomb', ['label'] = 'Pipe Bomb', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_pipebomb.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A homemade bomb, the components of which are contained in a pipe'}, + ['weapon_ball'] = {['name'] = 'weapon_ball', ['label'] = 'Ball', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_BALL', ['image'] = 'weapon_ball.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A solid or hollow spherical or egg-shaped object that is kicked, thrown, or hit in a game'}, + ['weapon_smokegrenade'] = {['name'] = 'weapon_smokegrenade', ['label'] = 'Smoke Grenade', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_c4.png', ['unique'] = true, ['useable'] = false, ['description'] = 'An explosive charge that can be remotely detonated'}, + ['weapon_flare'] = {['name'] = 'weapon_flare', ['label'] = 'Flare pistol', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_FLARE', ['image'] = 'weapon_flare.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A small pyrotechnic devices used for illumination and signalling'}, + + -- Miscellaneous + ['fuelsiphon'] = {['name'] = 'fuelsiphon', ['label'] = 'Fuel Siphon', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'fuelsiphon.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A fuel siphon to extract fuel from vehicles'}, + ['weapon_petrolcan'] = {['name'] = 'weapon_petrolcan', ['label'] = 'Petrol Can', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PETROLCAN', ['image'] = 'weapon_petrolcan.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A robust liquid container made from pressed steel'}, + ['weapon_fireextinguisher'] = {['name'] = 'weapon_fireextinguisher', ['label'] = 'Fire Extinguisher', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = nil, ['image'] = 'weapon_fireextinguisher.png', ['unique'] = true, ['useable'] = false, ['description'] = 'A portable device that discharges a jet of water, foam, gas, or other material to extinguish a fire'}, + ['weapon_hazardcan'] = {['name'] = 'weapon_hazardcan', ['label'] = 'Hazardous Jerry Can', ['weight'] = 1000, ['type'] = 'weapon', ['ammotype'] = 'AMMO_PETROLCAN', ['image'] = 'weapon_hazardcan.png', ['unique'] = true, ['useable'] = true, ['description'] = 'Weapon Hazardcan'}, + + -- PISTOL ATTACHMENTS + ['pistol_defaultclip'] = {['name'] = 'pistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Default Clip'}, + ['pistol_extendedclip'] = {['name'] = 'pistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Extended Clip'}, + ['pistol_flashlight'] = {['name'] = 'pistol_flashlight', ['label'] = 'Pistol Flashlight', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_flashlight.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Flashlight Attachment'}, + ['pistol_suppressor'] = {['name'] = 'pistol_suppressor', ['label'] = 'Pistol Suppressor', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Suppressor Attachment'}, + ['pistol_luxuryfinish'] = {['name'] = 'pistol_luxuryfinish', ['label'] = 'Pistol Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Luxury Finish'}, + ['pistol_scope'] = {['name'] = 'pistol_scope', ['label'] = 'Pistol Scope', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pistol Scope'}, + ['combatpistol_defaultclip'] = {['name'] = 'combatpistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat Pistol Default Clip'}, + ['combatpistol_extendedclip'] = {['name'] = 'combatpistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat Pistol Extended Clip'}, + ['combatpistol_luxuryfinish'] = {['name'] = 'combatpistol_luxuryfinish', ['label'] = 'Pistol Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat Pistol Luxury Finish'}, + ['appistol_defaultclip'] = {['name'] = 'appistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'APPistol Default Clip'}, + ['appistol_extendedclip'] = {['name'] = 'appistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'APPistol Extended Clip'}, + ['appistol_luxuryfinish'] = {['name'] = 'appistol_luxuryfinish', ['label'] = 'Pistol Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'APPistol Luxury Finish'}, + ['pistol50_defaultclip'] = {['name'] = 'pistol50_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '.50 Pistol Default Clip'}, + ['pistol50_extendedclip'] = {['name'] = 'pistol50_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '.50 Pistol Extended Clip'}, + ['pistol50_luxuryfinish'] = {['name'] = 'pistol50_luxuryfinish', ['label'] = 'Pistol Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '.50 Pistol Luxury Finish'}, + ['revolver_defaultclip'] = {['name'] = 'revolver_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Revovler Default Clip'}, + ['revolver_vipvariant'] = {['name'] = 'revolver_vipvariant', ['label'] = 'Pistol Variant', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Revovler Variant'}, + ['revolver_bodyguardvariant'] = {['name'] = 'revolver_bodyguardvariant', ['label'] = 'Pistol Variant', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Revovler Variant'}, + ['snspistol_defaultclip'] = {['name'] = 'snspistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SNS Pistol Default Clip'}, + ['snspistol_extendedclip'] = {['name'] = 'snspistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SNS Pistol Extended Clip'}, + ['snspistol_grip'] = {['name'] = 'snspistol_grip', ['label'] = 'Pistol Grip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SNS Pistol Grip Attachment'}, + ['heavypistol_defaultclip'] = {['name'] = 'heavypistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Pistol Default Clip'}, + ['heavypistol_extendedclip'] = {['name'] = 'heavypistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Pistol Extended Clip'}, + ['heavypistol_grip'] = {['name'] = 'heavypistol_grip', ['label'] = 'Pistol Grip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Pistol Grip Attachment'}, + ['vintagepistol_defaultclip'] = {['name'] = 'vintagepistol_defaultclip', ['label'] = 'Pistol Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Vintage Pistol Default Clip'}, + ['vintagepistol_extendedclip'] = {['name'] = 'vintagepistol_extendedclip', ['label'] = 'Pistol EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Vintage Pistol Default Clip'}, + + -- SMG ATTACHMENTS + ['microsmg_defaultclip'] = {['name'] = 'microsmg_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Micro SMG Default Clip'}, + ['microsmg_extendedclip'] = {['name'] = 'microsmg_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Micro SMG Extended Clip'}, + ['microsmg_scope'] = {['name'] = 'microsmg_scope', ['label'] = 'SMG Scope', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Micro SMG Scope Attachment'}, + ['microsmg_luxuryfinish'] = {['name'] = 'microsmg_luxuryfinish', ['label'] = 'SMG Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Micro SMG Luxury Finish'}, + ['smg_defaultclip'] = {['name'] = 'smg_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Default Clip'}, + ['smg_extendedclip'] = {['name'] = 'smg_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Extended Clip'}, + ['smg_suppressor'] = {['name'] = 'smg_suppressor', ['label'] = 'SMG Suppressor', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Suppressor'}, + ['smg_drum'] = {['name'] = 'smg_drum', ['label'] = 'SMG Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Drum'}, + ['smg_scope'] = {['name'] = 'smg_scope', ['label'] = 'SMG Scope', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Scope Attachment'}, + ['smg_luxuryfinish'] = {['name'] = 'smg_luxuryfinish', ['label'] = 'SMG Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'SMG Luxury Finish'}, + ['assaultsmg_defaultclip'] = {['name'] = 'assaultsmg_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault SMG Default Clip'}, + ['assaultsmg_extendedclip'] = {['name'] = 'assaultsmg_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault SMG Extended Clip'}, + ['assaultsmg_luxuryfinish'] = {['name'] = 'assaultsmg_luxuryfinish', ['label'] = 'SMG Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault SMG Luxury Finish'}, + ['minismg_defaultclip'] = {['name'] = 'minismg_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mini SMG Default Clip'}, + ['minismg_extendedclip'] = {['name'] = 'minismg_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mini SMG Extended Clip'}, + ['machinepistol_defaultclip'] = {['name'] = 'machinepistol_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Machine Pistol Default Clip'}, + ['machinepistol_extendedclip'] = {['name'] = 'machinepistol_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Machine Pistol Extended Clip'}, + ['machinepistol_drum'] = {['name'] = 'machinepistol_drum', ['label'] = 'SMG Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Machine Pistol Drum'}, + ['combatpdw_defaultclip'] = {['name'] = 'combatpdw_defaultclip', ['label'] = 'SMG Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat PDW Default Clip'}, + ['combatpdw_extendedclip'] = {['name'] = 'combatpdw_extendedclip', ['label'] = 'SMG EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat PDW Extended Clip'}, + ['combatpdw_drum'] = {['name'] = 'combatpdw_drum', ['label'] = 'SMG Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat PDW Drum'}, + ['combatpdw_grip'] = {['name'] = 'combatpdw_grip', ['label'] = 'SMG Grip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat PDW Grip Attachment'}, + ['combatpdw_scope'] = {['name'] = 'combatpdw_scope', ['label'] = 'SMG Scope', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Combat PDW Scope Attachment'}, + + -- SHOTGUN ATTACHMENTS + ['shotgun_suppressor'] = {['name'] = 'shotgun_suppressor', ['label'] = 'Shotgun Suppressor', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Shotgun Suppressor Attachment'}, + ['pumpshotgun_luxuryfinish'] = {['name'] = 'pumpshotgun_luxuryfinish', ['label'] = 'Shotgun Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pump Shotgun Luxury Finish'}, + ['sawnoffshotgun_luxuryfinish'] = {['name'] = 'sawnoffshotgun_luxuryfinish', ['label'] = 'Shotgun Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sawn Off Shotgun Luxury Finish'}, + ['assaultshotgun_defaultclip'] = {['name'] = 'assaultshotgun_defaultclip', ['label'] = 'Shotgun Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Shotgun Default Clip'}, + ['assaultshotgun_extendedclip'] = {['name'] = 'assaultshotgun_extendedclip', ['label'] = 'Shotgun EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Shotgun Extended Clip'}, + ['heavyshotgun_defaultclip'] = {['name'] = 'heavyshotgun_defaultclip', ['label'] = 'Shotgun Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Shotgun Default Clip'}, + ['heavyshotgun_extendedclip'] = {['name'] = 'heavyshotgun_extendedclip', ['label'] = 'Shotgun EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Shotgun Extended Clip'}, + ['heavyshotgun_drum'] = {['name'] = 'heavyshotgun_drum', ['label'] = 'Shotgun Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Shotgun Drum'}, + + -- RIFLE ATTACHMENTS + ['assaultrifle_defaultclip'] = {['name'] = 'assaultrifle_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Rifle Default Clip'}, + ['assaultrifle_extendedclip'] = {['name'] = 'assaultrifle_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Rifle Extended Clip'}, + ['assaultrifle_drum'] = {['name'] = 'assaultrifle_drum', ['label'] = 'Rifle Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Rifle Drum'}, + ['rifle_flashlight'] = {['name'] = 'rifle_flashlight', ['label'] = 'Rifle Flashlight', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_flashlight.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Rifle Flashlight Attachment'}, + ['rifle_grip'] = {['name'] = 'rifle_grip', ['label'] = 'Rifle Grip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Rifle Grip Attachment'}, + ['rifle_suppressor'] = {['name'] = 'rifle_suppressor', ['label'] = 'Rifle Suppressor', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Rifle Suppressor Attachment'}, + ['assaultrifle_luxuryfinish'] = {['name'] = 'assaultrifle_luxuryfinish', ['label'] = 'Rifle Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Assault Rifle Luxury Finish'}, + ['carbinerifle_defaultclip'] = {['name'] = 'carbinerifle_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Carbine Rifle Default Clip'}, + ['carbinerifle_extendedclip'] = {['name'] = 'carbinerifle_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Carbine Rifle Extended Clip'}, + ['carbinerifle_drum'] = {['name'] = 'carbinerifle_drum', ['label'] = 'Rifle Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Carbine Rifle Drum'}, + ['carbinerifle_scope'] = {['name'] = 'carbinerifle_scope', ['label'] = 'Rifle Scope', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Carbine Rifle Scope'}, + ['carbinerifle_luxuryfinish'] = {['name'] = 'carbinerifle_luxuryfinish', ['label'] = 'Rifle Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Carbine Rifle Luxury Finish'}, + ['advancedrifle_defaultclip'] = {['name'] = 'advancedrifle_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Advanced Rifle Default Clip'}, + ['advancedrifle_extendedclip'] = {['name'] = 'advancedrifle_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Advanced Rifle Extended Clip'}, + ['advancedrifle_luxuryfinish'] = {['name'] = 'advancedrifle_luxuryfinish', ['label'] = 'Rifle Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Advanced Rifle Luxury Finish'}, + ['specialcarbine_defaultclip'] = {['name'] = 'specialcarbine_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Special Carbine Default Clip'}, + ['specialcarbine_extendedclip'] = {['name'] = 'specialcarbine_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Special Carbine Extended Clip'}, + ['specialcarbine_drum'] = {['name'] = 'specialcarbine_drum', ['label'] = 'Rifle Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Special Carbine Drum'}, + ['specialcarbine_luxuryfinish'] = {['name'] = 'specialcarbine_luxuryfinish', ['label'] = 'Rifle Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Special Carbine Luxury Finish'}, + ['bullpuprifle_defaultclip'] = {['name'] = 'bullpuprifle_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Bullpup Rifle Default Clip'}, + ['bullpuprifle_extendedclip'] = {['name'] = 'bullpuprifle_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Bullpup Rifle Extended Clip'}, + ['bullpuprifle_luxuryfinish'] = {['name'] = 'bullpuprifle_luxuryfinish', ['label'] = 'Rifle Finish', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Bullpup Rifle Luxury Finish'}, + ['compactrifle_defaultclip'] = {['name'] = 'compactrifle_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Compact Rifle Default Clip'}, + ['compactrifle_extendedclip'] = {['name'] = 'compactrifle_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Compact Rifle Extended Clip'}, + ['compactrifle_drum'] = {['name'] = 'compactrifle_drum', ['label'] = 'Rifle Drum', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rifle_drummag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Compact Rifle Drum'}, + ['gusenberg_defaultclip'] = {['name'] = 'gusenberg_defaultclip', ['label'] = 'Rifle Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Gusenberg Default Clip'}, + ['gusenberg_extendedclip'] = {['name'] = 'gusenberg_extendedclip', ['label'] = 'Rifle EXT Clip', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Gusenberg Extended Clip'}, + + -- SNIPER ATTACHMENTS + ['sniperrifle_defaultclip'] = {['name'] = 'sniperrifle_defaultclip', ['label'] = 'Sniper Suppressor', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sniper Rifle Default Clip'}, + ['sniper_scope'] = {['name'] = 'sniper_scope', ['label'] = 'Sniper Scope', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sniper Rifle Scope Attachment'}, + ['snipermax_scope'] = {['name'] = 'snipermax_scope', ['label'] = 'Sniper Max Scope', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sniper Rifle Max Scope Attachment'}, + ['sniper_grip'] = {['name'] = 'sniper_grip', ['label'] = 'Sniper Grip', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sniper Rifle Grip Attachment'}, + ['heavysniper_defaultclip'] = {['name'] = 'heavysniper_defaultclip', ['label'] = 'Sniper Clip', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy Sniper Default Clip'}, + ['marksmanrifle_defaultclip'] = {['name'] = 'marksmanrifle_defaultclip', ['label'] = 'Sniper Clip', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Marksman Rifle Default Clip'}, + ['marksmanrifle_extendedclip'] = {['name'] = 'marksmanrifle_extendedclip', ['label'] = 'Sniper EXT Clip', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_extendedclip.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Marksman Rifle Extended Clip'}, + ['marksmanrifle_scope'] = {['name'] = 'marksmanrifle_scope', ['label'] = 'Sniper Scope', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'smg_scope.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Marksman Rifle Scope Attachment'}, + ['marksmanrifle_luxuryfinish'] = {['name'] = 'marksmanrifle_luxuryfinish', ['label'] = 'Sniper Finish', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pistol_suppressor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Marksman Rifle Luxury Finish'}, + + -- Weapon Tints + ['weapontint_black'] = {['name'] = 'weapontint_black', ['label'] = 'Default Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_black.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Default/Black Weapon Tint'}, + ['weapontint_green'] = {['name'] = 'weapontint_green', ['label'] = 'Green Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_green.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Green Weapon Tint'}, + ['weapontint_gold'] = {['name'] = 'weapontint_gold', ['label'] = 'Gold Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_gold.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Gold Weapon Tint'}, + ['weapontint_pink'] = {['name'] = 'weapontint_pink', ['label'] = 'Pink Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_pink.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pink Weapon Tint'}, + ['weapontint_army'] = {['name'] = 'weapontint_army', ['label'] = 'Army Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_army.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Army Weapon Tint'}, + ['weapontint_lspd'] = {['name'] = 'weapontint_lspd', ['label'] = 'LSPD Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_lspd.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'LSPD Weapon Tint'}, + ['weapontint_orange'] = {['name'] = 'weapontint_orange', ['label'] = 'Orange Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_orange.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Orange Weapon Tint'}, + ['weapontint_plat'] = {['name'] = 'weapontint_plat', ['label'] = 'Platinum Tint', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapontint_plat.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Platinum Weapon Tint'}, + + -- ITEMS + -- Ammo ITEMS + ["taserammo"] = {["name"] = "taserammo", ["label"] = "Taser Cartridges", ["weight"] = 3000, ["type"] = "item", ["image"] = "taserammo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "No More Spamming. lul"}, + ['pistol_ammo'] = {['name'] = 'pistol_ammo', ['label'] = 'Pistol ammo', ['weight'] = 20, ['type'] = 'item', ['image'] = 'pistol_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Pistols'}, + ['rifle_ammo'] = {['name'] = 'rifle_ammo', ['label'] = 'Rifle ammo', ['weight'] = 10, ['type'] = 'item', ['image'] = 'rifle_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Rifles'}, + ['smg_ammo'] = {['name'] = 'smg_ammo', ['label'] = 'SMG ammo', ['weight'] = 50, ['type'] = 'item', ['image'] = 'smg_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Sub Machine Guns'}, + ['shotgun_ammo'] = {['name'] = 'shotgun_ammo', ['label'] = 'Shotgun ammo', ['weight'] = 50, ['type'] = 'item', ['image'] = 'shotgun_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Shotguns'}, + ['mg_ammo'] = {['name'] = 'mg_ammo', ['label'] = 'MG ammo', ['weight'] = 10, ['type'] = 'item', ['image'] = 'mg_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Machine Guns'}, + ['snp_ammo'] = {['name'] = 'snp_ammo', ['label'] = 'Sniper ammo', ['weight'] = 10, ['type'] = 'item', ['image'] = 'rifle_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Sniper Rifles'}, + ['emp_ammo'] = {['name'] = 'emp_ammo', ['label'] = 'EMP Ammo', ['weight'] = 20, ['type'] = 'item', ['image'] = 'emp_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for EMP Launcher'}, + + -- Card ITEMS + ['id_card'] = {['name'] = 'id_card', ['label'] = 'ID Card', ['weight'] = 0, ['type'] = 'item', ['image'] = 'id_card.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A card containing all your information to identify yourself', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['driver_license'] = {['name'] = 'driver_license', ['label'] = 'Drivers License', ['weight'] = 0, ['type'] = 'item', ['image'] = 'driver_license.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Permit to show you can drive a vehicle', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['lawyerpass'] = {['name'] = 'lawyerpass', ['label'] = 'Lawyer Pass', ['weight'] = 0, ['type'] = 'item', ['image'] = 'lawyerpass.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Pass exclusive to lawyers to show they can represent a suspect'}, + ['weaponlicense'] = {['name'] = 'weaponlicense', ['label'] = 'Weapon License', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weapon_license.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Weapon License'}, + ['visa'] = {['name'] = 'visa', ['label'] = 'Visa Card', ['weight'] = 0, ['type'] = 'item', ['image'] = 'visacard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Visa can be used via ATM'}, + ['mastercard'] = {['name'] = 'mastercard', ['label'] = 'Master Card', ['weight'] = 0, ['type'] = 'item', ['image'] = 'mastercard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'MasterCard can be used via ATM'}, + ['security_card_01'] = {['name'] = 'security_card_01', ['label'] = 'Security Card A', ['weight'] = 0, ['type'] = 'item', ['image'] = 'security_card_01.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A security card... I wonder what it goes to'}, + ['security_card_02'] = {['name'] = 'security_card_02', ['label'] = 'Security Card B', ['weight'] = 0, ['type'] = 'item', ['image'] = 'security_card_02.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A security card... I wonder what it goes to'}, + + -- Eat ITEMS + ['tosti'] = {['name'] = 'tosti', ['label'] = 'Grilled Cheese Sandwich', ['weight'] = 20, ['type'] = 'item', ['image'] = 'tosti.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['twerks_candy'] = {['name'] = 'twerks_candy', ['label'] = 'Twerks', ['weight'] = 10, ['type'] = 'item', ['image'] = 'twerks_candy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some delicious candy :O', ["decay"] = 0.0, ["delete"] = false}, + ['snikkel_candy'] = {['name'] = 'snikkel_candy', ['label'] = 'Snikkel', ['weight'] = 10, ['type'] = 'item', ['image'] = 'snikkel_candy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some delicious candy :O', ["decay"] = 0.0, ["delete"] = false}, + ['sandwich'] = {['name'] = 'sandwich', ['label'] = 'Sandwich', ['weight'] = 20, ['type'] = 'item', ['image'] = 'sandwich.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice bread for your stomach', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Drink ITEMS + ['water_bottle'] = {['name'] = 'water_bottle', ['label'] = 'Bottle of Water', ['weight'] = 50, ['type'] = 'item', ['image'] = 'water_bottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ["created"] = nil}, + ['coffee'] = {['name'] = 'coffee', ['label'] = 'Coffee', ['weight'] = 20, ['type'] = 'item', ['image'] = 'coffee.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pump 4 Caffeine', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['kurkakola'] = {['name'] = 'kurkakola', ['label'] = 'Cola', ['weight'] = 50, ['type'] = 'item', ['image'] = 'cola.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Alcohol + ['beer'] = {['name'] = 'beer', ['label'] = 'Beer', ['weight'] = 50, ['type'] = 'item', ['image'] = 'beer.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nothing like a good cold beer!', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['whiskey'] = {['name'] = 'whiskey', ['label'] = 'Whiskey', ['weight'] = 50, ['type'] = 'item', ['image'] = 'whiskey.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['vodka'] = {['name'] = 'vodka', ['label'] = 'Vodka', ['weight'] = 50, ['type'] = 'item', ['image'] = 'vodka.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['grape'] = {['name'] = 'grape', ['label'] = 'Grape', ['weight'] = 10, ['type'] = 'item', ['image'] = 'grape.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Mmmmh yummie, grapes', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['wine'] = {['name'] = 'wine', ['label'] = 'Wine', ['weight'] = 30, ['type'] = 'item', ['image'] = 'wine.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Some good wine to drink on a fine evening', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['grapejuice'] = {['name'] = 'grapejuice', ['label'] = 'Grape Juice', ['weight'] = 20, ['type'] = 'item', ['image'] = 'grapejuice.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Grape juice is said to be healthy', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Drugs + ['joint'] = {['name'] = 'joint', ['label'] = 'Joint', ['weight'] = 0, ['type'] = 'item', ['image'] = 'joint.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sidney would be very proud at you', ["created"] = nil}, + ['cokebaggy'] = {['name'] = 'cokebaggy', ['label'] = 'Bag of Coke', ['weight'] = 0, ['type'] = 'item', ['image'] = 'cocaine_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy real quick', ["created"] = nil}, + ['crack_baggy'] = {['name'] = 'crack_baggy', ['label'] = 'Bag of Crack', ['weight'] = 0, ['type'] = 'item', ['image'] = 'crack_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy faster'}, + ['xtcbaggy'] = {['name'] = 'xtcbaggy', ['label'] = 'Bag of XTC', ['weight'] = 0, ['type'] = 'item', ['image'] = 'xtc_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pop those pills baby'}, + ['weed_brick'] = {['name'] = 'weed_brick', ['label'] = 'Weed Brick', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_brick.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '1KG Weed Brick to sell to large customers.'}, + ['coke_brick'] = {['name'] = 'coke_brick', ['label'] = 'Coke Brick', ['weight'] = 10, ['type'] = 'item', ['image'] = 'coke_brick.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy package of cocaine, mostly used for deals and takes a lot of space'}, + ['coke_small_brick'] = {['name'] = 'coke_small_brick', ['label'] = 'Coke Package', ['weight'] = 35, ['type'] = 'item', ['image'] = 'coke_small_brick.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Small package of cocaine, mostly used for deals and takes a lot of space'}, + ['oxy'] = {['name'] = 'oxy', ['label'] = 'Prescription Oxy', ['weight'] = 0, ['type'] = 'item', ['image'] = 'oxy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The Label Has Been Ripped Off', ["created"] = nil}, + ['meth'] = {['name'] = 'meth', ['label'] = 'Meth', ['weight'] = 10, ['type'] = 'item', ['image'] = 'meth_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A baggie of Meth', ["created"] = nil}, + ['rolling_paper'] = {['name'] = 'rolling_paper', ['label'] = 'Rolling Paper', ['weight'] = 0, ['type'] = 'item', ['image'] = 'rolling_paper.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = {accept = {'weed_white-widow', 'weed_skunk', 'weed_purple-haze', 'weed_og-kush', 'weed_amnesia', 'weed_ak47'}, reward = 'joint', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Rolling joint', ['timeOut'] = 5000, }}, ['description'] = 'Paper made specifically for encasing and smoking tobacco or cannabis.'}, + + -- Seed And Weed + ['weed_white-widow'] = {['name'] = 'weed_white-widow', ['label'] = 'White Widow 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g White Widow'}, + ['weed_skunk'] = {['name'] = 'weed_skunk', ['label'] = 'Skunk 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Skunk'}, + ['weed_purple-haze'] = {['name'] = 'weed_purple-haze', ['label'] = 'Purple Haze 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Purple Haze'}, + ['weed_og-kush'] = {['name'] = 'weed_og-kush', ['label'] = 'OGKush 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g OG Kush'}, + ['weed_amnesia'] = {['name'] = 'weed_amnesia', ['label'] = 'Amnesia 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Amnesia'}, + ['weed_ak47'] = {['name'] = 'weed_ak47', ['label'] = 'AK47 2g', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g AK47'}, + ['weed_white-widow_seed'] = {['name'] = 'weed_white-widow_seed', ['label'] = 'White Widow Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed seed of White Widow'}, + ['weed_skunk_seed'] = {['name'] = 'weed_skunk_seed', ['label'] = 'Skunk Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Skunk'}, + ['weed_purple-haze_seed'] = {['name'] = 'weed_purple-haze_seed', ['label'] = 'Purple Haze Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Purple Haze'}, + ['weed_og-kush_seed'] = {['name'] = 'weed_og-kush_seed', ['label'] = 'OGKush Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of OG Kush'}, + ['weed_amnesia_seed'] = {['name'] = 'weed_amnesia_seed', ['label'] = 'Amnesia Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Amnesia'}, + ['weed_ak47_seed'] = {['name'] = 'weed_ak47_seed', ['label'] = 'AK47 Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of AK47'}, + ['empty_weed_bag'] = {['name'] = 'empty_weed_bag', ['label'] = 'Empty Weed Bag', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_baggy_empty.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A small empty bag'}, + ['weed_nutrition'] = {['name'] = 'weed_nutrition', ['label'] = 'Plant Fertilizer', ['weight'] = 20, ['type'] = 'item', ['image'] = 'weed_nutrition.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Plant nutrition'}, + + -- Material + ['plastic'] = {['name'] = 'plastic', ['label'] = 'Plastic', ['weight'] = 10, ['type'] = 'item', ['image'] = 'plastic.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'RECYCLE! - Greta Thunberg 2019', ["created"] = nil}, + ['metalscrap'] = {['name'] = 'metalscrap', ['label'] = 'Metal Scrap', ['weight'] = 10, ['type'] = 'item', ['image'] = 'metalscrap.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'You can probably make something nice out of this', ["created"] = nil}, + ['copper'] = {['name'] = 'copper', ['label'] = 'Copper', ['weight'] = 10, ['type'] = 'item', ['image'] = 'copper.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ["created"] = nil}, + ['aluminum'] = {['name'] = 'aluminum', ['label'] = 'Aluminium', ['weight'] = 10, ['type'] = 'item', ['image'] = 'aluminum.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ["created"] = nil}, + ['aluminumoxide'] = {['name'] = 'aluminumoxide', ['label'] = 'Aluminium Powder', ['weight'] = 10, ['type'] = 'item', ['image'] = 'aluminumoxide.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Some powder to mix with', ["created"] = nil}, + ['iron'] = {['name'] = 'iron', ['label'] = 'Iron', ['weight'] = 10, ['type'] = 'item', ['image'] = 'iron.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Handy piece of metal that you can probably use for something', ["created"] = nil}, + ['ironoxide'] = {['name'] = 'ironoxide', ['label'] = 'Iron Powder', ['weight'] = 10, ['type'] = 'item', ['image'] = 'ironoxide.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = {accept = {'aluminumoxide'}, reward = 'thermite', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Mixing powder..', ['timeOut'] = 10000}}, ['description'] = 'Some powder to mix with.', ["created"] = nil}, + ['steel'] = {['name'] = 'steel', ['label'] = 'Steel', ['weight'] = 10, ['type'] = 'item', ['image'] = 'steel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ["created"] = nil}, + ['rubber'] = {['name'] = 'rubber', ['label'] = 'Rubber', ['weight'] = 10, ['type'] = 'item', ['image'] = 'rubber.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Rubber, I believe you can make your own rubber ducky with it :D', ["created"] = nil}, + ['glass'] = {['name'] = 'glass', ['label'] = 'Glass', ['weight'] = 10, ['type'] = 'item', ['image'] = 'glass.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'It is very fragile, watch out', ["created"] = nil}, + + -- Tools + ['lockpick'] = {['name'] = 'lockpick', ['label'] = 'Lockpick', ['weight'] = 30, ['type'] = 'item', ['image'] = 'lockpick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = {accept = {'screwdriverset'}, reward = 'advancedlockpick', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Crafting lockpick', ['timeOut'] = 7500, }}, ['description'] = 'Very useful if you lose your keys a lot.. or if you want to use it for something else...', ["created"] = nil}, + ['advancedlockpick'] = {['name'] = 'advancedlockpick', ['label'] = 'Advanced Lockpick', ['weight'] = 50, ['type'] = 'item', ['image'] = 'advancedlockpick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'If you lose your keys a lot this is very useful... Also useful to open your beers', ["created"] = nil}, + ['electronickit'] = {['name'] = 'electronickit', ['label'] = 'Electronic Kit', ['weight'] = 10, ['type'] = 'item', ['image'] = 'electronickit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = {accept = {'gatecrack'}, reward = 'trojan_usb', anim = nil}, ['description'] = 'If you\'ve always wanted to build a robot you can maybe start here. Maybe you\'ll be the new Elon Musk?', ["created"] = nil}, + ['gatecrack'] = {['name'] = 'gatecrack', ['label'] = 'Gatecrack', ['weight'] = 0, ['type'] = 'item', ['image'] = 'usb_device.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Handy software to tear down some fences', ["created"] = nil}, + ['thermite'] = {['name'] = 'thermite', ['label'] = 'Thermite', ['weight'] = 10, ['type'] = 'item', ['image'] = 'thermite.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sometimes you\'d wish for everything to burn', ["created"] = nil}, + ['trojan_usb'] = {['name'] = 'trojan_usb', ['label'] = 'Trojan USB', ['weight'] = 0, ['type'] = 'item', ['image'] = 'usb_device.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Handy software to shut down some systems', ["created"] = nil}, + ['screwdriverset'] = {['name'] = 'screwdriverset', ['label'] = 'Toolkit', ['weight'] = 10, ['type'] = 'item', ['image'] = 'screwdriverset.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Very useful to screw... screws...', ["created"] = nil}, + ['drill'] = {['name'] = 'drill', ['label'] = 'Drill', ['weight'] = 20, ['type'] = 'item', ['image'] = 'drill.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'The real deal...', ["created"] = nil}, + ['shears'] = {['name'] = 'shears', ['label'] = 'Shears', ['weight'] = 20, ['type'] = 'item', ['image'] = 'drug_shears.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Used to maintain hedges!', ["created"] = nil}, + + -- Vehicle Tools + ['nitrous'] = {['name'] = 'nitrous', ['label'] = 'Nitrous', ['weight'] = 10, ['type'] = 'item', ['image'] = 'nitrous.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Speed up, gas pedal! :D', ["created"] = nil}, + ['repairkit'] = {['name'] = 'repairkit', ['label'] = 'Repairkit', ['weight'] = 20, ['type'] = 'item', ['image'] = 'repairkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice toolbox with stuff to repair your vehicle', ["created"] = nil}, + ['advancedrepairkit'] = {['name'] = 'advancedrepairkit', ['label'] = 'Advanced Repairkit', ['weight'] = 40, ['type'] = 'item', ['image'] = 'advancedkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice toolbox with stuff to repair your vehicle', ["created"] = nil}, + ['cleaningkit'] = {['name'] = 'cleaningkit', ['label'] = 'Cleaning Kit', ['weight'] = 25, ['type'] = 'item', ['image'] = 'cleaningkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A microfiber cloth with some soap will let your car sparkle again!', ["created"] = nil}, + ['tunerlaptop'] = {['name'] = 'tunerlaptop', ['label'] = 'Tunerchip', ['weight'] = 20, ['type'] = 'item', ['image'] = 'tunerchip.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With this tunerchip you can get your car on steroids... If you know what you\'re doing', ["created"] = nil}, + ['harness'] = {['name'] = 'harness', ['label'] = 'Race Harness', ['weight'] = 10, ['type'] = 'item', ['image'] = 'harness.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Racing Harness so no matter what you stay in the car', ["created"] = nil}, + ['jerry_can'] = {['name'] = 'jerry_can', ['label'] = 'Jerrycan 20L', ['weight'] = 20, ['type'] = 'item', ['image'] = 'jerry_can.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A can full of Fuel', ["created"] = nil}, + + -- Medication + ['firstaid'] = {['name'] = 'firstaid', ['label'] = 'First Aid', ['weight'] = 25, ['type'] = 'item', ['image'] = 'firstaid.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You can use this First Aid kit to get people back on their feet', ["created"] = nil}, + ['bandage'] = {['name'] = 'bandage', ['label'] = 'Bandage', ['weight'] = 0, ['type'] = 'item', ['image'] = 'bandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bandage works every time', ["created"] = nil}, + ['ifaks'] = {['name'] = 'ifaks', ['label'] = 'ifaks', ['weight'] = 20, ['type'] = 'item', ['image'] = 'ifaks.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'ifaks for healing and a complete stress remover.', ["created"] = nil}, + ['painkillers'] = {['name'] = 'painkillers', ['label'] = 'Painkillers', ['weight'] = 0, ['type'] = 'item', ['image'] = 'painkillers.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For pain you can\'t stand anymore, take this pill that\'d make you feel great again', ["created"] = nil}, + ['walkstick'] = {['name'] = 'walkstick', ['label'] = 'Walking Stick', ['weight'] = 10, ['type'] = 'item', ['image'] = 'walkstick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Walking stick for ya\'ll grannies out there.. HAHA', ["created"] = nil}, + + -- Communication + ['phone'] = {['name'] = 'phone', ['label'] = 'Phone', ['weight'] = 70, ['type'] = 'item', ['image'] = 'phone.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Neat phone ya got there', ["created"] = nil}, + ['radio'] = {['name'] = 'radio', ['label'] = 'Radio', ['weight'] = 20, ['type'] = 'item', ['image'] = 'radio.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You can communicate with this through a signal', ["created"] = nil}, + ['iphone'] = {['name'] = 'iphone', ['label'] = 'iPhone', ['weight'] = 10, ['type'] = 'item', ['image'] = 'iphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Very expensive phone', ["created"] = nil}, + ['samsungphone'] = {['name'] = 'samsungphone', ['label'] = 'Samsung S10', ['weight'] = 10, ['type'] = 'item', ['image'] = 'samsungphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Very expensive phone', ["created"] = nil}, + ['laptop'] = {['name'] = 'laptop', ['label'] = 'Laptop', ['weight'] = 40, ['type'] = 'item', ['image'] = 'laptop.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Expensive laptop', ["created"] = nil}, + ['tablet'] = {['name'] = 'tablet', ['label'] = 'Tablet', ['weight'] = 20, ['type'] = 'item', ['image'] = 'tablet.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Expensive tablet', ["created"] = nil}, + ['fitbit'] = {['name'] = 'fitbit', ['label'] = 'Fitbit', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fitbit.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I like fitbit', ["created"] = nil}, + ['radioscanner'] = {['name'] = 'radioscanner', ['label'] = 'Radio Scanner', ['weight'] = 10, ['type'] = 'item', ['image'] = 'radioscanner.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With this you can get some police alerts. Not 100% effective however', ["created"] = nil}, + ['pinger'] = {['name'] = 'pinger', ['label'] = 'Pinger', ['weight'] = 10, ['type'] = 'item', ['image'] = 'pinger.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With a pinger and your phone you can send out your location', ["created"] = nil}, + ['cryptostick'] = {['name'] = 'cryptostick', ['label'] = 'Crypto Stick', ['weight'] = 20, ['type'] = 'item', ['image'] = 'cryptostick.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Why would someone ever buy money that doesn\'t exist.. How many would it contain..?', ["created"] = nil}, + + -- Theft and Jewelry + ['rolex'] = {['name'] = 'rolex', ['label'] = 'Golden Watch', ['weight'] = 10, ['type'] = 'item', ['image'] = 'rolex.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A golden watch seems like the jackpot to me!', ["created"] = nil}, + ['diamond_ring'] = {['name'] = 'diamond_ring', ['label'] = 'Diamond Ring', ['weight'] = 10, ['type'] = 'item', ['image'] = 'diamond_ring.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A diamond ring seems like the jackpot to me!', ["created"] = nil}, + ['diamond'] = {['name'] = 'diamond', ['label'] = 'Diamond', ['weight'] = 10, ['type'] = 'item', ['image'] = 'diamond.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A diamond seems like the jackpot to me!', ["created"] = nil}, + ['goldchain'] = {['name'] = 'goldchain', ['label'] = 'Golden Chain', ['weight'] = 15, ['type'] = 'item', ['image'] = 'goldchain.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A golden chain seems like the jackpot to me!', ["created"] = nil}, + ['10kgoldchain'] = {['name'] = '10kgoldchain', ['label'] = '10k Gold Chain', ['weight'] = 20, ['type'] = 'item', ['image'] = '10kgoldchain.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '10 carat golden chain', ["created"] = nil}, + ['goldbar'] = {['name'] = 'goldbar', ['label'] = 'Gold Bar', ['weight'] = 70, ['type'] = 'item', ['image'] = 'goldbar.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Looks pretty expensive to me', ["created"] = nil}, + + -- Cops Tools + ['armor'] = {['name'] = 'armor', ['label'] = 'Armor', ['weight'] = 200, ['type'] = 'item', ['image'] = 'armor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some protection won\'t hurt... right?', ["created"] = nil}, + ['heavyarmor'] = {['name'] = 'heavyarmor', ['label'] = 'Heavy Armor', ['weight'] = 300, ['type'] = 'item', ['image'] = 'armor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some protection won\'t hurt... right?', ["created"] = nil}, + ['handcuffs'] = {['name'] = 'handcuffs', ['label'] = 'Handcuffs', ['weight'] = 50, ['type'] = 'item', ['image'] = 'handcuffs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Comes in handy when people misbehave. Maybe it can be used for something else?', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['police_stormram'] = {['name'] = 'police_stormram', ['label'] = 'Stormram', ['weight'] = 18, ['type'] = 'item', ['image'] = 'police_stormram.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice tool to break into doors', ["created"] = nil}, + ['empty_evidence_bag'] = {['name'] = 'empty_evidence_bag', ['label'] = 'Empty Evidence Bag', ['weight'] = 0, ['type'] = 'item', ['image'] = 'evidence.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Used a lot to keep DNA from blood, bullet shells and more', ["created"] = nil}, + ['filled_evidence_bag'] = {['name'] = 'filled_evidence_bag', ['label'] = 'Evidence Bag', ['weight'] = 20, ['type'] = 'item', ['image'] = 'evidence.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A filled evidence bag to see who committed the crime >:(', ["created"] = nil}, + + -- Firework Tools + ['firework1'] = {['name'] = 'firework1', ['label'] = '2Brothers', ['weight'] = 10, ['type'] = 'item', ['image'] = 'firework1.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ["created"] = nil}, + ['firework2'] = {['name'] = 'firework2', ['label'] = 'Poppelers', ['weight'] = 10, ['type'] = 'item', ['image'] = 'firework2.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ["created"] = nil}, + ['firework3'] = {['name'] = 'firework3', ['label'] = 'WipeOut', ['weight'] = 10, ['type'] = 'item', ['image'] = 'firework3.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ["created"] = nil}, + ['firework4'] = {['name'] = 'firework4', ['label'] = 'Weeping Willow', ['weight'] = 10, ['type'] = 'item', ['image'] = 'firework4.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ["created"] = nil}, + + + + -- Sea Tools + ['dendrogyra_coral'] = {['name'] = 'dendrogyra_coral', ['label'] = 'Dendrogyra', ['weight'] = 10, ['type'] = 'item', ['image'] = 'dendrogyra_coral.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its also known as pillar coral', ["created"] = nil}, + ['antipatharia_coral'] = {['name'] = 'antipatharia_coral', ['label'] = 'Antipatharia', ['weight'] = 10, ['type'] = 'item', ['image'] = 'antipatharia_coral.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its also known as black corals or thorn corals', ["created"] = nil}, + ['diving_gear'] = {['name'] = 'diving_gear', ['label'] = 'Diving Gear', ['weight'] = 300, ['type'] = 'item', ['image'] = 'diving_gear.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'An oxygen tank and a rebreather', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['diving_fill'] = {['name'] = 'diving_fill', ['label'] = 'Diving Tube', ['weight'] = 30, ['type'] = 'item', ['image'] = 'diving_tube.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['discription'] = 'An oxygen tube and a rebreather', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Other Tools + ['casinochips'] = {['name'] = 'casinochips', ['label'] = 'Casino Chips', ['weight'] = 0, ['type'] = 'item', ['image'] = 'casinochips.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Chips For Casino Gambling', ["created"] = nil}, + ['stickynote'] = {['name'] = 'stickynote', ['label'] = 'Sticky note', ['weight'] = 0, ['type'] = 'item', ['image'] = 'stickynote.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Sometimes handy to remember something :)', ["created"] = nil}, + ['moneybag'] = {['name'] = 'moneybag', ['label'] = 'Money Bag', ['weight'] = 0, ['type'] = 'item', ['image'] = 'moneybag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bag with cash', ["created"] = nil}, + ['parachute'] = {['name'] = 'parachute', ['label'] = 'Parachute', ['weight'] = 300, ['type'] = 'item', ['image'] = 'parachute.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The sky is the limit! Woohoo!', ["created"] = nil}, + ['binoculars'] = {['name'] = 'binoculars', ['label'] = 'Binoculars', ['weight'] = 60, ['type'] = 'item', ['image'] = 'binoculars.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sneaky Breaky...', ["created"] = nil}, + ['lighter'] = {['name'] = 'lighter', ['label'] = 'Lighter', ['weight'] = 0, ['type'] = 'item', ['image'] = 'lighter.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'On new years eve a nice fire to stand next to', ["created"] = nil}, + ['certificate'] = {['name'] = 'certificate', ['label'] = 'Certificate', ['weight'] = 0, ['type'] = 'item', ['image'] = 'certificate.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Certificate that proves you own certain stuff', ["created"] = nil}, + ['markedbills'] = {['name'] = 'markedbills', ['label'] = 'Marked Money', ['weight'] = 10, ['type'] = 'item', ['image'] = 'markedbills.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Money?', ["created"] = nil}, + -- ['labkey'] = {['name'] = 'labkey', ['label'] = 'Key', ['weight'] = 50, ['type'] = 'item', ['image'] = 'labkey.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Key for a lock...?', ["created"] = nil}, + ['printerdocument'] = {['name'] = 'printerdocument', ['label'] = 'Document', ['weight'] = 50, ['type'] = 'item', ['image'] = 'printerdocument.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document', ["created"] = nil}, + --- + ["bluechip"] = {["name"] = "bluechip", ["label"] = "Blue Key", ["weight"] = 0, ["type"] = "item", ["image"] = "bluechip.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Wants To Hack! You may need me.", ["created"] = nil}, + ["greenchip"] = {["name"] = "greenchip", ["label"] = "Green Key", ["weight"] = 0, ["type"] = "item", ["image"] = "greenchip.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Wants To Hack! You may need me.", ["created"] = nil}, + ["redchip"] = {["name"] = "redchip", ["label"] = "Red Key", ["weight"] = 0, ["type"] = "item", ["image"] = "redchip.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Wants To Hack! You may need me.", ["created"] = nil}, + + ---mistry box + ["mystery_smallbox"] = {["name"] = "mystery_smallbox", ["label"] = "Small Mystery Box", ["weight"] = 100, ["type"] = "item", ["image"] = "mystery_smallBox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "small mistry box", ["created"] = nil}, + ["mystery_mediumbox"] = {["name"] = "mystery_mediumbox", ["label"] = "Medium Mystery Box", ["weight"] = 100, ["type"] = "item", ["image"] = "mystery_mediumBox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "mid level mistry box", ["created"] = nil}, + ["mystery_bigbox"] = {["name"] = "mystery_bigbox", ["label"] = "Big Mystery Box", ["weight"] = 100, ["type"] = "item", ["image"] = "mystery_bigBox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "large mistry box maybe", ["created"] = nil}, + ["mystery_expensivebox"] = {["name"] = "mystery_expensivebox", ["label"] = "Super Mystery Box", ["weight"] = 100, ["type"] = "item", ["image"] = "mystery_expensiveBox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "mistry is always mistry", ["created"] = nil}, + + ----rental + ['renting_contract'] = {['name'] = 'renting_contract', ['label'] = 'Renting Contract', ['weight'] = 50, ['type'] = 'item', ['image'] = 'renting_contract.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'rental recipts', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --hcrp-farming 2.0 + ["farm_fertilizante"] = {["name"] = "farm_fertilizante", ["label"] = "Agricultural Fertilizer", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_fertilizante.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_tomate"] = {["name"] = "farm_tomate", ["label"] = "Tomato Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_tomate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_trigo"] = {["name"] = "farm_trigo", ["label"] = "Wheat Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_trigo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_batatas"] = {["name"] = "farm_batatas", ["label"] = "Potato Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_batatas.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_pepino"] = {["name"] = "farm_pepino", ["label"] = "Cucumber Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_pepino.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cebola"] = {["name"] = "farm_cebola", ["label"] = "Onion Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cebola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cove"] = {["name"] = "farm_cove", ["label"] = "Cabbage Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cove.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_alface"] = {["name"] = "farm_alface", ["label"] = "Lettuce Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_alface.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cenora"] = {["name"] = "farm_cenora", ["label"] = "Carrot Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cenora.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_beterraba"] = {["name"] = "farm_beterraba", ["label"] = "Beet Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_beterraba.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_nabo"] = {["name"] = "farm_nabo", ["label"] = "Turnip Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_nabo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cogumelos"] = {["name"] = "farm_cogumelos", ["label"] = "Mushrooms Seeds", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cogumelos.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_regador"] = {["name"] = "farm_regador", ["label"] = "Empty Watering Can", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_regador.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_regador_cheio"] = {["name"] = "farm_regador_cheio", ["label"] = "Full Watering Can", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_regador.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_pa"] = {["name"] = "farm_pa", ["label"] = "Shovel", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_pa.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_trigo_colhido"] = {["name"] = "farm_trigo_colhido", ["label"] = "Wheat", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_trigo_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_tomate_colhido"] = {["name"] = "farm_tomate_colhido", ["label"] = "Tomato", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_tomate_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_nabo_colhido"] = {["name"] = "farm_nabo_colhido", ["label"] = "Turnip", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_nabo_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_batatas_colhido"] = {["name"] = "farm_batatas_colhido", ["label"] = "Potato", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_batatas_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_pepino_colhido"] = {["name"] = "farm_pepino_colhido", ["label"] = "Cucumber", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_pepino_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cebola_colhido"] = {["name"] = "farm_cebola_colhido", ["label"] = "Onion", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cebola_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cove_colhido"] = {["name"] = "farm_cove_colhido", ["label"] = "Cabbage", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cove_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_alface_colhido"] = {["name"] = "farm_alface_colhido", ["label"] = "Lettuce", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_alface_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cenora_colhido"] = {["name"] = "farm_cenora_colhido", ["label"] = "Carrot", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cenora_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_cogumelos_colhido"] = {["name"] = "farm_cogumelos_colhido", ["label"] = "Mushrooms", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_cogumelos_colhido.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_leite"] = {["name"] = "farm_leite", ["label"] = "Fresh Milk", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_leite.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_maca"] = {["name"] = "farm_maca", ["label"] = "Apple", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_maca.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_pessego"] = {["name"] = "farm_pessego", ["label"] = "Peach", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_pessego.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_pera"] = {["name"] = "farm_pera", ["label"] = "Pear", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_pera.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_manga"] = {["name"] = "farm_manga", ["label"] = "Mango", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_manga.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_laranja"] = {["name"] = "farm_laranja", ["label"] = "Orange", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_laranja.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_limao"] = {["name"] = "farm_limao", ["label"] = "Limon", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_limao.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_tesoura"] = {["name"] = "farm_tesoura", ["label"] = "Farm Scisors", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_tesoura.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_tomate"] = {["name"] = "farm_sumo_tomate", ["label"] = "Tomato Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_tomate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_farinha"] = {["name"] = "farm_farinha", ["label"] = "Wheat Flour", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_farinha.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_laranja"] = {["name"] = "farm_sumo_laranja", ["label"] = "Orange Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_laranja.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_pessego"] = {["name"] = "farm_sumo_pessego", ["label"] = "Peach Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_pessego.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_maca"] = {["name"] = "farm_sumo_maca", ["label"] = "Apple Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_maca.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_manga"] = {["name"] = "farm_sumo_manga", ["label"] = "Mango Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_manga.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_pera"] = {["name"] = "farm_sumo_pera", ["label"] = "Pear Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_pera.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["farm_sumo_limao"] = {["name"] = "farm_sumo_limao", ["label"] = "Lemon Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "farm_sumo_limao.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["digiscanner"] = {["name"] = "digiscanner", ["label"] = "Digiscanner", ["weight"] = 200, ["type"] = "item", ["image"] = "digiscanner.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Used to scan for things..", ["created"] = nil}, + ["shovel"] = {["name"] = "shovel", ["label"] = "Shovel", ["weight"] = 300, ["type"] = "item", ["image"] = "shovel.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A handy shovel.", ["created"] = nil}, + + + -- -----additional drinks item + ["sprunk"] = {["name"] = "sprunk", ["label"] = "Sprunk", ["weight"] = 100, ["type"] = "item", ["image"] = "sprunk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sprunklight"] = {["name"] = "sprunklight", ["label"] = "Sprunk Light", ["weight"] = 100, ["type"] = "item", ["image"] = "sprunklight.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ecola"] = {["name"] = "ecola", ["label"] = "eCola", ["weight"] = 100, ["type"] = "item", ["image"] = "ecola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ecolalight"] = {["name"] = "ecolalight", ["label"] = "eCola Light", ["weight"] = 100, ["type"] = "item", ["image"] = "ecolalight.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['vehiclekey'] = {['name'] = 'vehiclekey', ['label'] = 'Vehicle key', ['weight'] = 100, ['type'] = 'item', ['image'] = 'vehiclekeys.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "", ["created"] = nil}, + + ['driving_test_permit'] = {['name'] = 'driving_test_permit', ['label'] = 'Driving Test Permit', ['weight'] = 0, ['type'] = 'item', ['image'] = 'dmv.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Permite for Driving Test', ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["toolbox"] = {["name"] = "toolbox", ["label"] = "Toolbox", ["weight"] = 0, ["type"] = "item", ["image"] = "toolbox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Needed for Performance part removal", ["created"] = nil}, + ["ducttape"] = {["name"] = "ducttape", ["label"] = "Duct Tape", ["weight"] = 0, ["type"] = "item", ["image"] = "bodyrepair.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Good for quick fixes", ["created"] = nil}, + ["mechboard"] = {["name"] = "mechboard", ["label"] = "Mechanic Sheet", ["weight"] = 0, ["type"] = "item", ["image"] = "mechboard.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil}, + + -- ITEMS + ['fishingrod1'] = {['name'] = 'fishingrod1', ['label'] = 'Fishing Rod (1Lv.)', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishingrod1.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Chips For Casino Gambling'}, + ['fishingrod2'] = {['name'] = 'fishingrod2', ['label'] = 'Fishing Rod (2Lv.)', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishingrod2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Sometimes handy to remember something :)'}, + ['fishingrod3'] = {['name'] = 'fishingrod3', ['label'] = 'Fishing Rod (3Lv.)', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishingrod3.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bag with cash'}, + ['fishingrod4'] = {['name'] = 'fishingrod4', ['label'] = 'Fishing Rod (4Lv.)', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishingrod4.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The sky is the limit! Woohoo!'}, + ['fishingrod5'] = {['name'] = 'fishingrod5', ['label'] = 'Fishing Rod (5Lv.)', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishingrod5.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sneaky Breaky...'}, + ['anchovy'] = {['name'] = 'anchovy', ['label'] = 'Anchovy', ['weight'] = 50, ['type'] = 'item', ['image'] = 'anchovy.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'On new years eve a nice fire to stand next to'}, + ['smallbluefish'] = {['name'] = 'smallbluefish', ['label'] = 'Small Blue Fish', ['weight'] = 50, ['type'] = 'item', ['image'] = 'smallbluefish.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Certificate that proves you own certain stuff'}, + ['bluefish'] = {['name'] = 'bluefish', ['label'] = 'Blue Fish', ['weight'] = 50, ['type'] = 'item', ['image'] = 'bluefish.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Money?'}, + ['bonitosfish'] = {['name'] = 'bonitosfish', ['label'] = 'Bonitos', ['weight'] = 50, ['type'] = 'item', ['image'] = 'bonitosfish.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Key for a lock...?'}, + ['garfish'] = {['name'] = 'garfish', ['label'] = 'Garfish', ['weight'] = 50, ['type'] = 'item', ['image'] = 'garfish.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document'}, + ['perch'] = {['name'] = 'perch', ['label'] = 'Perch', ['weight'] = 50, ['type'] = 'item', ['image'] = 'perch.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Chips For Casino Gambling'}, + ['carettacaretta'] = {['name'] = 'carettacaretta', ['label'] = 'Kaplumbağa', ['weight'] = 50, ['type'] = 'item', ['image'] = 'carettacaretta.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Sometimes handy to remember something :)'}, + ['pantfish'] = {['name'] = 'pantfish', ['label'] = 'Pant Fish', ['weight'] = 50, ['type'] = 'item', ['image'] = 'pantfish.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bag with cash'}, + ['sharkfish'] = {['name'] = 'sharkfish', ['label'] = 'Shark', ['weight'] = 50, ['type'] = 'item', ['image'] = 'sharkfish.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The sky is the limit! Woohoo!'}, + ['whitepearl'] = {['name'] = 'whitepearl', ['label'] = 'White Pearl', ['weight'] = 50, ['type'] = 'item', ['image'] = 'whitepearl.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sneaky Breaky...'}, + ['bluepearl'] = {['name'] = 'bluepearl', ['label'] = 'Blue Pearl', ['weight'] = 50, ['type'] = 'item', ['image'] = 'bluepearl.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'On new years eve a nice fire to stand next to'}, + ['redpearl'] = {['name'] = 'redpearl', ['label'] = 'Red Pearl', ['weight'] = 50, ['type'] = 'item', ['image'] = 'redpearl.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Certificate that proves you own certain stuff'}, + ['yellowpearl'] = {['name'] = 'yellowpearl', ['label'] = 'Yellow Pearl', ['weight'] = 50, ['type'] = 'item', ['image'] = 'yellowpearl.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Money?'}, + ['greenpearl'] = {['name'] = 'greenpearl', ['label'] = 'Green Pearl', ['weight'] = 50, ['type'] = 'item', ['image'] = 'greenpearl.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Key for a lock...?'}, + ['fish'] = {['name'] = 'fish', ['label'] = 'Tiny Fish', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fish.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document'}, + ['fishbait'] = {['name'] = 'fishbait', ['label'] = 'Fish Bait', ['weight'] = 50, ['type'] = 'item', ['image'] = 'fishbait.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document'}, + ['illegalfishbait'] = {['name'] = 'illegalfishbait', ['label'] = 'Illegal Fish Bait', ['weight'] = 50, ['type'] = 'item', ['image'] = 'illegalFishBait.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document'}, + + + + + + -- New v9 Items + ['rubikcube'] = {['name'] = 'rubikcube', ['label'] = 'Rubik Cube', ['weight'] = 700, ['type'] = 'item', ['image'] = 'rubikcube.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'rubikcube'}, + + ['towremote'] = {['name'] = 'towremote', ['label'] = 'Tow Remote', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'towremote.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ["created"] = nil, ['description'] = '[useable] | [G] when in tow truck to lower and raise bed, [E] to pick the hook up and put the hook down'}, + ["reponote"] = {["name"] = "reponote", ["label"] = "Repo Note", ["weight"] = 500, ["type"] = "item", ["image"] = "reponote.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["created"] = nil, ["description"] = "[useable] | [G] when in tow truck to lower and raise bed, [E] to pick the hook up and put the hook down"}, + + ['fitness_subscription'] = {['name'] = 'fitness_subscription', ['label'] = 'Gym membership', ['weight'] = 0, ['type'] = 'item', ['image'] = 'stickynote.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Gym Notebook'}, + ['wheeltoken'] = {['name'] = 'wheeltoken', ['label'] = 'Wheel Token', ['weight'] = 100, ['type'] = 'item', ['image'] = 'token.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Token for spinning the wheel in a casino'}, + ['matticket'] = {['name'] = 'matticket', ['label'] = 'Material Voucher', ['weight'] = 100, ['type'] = 'item', ['image'] = 'matticket.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = "Turn this in at sanitation to be rewarded with some scrapped material"}, + ["kuz_divinggear"] = {["name"] = "kuz_divinggear", ["label"] = "Diving gear", ["weight"] = 3000, ["type"] = "item", ["image"] = "kuz_divinggear.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Basic diving gear"}, + ["kuz_divinggeargood"] = {["name"] = "kuz_divinggeargood", ["label"] = "Scuba gear", ["weight"] = 6000, ["type"] = "item", ["image"] = "kuz_divinggeargood.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Advanced diving gear"}, + ["kuz_silvercoin"] = {["name"] = "kuz_silvercoin", ["label"] = "Silver coin", ["weight"] = 100, ["type"] = "item", ["image"] = "kuz_silvercoin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Silver coin"}, + ["kuz_goldcoin"] = {["name"] = "kuz_goldcoin", ["label"] = "Gold coin", ["weight"] = 150, ["type"] = "item", ["image"] = "kuz_goldcoin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Gold coin"}, + ["kuz_pearl"] = {["name"] = "kuz_pearl", ["label"] = "Pearl", ["weight"] = 250, ["type"] = "item", ["image"] = "kuz_pearl.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Pearl"}, + ["kuz_rarecoin"] = {["name"] = "kuz_rarecoin", ["label"] = "Rare coin", ["weight"] = 250, ["type"] = "item", ["image"] = "kuz_rarecoin.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare coin"}, + ["kuz_plasmacutter"] = {["name"] = "kuz_plasmacutter", ["label"] = "Underwater Plasma cutter", ["weight"] = 2500, ["type"] = "item", ["image"] = "kuz_plasmacutter.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Underwater Plasma Cutter"}, + ["kuz_merryweather"] = {["name"] = "kuz_merryweather", ["label"] = "Merryweather parts", ["weight"] = 5000, ["type"] = "item", ["image"] = "kuz_merryweather.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Merryweather parts"}, + ["kuz_jewelry"] = {["name"] = "kuz_jewelry", ["label"] = "Jewelry", ["weight"] = 1000, ["type"] = "item", ["image"] = "kuz_jewelry.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Jewelry"}, + ["kuz_watch"] = {["name"] = "kuz_watch", ["label"] = "Expensive watch", ["weight"] = 500, ["type"] = "item", ["image"] = "kuz_watch.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Expensive watch"}, + + -- m-Tequila + ["tq_berry_hydrating"] = {["name"] = "tq_berry_hydrating", ["label"] = "Berry Hydrating", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_berry_hydrating.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_cake"] = {["name"] = "tq_cake", ["label"] = "Cake", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_cake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_chocolate_cake"] = {["name"] = "tq_chocolate_cake", ["label"] = "Chocolate Cake", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_chocolate_cake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_cocktail"] = {["name"] = "tq_cocktail", ["label"] = "Cocktail", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_cocktail.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_coconut_drink"] = {["name"] = "tq_coconut_drink", ["label"] = "Coconut Drink", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_coconut_drink.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_coffee"] = {["name"] = "tq_coffee", ["label"] = "Coffee", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_coffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_coffee_heart"] = {["name"] = "tq_coffee_heart", ["label"] = "Coffee Heart", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_coffee_heart.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_green_dream"] = {["name"] = "tq_green_dream", ["label"] = "Green Dream", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_green_dream.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_island_breeze"] = {["name"] = "tq_island_breeze", ["label"] = "Island Breeze", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_island_breeze.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_island_fantasy"] = {["name"] = "tq_island_fantasy", ["label"] = "Island Fantasy", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_island_fantasy.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_just_peachy"] = {["name"] = "tq_just_peachy", ["label"] = "Just Peachy", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_just_peachy.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_kamikaze"] = {["name"] = "tq_kamikaze", ["label"] = "Kamikaze", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_kamikaze.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_redhot_daquiri"] = {["name"] = "tq_redhot_daquiri", ["label"] = "Redhot Daquiri", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_redhot_daquiri.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_watermelon_dream"] = {["name"] = "tq_watermelon_dream", ["label"] = "Watermelon Dream", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_watermelon_dream.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_tequila"] = {["name"] = "tq_tequila", ["label"] = "Tequila", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_tequila.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_daquiri"] = {["name"] = "tq_daquiri", ["label"] = "Daquiri", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_daquiri.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_water"] = {["name"] = "tq_water", ["label"] = "Water", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_water.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_caramel"] = {["name"] = "tq_caramel", ["label"] = "Caramel", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_caramel.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_chocolate"] = {["name"] = "tq_chocolate", ["label"] = "Chocolate", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_cheese"] = {["name"] = "tq_cheese", ["label"] = "Cheese", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_cheese.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_milk"] = {["name"] = "tq_milk", ["label"] = "Milk", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_milk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + -- Juices + ["tq_orange_juice"] = {["name"] = "tq_orange_juice", ["label"] = "Orange Juice", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_orange_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_kiwi_juice"] = {["name"] = "tq_kiwi_juice", ["label"] = "Kiwi Juice", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_kiwi_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_strawberry_juice"] = {["name"] = "tq_strawberry_juice", ["label"] = "Strawberry Juice", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_strawberry_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_banana_juice"] = {["name"] = "tq_banana_juice", ["label"] = "Banana Juice", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_banana_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_ban_straw_juice"] = {["name"] = "tq_ban_straw_juice", ["label"] = "Banana & Strawberry Juice", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_ban_straw_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + -- Fruits + ["tq_kiwi"] = {["name"] = "tq_kiwi", ["label"] = "Kiwi", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_kiwi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_orange"] = {["name"] = "tq_orange", ["label"] = "Orange", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_orange.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_strawberry"] = {["name"] = "tq_strawberry", ["label"] = "Strawberry", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_strawberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_sugar"] = {["name"] = "tq_sugar", ["label"] = "Sugar", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_sugar.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_watermelon"] = {["name"] = "tq_watermelon", ["label"] = "Watermelon", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_watermelon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_banana"] = {["name"] = "tq_banana", ["label"] = "Banana", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_banana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_coconut"] = {["name"] = "tq_coconut", ["label"] = "Coconut", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_coconut.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_banana_nut"] = {["name"] = "tq_banana_nut", ["label"] = "banana nut", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_banana_nut.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_chocolatecup"] = {["name"] = "tq_chocolatecup", ["label"] = "chocolatecup", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_chocolatecup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["tq_strawberrycup"] = {["name"] = "tq_strawberrycup", ["label"] = "Cocotq strawberrycupnut", ["weight"] = 50, ["type"] = "item", ["image"] = "tq_strawberrycup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + + + -- bahama mamas + ['beach-cocktail'] = {['name'] = 'beach-cocktail', ['label'] = 'Sax on the Beach', ['weight'] = 100, ['type'] = 'item', ['image'] = 'beach-cocktail.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I Think Sax is Spelt Wrong'}, + ['bloody-mary'] = {['name'] = 'bloody-mary', ['label'] = 'Bloody Mary', ['weight'] = 100, ['type'] = 'item', ['image'] = 'bloody-mary.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Whos Mary and Why is She Bloody?'}, + ['cherry-bomb'] = {['name'] = 'cherry-bomb', ['label'] = 'Cherry Bomb', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cherry-bomb.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I Love a Good Fruity Drink'}, + ['cherrydrop-shot'] = {['name'] = 'cherrydrop-shot', ['label'] = 'Cherry Drop', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cherrydrop-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fruity Shot'}, + ['firedrop-shot'] = {['name'] = 'firedrop-shot', ['label'] = 'Fire Drop', ['weight'] = 100, ['type'] = 'item', ['image'] = 'firedrop-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Spiiiicy!!!!'}, + ['lemonchello-shot'] = {['name'] = 'lemonchello-shot', ['label'] = 'Lemonchello', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lemonchello-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'This is a Unique Taste'}, + ['liquidflame-shot'] = {['name'] = 'liquidflame-shot', ['label'] = 'Liquid Flame', ['weight'] = 100, ['type'] = 'item', ['image'] = 'liquidflame-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Super Hot'}, + ['minihulk-shot'] = {['name'] = 'minihulk-shot', ['label'] = 'Mini Hulk', ['weight'] = 100, ['type'] = 'item', ['image'] = 'minihulk-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Thats your secret.. Youre Always Drunk'}, + ['orange-blast'] = {['name'] = 'orange-blast', ['label'] = 'Orange Blast', ['weight'] = 100, ['type'] = 'item', ['image'] = 'orange-blast.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Tangy'}, + ['orange-vodka'] = {['name'] = 'orange-vodka', ['label'] = 'Orange Vodka', ['weight'] = 100, ['type'] = 'item', ['image'] = 'orange-vodka.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Hit With The Ladies'}, + ['pina-colada'] = {['name'] = 'pina-colada', ['label'] = 'Pina Colada', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pina-colada.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'In The Pouring Rain?'}, + ['pineapple-gin'] = {['name'] = 'pineapple-gin', ['label'] = 'Pineapple Gin', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pineapple-gin.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fruity Concoctions'}, + ['polarbear'] = {['name'] = 'polarbear', ['label'] = 'Polar Bear', ['weight'] = 100, ['type'] = 'item', ['image'] = 'polarbear.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Icy Cold'}, + ['rumcoke'] = {['name'] = 'rumcoke', ['label'] = 'Rum n Coke', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rumcoke.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Kinda Pirates life for me'}, + ['sourblast-shot'] = {['name'] = 'sourblast-shot', ['label'] = 'Sour Blast', ['weight'] = 100, ['type'] = 'item', ['image'] = 'sourblast-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Too Sour Maybe?..'}, + ['tequila-shot'] = {['name'] = 'tequila-shot', ['label'] = 'Tequila', ['weight'] = 100, ['type'] = 'item', ['image'] = 'tequila-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Classic'}, + ['vampireskiss-shot'] = {['name'] = 'vampireskiss-shot', ['label'] = 'Vampires Kiss', ['weight'] = 100, ['type'] = 'item', ['image'] = 'vampireskiss-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Bloody Encounter'}, + ['vampireslove-shot'] = {['name'] = 'vampireslove-shot', ['label'] = 'Vampires Love', ['weight'] = 100, ['type'] = 'item', ['image'] = 'vampireslove-shot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Team E vs Team J'}, + ['pisswasser-crate'] = {['name'] = 'pisswasser-crate', ['label'] = 'Pisswasser Crate', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'pisswasser-crate.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Contains Beer'}, + ['pisswasser'] = {['name'] = 'pisswasser', ['label'] = 'Pisswasser', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pisswasser.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its Pisswasser'}, + ['pisswasser-lite'] = {['name'] = 'pisswasser-lite', ['label'] = 'Pisswasser Lite', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pisswasser-lite.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Smooth Low Alcohol Version'}, + ['pisswasser-dark'] = {['name'] = 'pisswasser-dark', ['label'] = 'Pisswasser Dark', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pisswasser-dark.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Rich Foamy Taste'}, + ['mesa-coffee'] = {['name'] = 'mesa-coffee', ['label'] = 'Mesa Coffee', ['weight'] = 100, ['type'] = 'item', ['image'] = 'mesa-coffee.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mesanuxta Branded Coffee'}, + ['mesa-beans'] = {['name'] = 'mesa-beans', ['label'] = 'Mesa Beans', ['weight'] = 100, ['type'] = 'item', ['image'] = 'mesa-beans.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mesanuxta Branded Beans'}, + ['mesa-cup'] = {['name'] = 'mesa-cup', ['label'] = 'Mesa Cup', ['weight'] = 100, ['type'] = 'item', ['image'] = 'mesa-cup.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mesanuxta Branded Cup'}, + ['cocktail-mix'] = {['name'] = 'cocktail-mix', ['label'] = 'Cocktail Mix', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cocktail-mix.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'All The Ingredients Needed to Make Cocktails'}, + ['shots-mix'] = {['name'] = 'shots-mix', ['label'] = 'Shots Mix', ['weight'] = 100, ['type'] = 'item', ['image'] = 'shots-mix.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'All The Ingredients Needed to Make Shots'}, + ['cocktail-glass'] = {['name'] = 'cocktail-glass', ['label'] = 'Cocktail Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cocktail-glass.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Shiny Cocktail Glass'}, + ['shot-glass'] = {['name'] = 'shot-glass', ['label'] = 'Shot Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'shot-glass.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Little Shot Glass'}, + + + + -- prison + ["ass-meth"] = {["name"] = "ass-meth", ["label"] = "Ass Meth", ["weight"] = 1000, ["type"] = "item", ["image"] = "ass-meth.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A batch of some real crappy meth.."}, + ["magnet-stick"] = {["name"] = "magnet-stick", ["label"] = "Little Magnet", ["weight"] = 500, ["type"] = "item", ["image"] = "magnet-stick.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A little magnet on an extendable stick.."}, + ["charging-brick"] = {["name"] = "charging-brick", ["label"] = "Charging Brick", ["weight"] = 500, ["type"] = "item", ["image"] = "charger-brick.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A charging brick.."}, + ["charging-cable"] = {["name"] = "charging-cable", ["label"] = "Charging Cable", ["weight"] = 500, ["type"] = "item", ["image"] = "charger-cable.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "You can use this to charge your phone."}, + ["tower-keys"] = {["name"] = "tower-keys", ["label"] = "Keys on a ring", ["weight"] = 500, ["type"] = "item", ["image"] = "tower-keys.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Some of these are bent beyond using"}, + ["infirmary-key"] = {["name"] = "infirmary-key", ["label"] = "Keycard", ["weight"] = 500, ["type"] = "item", ["image"] = "infirmary-key.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A keycard that gets you in to a laboratory?"}, + ['prison-ephedrine'] = {['name'] = 'prison-ephedrine', ['label'] = 'Ephedrine', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'ephedrine.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Prescription medicine used to treat the symptoms of low blood pressure'}, + ["sudafed"] = {["name"] = "sudafed", ["label"] = "Sudafed", ["weight"] = 500, ["type"] = "item", ["image"] = "sudafed.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Cold and congestive medicine"}, + ["nailpolish-remover"] = {["name"] = "nailpolish-remover", ["label"] = "Nail Polish Remover", ["weight"] = 500, ["type"] = "item", ["image"] = "nailpolish-remover.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "For cleaning your nails. Contains acetone."}, + ["prison-lighter"] = {["name"] = "prison-lighter", ["label"] = "Lighter", ["weight"] = 500, ["type"] = "item", ["image"] = "prison-lighter.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Produces a solid, constant flame."}, + ["prison-baggy"] = {["name"] = "prison-baggy", ["label"] = "Plastic Bag", ["weight"] = 500, ["type"] = "item", ["image"] = "prison-baggy.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Empty bag to put something is.."}, + ["prison-foodprep"] = {["name"] = "prison-foodprep", ["label"] = "Prepared Food", ["weight"] = 0, ["type"] = "item", ["image"] = "prison-foodprep.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Medicore food ready for mediocre citiznes.."}, + ["prison-foodsupplies"] = {["name"] = "prison-foodsupplies", ["label"] = "Ingredients", ["weight"] = 0, ["type"] = "item", ["image"] = "prison-foodsupplies.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Random food ingredients."}, + ['deadphone'] = {['name'] = 'deadphone', ['label'] = 'Dead Smartphone', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'deadphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice enough phone, looks like the battery is dead..'}, + ['chargedphone'] = {['name'] = 'chargedphone', ['label'] = 'Charged Smartphone', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'chargedphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice enough phone. This used to belong to a guard?'}, + ["care-package"] = {["name"] = "care-package", ["label"] = "Care Package Flare", ["weight"] = 5000, ["type"] = "item", ["image"] = "weapon_flare.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A prison care package"}, + -- houserobbery + ["houselaptop"] = {["name"] = "houselaptop", ["label"] = "House Hacking Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "houselaptop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["mansionlaptop"] = {["name"] = "mansionlaptop", ["label"] = "Mansion Hacking Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "mansionlaptop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + + -- moneywash + ["bandsofnotes"] = {["name"] = "bandsofnotes", ["label"] = "Bands Of Notes", ["weight"] = 1, ["type"] = "item", ["image"] = "cashroll.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bands of notes belonging to a 24/7 supermarket"}, + ["stacksofcash"] = {["name"] = "stacksofcash", ["label"] = "Stacks Of Cash", ["weight"] = 1, ["type"] = "item", ["image"] = "cashstack.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Stacks of cash belonging to a bank"}, + ["moneyorder"] = {["name"] = "moneyorder", ["label"] = "Money Order", ["weight"] = 0, ["type"] = "item", ["image"] = "moneyorder.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A money order. Turn this in to get paid. "}, + + -- bandage + ['kittybandage'] = {['name'] = 'kittybandage', ['label'] = 'Hello Kitty Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'kittybandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'These will help you feel Purrrrrfect'}, + ['swbandage'] = {['name'] = 'swbandage', ['label'] = 'Star Wars Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'swbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'No bacta tank around..these will do'}, + ['shrekbandage'] = {['name'] = 'shrekbandage', ['label'] = 'Shrek Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'shrekbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Next best thing after a mud bath!'}, + ['carsbandage'] = {['name'] = 'carsbandage', ['label'] = 'Cars Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'carsbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Healing you FAST. SPEED!'}, + ['mousebandage'] = {['name'] = 'mousebandage', ['label'] = 'Disney Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'mousebandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magical healing!'}, + ['avengersbandage'] = {['name'] = 'avengersbandage', ['label'] = 'Avengers Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'avengersbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You have been saved by the Avengers'}, + ['baconbandage'] = {['name'] = 'baconbandage', ['label'] = 'Bacon Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'baconbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Dont eat these'}, + ['pokemonbandage'] = {['name'] = 'pokemonbandage', ['label'] = 'Pokemon Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'pokemonbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I wanna feel the very best..'}, + ['spongebobbandage'] = {['name'] = 'spongebobbandage', ['label'] = 'Spongebob Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'spongebobbandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'This can heal your Bikini Bottom'}, + ['toystorybandage'] = {['name'] = 'toystorybandage', ['label'] = 'Toy Story Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'toystory-bandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You have been saved by the Avengers'}, + ['scoobydobandage'] = {['name'] = 'scoobydobandage', ['label'] = 'Scooby-Do Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'scoobydobandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'We got some help for you now!'}, + ['packofbandaids'] = {['name'] = 'packofbandaids', ['label'] = 'Pack of Bandaids', ['weight'] = 0, ['type'] = 'item', ['image'] = 'packofbandaids.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pack of 5 bandaids'}, + + + -- drugs + ["coke_box"] = {["name"] = "coke_box", ["label"] = "Box with Coke", ["weight"] = 2000, ["type"] = "item", ["image"] = "coke_box.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Be careful not to spill it on the ground"}, + ["trowel"] = {["name"] = "trowel", ["label"] = "Trowel", ["weight"] = 250, ["type"] = "item", ["image"] = "trowel.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Perfect for your garden or for Coca plant"}, + ["coke_leaf"] = {["name"] = "coke_leaf", ["label"] = "Coca leaves", ["weight"] = 15, ["type"] = "item", ["image"] = "coca_leaf.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Leaf from amazing plant"}, + ["coke_access"] = {["name"] = "coke_access", ["label"] = "Access card", ["weight"] = 50, ["type"] = "item", ["image"] = "coke_access.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Access Card for Coke Lab"}, + ["coke_raw"] = {["name"] = "coke_raw", ["label"] = "Raw Coke", ["weight"] = 50, ["type"] = "item", ["image"] = "coke_raw.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Coke with some dirty particles"}, + ["coke_pure"] = {["name"] = "coke_pure", ["label"] = "Pure Coke", ["weight"] = 70, ["type"] = "item", ["image"] = "coke_pure.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Coke without any dirty particles"}, + ["coke_figure"] = {["name"] = "coke_figure", ["label"] = "Action Figure", ["weight"] = 150, ["type"] = "item", ["image"] = "coke_figure.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Action Figure of the cartoon superhero Impotent Rage"}, + ["coke_figureempty"] = {["name"] = "coke_figureempty", ["label"] = "Action Figure", ["weight"] = 150, ["type"] = "item", ["image"] = "coke_figureempty.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Action Figure of the cartoon superhero Impotent Rage"}, + ["coke_figurebroken"] = {["name"] = "coke_figurebroken", ["label"] = "Pieces of Action Figure", ["weight"] = 100, ["type"] = "item", ["image"] = "coke_figurebroken.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "You can throw this away or try to repair with glue"}, + ["meth_amoniak"] = {["name"] = "meth_amoniak", ["label"] = "Ammonia", ["weight"] = 1000, ["type"] = "item", ["image"] = "meth_amoniak.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Warning! Dangerous Chemicals!"}, + ["meth_pipe"] = {["name"] = "meth_pipe", ["label"] = "Meth Pipe", ["weight"] = 880, ["type"] = "item", ["image"] = "meth_pipe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your new crystal clear stuff!"}, + ["crack_pipe"] = {["name"] = "crack_pipe", ["label"] = "Crack Pipe", ["weight"] = 550, ["type"] = "item", ["image"] = "crack_pipe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your Crack!"}, + ["syringe"] = {["name"] = "syringe", ["label"] = "Syringe", ["weight"] = 300, ["type"] = "item", ["image"] = "syringe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your new crystal clear stuff!"}, + ["meth_syringe"] = {["name"] = "meth_syringe", ["label"] = "Syringe", ["weight"] = 320, ["type"] = "item", ["image"] = "meth_syringe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your new crystal clear stuff!"}, + ["heroin_syringe"] = {["name"] = "heroin_syringe", ["label"] = "Syringe", ["weight"] = 320, ["type"] = "item", ["image"] = "heroin_syringe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your new crystal clear stuff!"}, + ["meth_sacid"] = {["name"] = "meth_sacid", ["label"] = "Sodium Benzoate Canister", ["weight"] = 5000, ["type"] = "item", ["image"] = "meth_sacid.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Warning! Dangerous Chemicals!"}, + ["meth_emptysacid"] = {["name"] = "meth_emptysacid", ["label"] = "Empty Canister", ["weight"] = 2000, ["type"] = "item", ["image"] = "meth_emptysacid.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Material: Plastic, Good for Sodium Benzoate"}, + ["meth_access"] = {["name"] = "meth_access", ["label"] = "Access Card", ["weight"] = 50, ["type"] = "item", ["image"] = "meth_access.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Access Card for Meth Lab"}, + ["meth_glass"] = {["name"] = "meth_glass", ["label"] = "Tray with meth", ["weight"] = 1000, ["type"] = "item", ["image"] = "meth_glass.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Needs to be smashed with hammer"}, + ["meth_sharp"] = {["name"] = "meth_sharp", ["label"] = "Tray with smashed meth", ["weight"] = 1000, ["type"] = "item", ["image"] = "meth_sharp.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Can be packed"}, + ["meth_bag"] = {["name"] = "meth_bag", ["label"] = "Meth Bag", ["weight"] = 1000, ["type"] = "item", ["image"] = "meth_bag.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Plastic bag with magic stuff!"}, + ["weed_package"] = {["name"] = "weed_package", ["label"] = "Weed Bag", ["weight"] = 500, ["type"] = "item", ["image"] = "weed_package.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Plastic bag with magic stuff!"}, + ["weed_access"] = {["name"] = "weed_access", ["label"] = "Access Card", ["weight"] = 50, ["type"] = "item", ["image"] = "weed_access.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Access Card for Weed Lab"}, + ["weed_bud"] = {["name"] = "weed_bud", ["label"] = "Weed Bud", ["weight"] = 40, ["type"] = "item", ["image"] = "weed_bud.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Needs to be clean at the table"}, + ["weed_blunt"] = {["name"] = "weed_blunt", ["label"] = "Blunt", ["weight"] = 90, ["type"] = "item", ["image"] = "weed_blunt.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your weed!"}, + ["weed_wrap"] = {["name"] = "weed_wrap", ["label"] = "Blunt Wraps", ["weight"] = 75, ["type"] = "item", ["image"] = "weed_wrap.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Get Weed Bag and roll blunt!"}, + ["weed_papers"] = {["name"] = "weed_papers", ["label"] = "Weed Papers", ["weight"] = 15, ["type"] = "item", ["image"] = "weed_papers.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Get Weed Bag and roll joint!"}, + ["weed_joint"] = {["name"] = "weed_joint", ["label"] = "Joint", ["weight"] = 50, ["type"] = "item", ["image"] = "weed_joint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Enjoy your weed!"}, + ["weed_budclean"] = {["name"] = "weed_budclean", ["label"] = "Weed Bud", ["weight"] = 35, ["type"] = "item", ["image"] = "weed_budclean.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "You can pack this at the table"}, + ["plastic_bag"] = {["name"] = "plastic_bag", ["label"] = "Plastic Bag", ["weight"] = 8, ["type"] = "item", ["image"] = "plastic_bag.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "You can pack a lot of stuff here!"}, + ["scissors"] = {["name"] = "scissors", ["label"] = "Scissors", ["weight"] = 40, ["type"] = "item", ["image"] = "scissors.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "To help you with collecting"}, + ["ecstasy1"] = {["name"] = "ecstasy1", ["label"] = "Ectasy", ["weight"] = 10, ["type"] = "item", ["image"] = "ecstasy1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["ecstasy2"] = {["name"] = "ecstasy2", ["label"] = "Ectasy", ["weight"] = 10, ["type"] = "item", ["image"] = "ecstasy2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["ecstasy3"] = {["name"] = "ecstasy3", ["label"] = "Ectasy", ["weight"] = 10, ["type"] = "item", ["image"] = "ecstasy3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["ecstasy4"] = {["name"] = "ecstasy4", ["label"] = "Ectasy", ["weight"] = 10, ["type"] = "item", ["image"] = "ecstasy4.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["ecstasy5"] = {["name"] = "ecstasy5", ["label"] = "Ectasy", ["weight"] = 10, ["type"] = "item", ["image"] = "ecstasy5.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["lsd1"] = {["name"] = "lsd1", ["label"] = "LSD", ["weight"] = 10, ["type"] = "item", ["image"] = "lsd1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["lsd2"] = {["name"] = "lsd2", ["label"] = "LSD", ["weight"] = 10, ["type"] = "item", ["image"] = "lsd2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["lsd3"] = {["name"] = "lsd3", ["label"] = "LSD", ["weight"] = 10, ["type"] = "item", ["image"] = "lsd3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["lsd4"] = {["name"] = "lsd4", ["label"] = "LSD", ["weight"] = 10, ["type"] = "item", ["image"] = "lsd4.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["lsd5"] = {["name"] = "lsd5", ["label"] = "LSD", ["weight"] = 10, ["type"] = "item", ["image"] = "lsd5.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["magicmushroom"] = {["name"] = "magicmushroom", ["label"] = "Magic Mushroom", ["weight"] = 30, ["type"] = "item", ["image"] = "magicmushroom.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["peyote"] = {["name"] = "peyote", ["label"] = "Peyote", ["weight"] = 30, ["type"] = "item", ["image"] = "peyote.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["xanaxpack"] = {["name"] = "xanaxpack", ["label"] = "Xanax Pack", ["weight"] = 130, ["type"] = "item", ["image"] = "xanaxpack.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["xanaxplate"] = {["name"] = "xanaxplate", ["label"] = "Xanax Plate", ["weight"] = 30, ["type"] = "item", ["image"] = "xanaxplate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["xanaxpill"] = {["name"] = "xanaxpill", ["label"] = "Xanax Pill", ["weight"] = 2, ["type"] = "item", ["image"] = "xanaxpill.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["glue"] = {["name"] = "glue", ["label"] = "Glue", ["weight"] = 30, ["type"] = "item", ["image"] = "glue.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Good for repairing things!"}, + ["hammer"] = {["name"] = "hammer", ["label"] = "Hammer", ["weight"] = 500, ["type"] = "item", ["image"] = "hammer.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Good for smashing things!"}, + ["poppyplant"] = {["name"] = "poppyplant", ["label"] = "Poppy Plant", ["weight"] = 30, ["type"] = "item", ["image"] = "poppyplant.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Very nice plant!"}, + ["heroin"] = {["name"] = "heroin", ["label"] = "Heroin", ["weight"] = 30, ["type"] = "item", ["image"] = "heroin.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["crack"] = {["name"] = "crack", ["label"] = "Crack", ["weight"] = 30, ["type"] = "item", ["image"] = "crack.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Explore a new universe!"}, + ["baking_soda"] = {["name"] = "baking_soda", ["label"] = "Baking Soda", ["weight"] = 30, ["type"] = "item", ["image"] = "baking_soda.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Baking Bad!"}, + + + ['seedonion'] = { + ['name'] = 'seedonion', + ['label'] = 'Onion Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedonion.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['seedtea'] = { + ['name'] = 'seedtea', + ['label'] = 'Tea Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedtea.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['seedcoffee'] = { + ['name'] = 'seedcoffee', + ['label'] = 'Coffee Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedcoffee.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['seedpotato'] = { + ['name'] = 'seedpotato', + ['label'] = 'Potato Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedpotato.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['seedoat'] = { + ['name'] = 'seedoat', + ['label'] = 'Oat Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedoat.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['seedlettuce'] = { + ['name'] = 'seedlettuce', + ['label'] = 'Lettuce Seed', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'seedlettuce.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice seed' + }, + + ['onion'] = { + ['name'] = 'onion', + ['label'] = 'Onion', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'onion.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + ['tea'] = { + ['name'] = 'tea', + ['label'] = 'Tea', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'tea.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + ['coffee'] = { + ['name'] = 'coffee', + ['label'] = 'Coffee', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'coffee.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + ['potato'] = { + ['name'] = 'potato', + ['label'] = 'Potato', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'potato.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + ['oat'] = { + ['name'] = 'oat', + ['label'] = 'Oat', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'oat.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + ['lettuce'] = { + ['name'] = 'lettuce', + ['label'] = 'Lettuce', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'lettuce.png', + ['unique'] = false, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A nice Item' + }, + + -- hunting + ['leather'] = {['name'] = 'Leather', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'leather.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Leather'}, + ['meat'] = {['name'] = 'Meat', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'meat.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Meat'}, + ['feather'] = {['name'] = 'Feather', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'feather.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Feather'}, + ['coyote_leather'] = {['name'] = 'Coyote Leather', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'coyote_leather.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Coyote Leather'}, + ['panther_leather'] = {['name'] = 'Panther Leather', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'panther_leather.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Panther Leather'}, + ['antler'] = {['name'] = 'Antler', ['label'] = '', ['weight'] = 1, ['type'] = 'item', ['image'] = 'antler.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Antler'}, + --- ps-weedplanting + ['weedplant_seedm'] = {['name'] = 'weedplant_seedm', ['label'] = 'Male Weed Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weedplant_seed.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Male Weed Seed'}, + ['weedplant_seedf'] = {['name'] = 'weedplant_seedf', ['label'] = 'Female Weed Seed', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weedplant_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Female Weed Seed'}, + ['weedplant_branch'] = {['name'] = 'weedplant_branch', ['label'] = 'Weed Branch', ['weight'] = 10000, ['type'] = 'item', ['image'] = 'weedplant_branch.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Weed plant'}, + ['weedplant_weed'] = {['name'] = 'weedplant_weed', ['label'] = 'Dried Weed', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weedplant_weed.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Weed ready for packaging'}, + ['weedplant_packedweed'] = {['name'] = 'weedplant_packedweed', ['label'] = 'Packed Weed', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weedplant_weed.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Weed ready for sale'}, + ['weedplant_package'] = {['name'] = 'weedplant_package', ['label'] = 'Suspicious Package', ['weight'] = 10000, ['type'] = 'item', ['image'] = 'weedplant_package.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Suspicious Package'}, + ['plant_tub'] = {['name'] = 'plant_tub', ['label'] = 'Plant Tub', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'plant_tub.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Pot for planting plants'}, + ['empty_watering_can'] = {['name'] = 'empty_watering_can', ['label'] = 'Empty Watering Can', ['weight'] = 500, ['type'] = 'item', ['image'] = 'watering_can.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Empty watering can'}, + ['full_watering_can'] = {['name'] = 'full_watering_can', ['label'] = 'Full Watering Can', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'watering_can.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Watering can filled with water for watering plants'}, + ["keya"] = {["name"] = "keya", ["label"] = "Labkey A", ["weight"] = 0, ["type"] = "item", ["image"] = "keya.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Labkey A.."}, + ["usb_green"] = {["name"] = "usb_green", ["label"] = "USB Drive", ["weight"] = 1000, ["type"] = "item", ["image"] = "usb_green.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A green USB flash drive"}, + ["usb_red"] = {["name"] = "usb_red", ["label"] = "USB Drive", ["weight"] = 1000, ["type"] = "item", ["image"] = "usb_red.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A red USB flash drive"}, + ["usb_blue"] = {["name"] = "usb_blue", ["label"] = "USB Drive", ["weight"] = 1000, ["type"] = "item", ["image"] = "usb_blue.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A blue USB flash drive"}, + ["usb_gold"] = {["name"] = "usb_gold", ["label"] = "USB Drive", ["weight"] = 1000, ["type"] = "item", ["image"] = "usb_gold.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A gold USB flash drive"}, + ["boombox"] = {["name"] = "boombox", ["label"] = "Boombox", ["weight"] = 5000, ["type"] = "item", ["image"] = "boombox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Play some music anywhere."}, + ["usb_grey"] = {["name"] = "usb_grey", ["label"] = "USB Drive", ["weight"] = 1000, ["type"] = "item", ["image"] = "usb_grey.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A grey USB flash drive"}, + ["nitroradio"] = { + ["name"] = "nitroradio", + ["label"] = "Nitro Radio ", + ["weight"] = 1000, + ["type"] = "item", + ["image"] = "nitroradio.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "You can use this in Contracts" + }, + + ["nitrocash"] = { + ["name"] = "nitrocash", + ["label"] = "Nitro Cash ", + ["weight"] = 0, + ["type"] = "item", + ["image"] = "nitrocash.png", + ["unique"] = false, + ["useable"] = false, + ["shouldClose"] = false, + ["combinable"] = nil, + ["description"] = "You can buy some cool stuff with this" + }, + + -- Shared Items + ['skateboard'] = {['name'] = 'skateboard', ['label'] = 'Skateboard', ['weight'] = 3000, ['type'] = 'item', ['image'] = 'skateboard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Skateboard'}, + -- uwu-- + ["emsbag"] = {["name"] = "emsbag", ["label"] = "emsbag", ["weight"] = 150, ["type"] = "item", ["image"] = "emsbag.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + + -- UwuU Cafe Items + ["shiny_wasabi"] = {["name"] = "shiny_wasabi", ["label"] = "Shiny wasabi", ["weight"] = 150, ["type"] = "item", ["image"] = "shiny_wasabi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["onion"] = {["name"] = "onion", ["label"] = "Onion", ["weight"] = 150, ["type"] = "item", ["image"] = "onion.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["chicken_thighs"] = {["name"] = "chicken_thighs", ["label"] = "Chicken thighs", ["weight"] = 150, ["type"] = "item", ["image"] = "chicken_thighs.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["virgin_olive_oil"] = {["name"] = "virgin_olive_oil", ["label"] = "Virgin olive oil", ["weight"] = 150, ["type"] = "item", ["image"] = "virgin_olive_oil.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["rice"] = {["name"] = "rice", ["label"] = "Rice", ["weight"] = 150, ["type"] = "item", ["image"] = "rice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["soy_sauce"] = {["name"] = "soy_sauce", ["label"] = "Soy sauce", ["weight"] = 150, ["type"] = "item", ["image"] = "soy_sauce.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["pullman_bread"] = {["name"] = "pullman_bread", ["label"] = "Pullman bread", ["weight"] = 150, ["type"] = "item", ["image"] = "pullman_bread.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["egg"] = {["name"] = "egg", ["label"] = "Egg", ["weight"] = 150, ["type"] = "item", ["image"] = "egg.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["chicken_breast"] = {["name"] = "chicken_breast", ["label"] = "Chicken breast", ["weight"] = 150, ["type"] = "item", ["image"] = "chicken_breast.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["flour"] = {["name"] = "flour", ["label"] = "Flour", ["weight"] = 150, ["type"] = "item", ["image"] = "flour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["butter"] = {["name"] = "butter", ["label"] = "Butter", ["weight"] = 150, ["type"] = "item", ["image"] = "butter.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["milk"] = {["name"] = "milk", ["label"] = "Milk", ["weight"] = 150, ["type"] = "item", ["image"] = "milk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sea_moss"] = {["name"] = "sea_moss", ["label"] = "Sea moss", ["weight"] = 150, ["type"] = "item", ["image"] = "sea_moss.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["matcha_powder"] = {["name"] = "matcha_powder", ["label"] = "Matcha powder", ["weight"] = 150, ["type"] = "item", ["image"] = "matcha_powder.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sugar"] = {["name"] = "sugar", ["label"] = "Sugar", ["weight"] = 150, ["type"] = "item", ["image"] = "suger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["dried_boba_tapioca_pearls"] = {["name"] = "dried_boba_tapioca_pearls", ["label"] = "Dried boba tapioca pearls", ["weight"] = 150, ["type"] = "item", ["image"] = "dried_boba_tapioca_pearls.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["juice"] = {["name"] = "juice", ["label"] = "Juice", ["weight"] = 150, ["type"] = "item", ["image"] = "juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["lemon"] = {["name"] = "lemon", ["label"] = "Lemon", ["weight"] = 150, ["type"] = "item", ["image"] = "lemon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["mint"] = {["name"] = "mint", ["label"] = "Mint", ["weight"] = 150, ["type"] = "item", ["image"] = "mint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["chicken"] = {["name"] = "chicken", ["label"] = "Chicken", ["weight"] = 150, ["type"] = "item", ["image"] = "chicken.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["baking_powder"] = {["name"] = "baking_powder", ["label"] = "Baking powder", ["weight"] = 150, ["type"] = "item", ["image"] = "baking_powder.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["rice_flour"] = {["name"] = "rice_flour", ["label"] = "Rice flour", ["weight"] = 150, ["type"] = "item", ["image"] = "rice_flour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["awwdorable_valentines_chocolate"] = {["name"] = "awwdorable_valentines_chocolate", ["label"] = "Awwdorable valentines chocolate", ["weight"] = 150, ["type"] = "item", ["image"] = "awwdorable_valentines_chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["booba_milk_tea_1"] = {["name"] = "booba_milk_tea_1", ["label"] = "Booba milk tea Brown", ["weight"] = 150, ["type"] = "item", ["image"] = "booba_milk_tea_1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["booba_milk_tea_2"] = {["name"] = "booba_milk_tea_2", ["label"] = "Booba milk tea Orange", ["weight"] = 150, ["type"] = "item", ["image"] = "booba_milk_tea_2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["brewed_coffe"] = {["name"] = "brewed_coffe", ["label"] = "Brewed coffe", ["weight"] = 150, ["type"] = "item", ["image"] = "brewed_coffe.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cocoa_powder"] = {["name"] = "cocoa_powder", ["label"] = "Cocoa powder", ["weight"] = 150, ["type"] = "item", ["image"] = "cocoa_powder.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["doki_doki_pancakes"] = {["name"] = "doki_doki_pancakes", ["label"] = "Doki doki pancakes", ["weight"] = 150, ["type"] = "item", ["image"] = "doki_doki_pancakes.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["gingerkitty_cookie"] = {["name"] = "gingerkitty_cookie", ["label"] = "Gingerkitty cookie", ["weight"] = 150, ["type"] = "item", ["image"] = "gingerkitty_cookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["hamburg_stake"] = {["name"] = "hamburg_stake", ["label"] = "Hamburg Steak", ["weight"] = 150, ["type"] = "item", ["image"] = "hamburg_stake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["hot_chocolate"] = {["name"] = "hot_chocolate", ["label"] = "Hot chocolate", ["weight"] = 150, ["type"] = "item", ["image"] = "hot_chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["jelly_beans"] = {["name"] = "jelly_beans", ["label"] = "Jelly beans", ["weight"] = 150, ["type"] = "item", ["image"] = "jelly_beans.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["lovely_hot_chocolate"] = {["name"] = "lovely_hot_chocolate", ["label"] = "lovely hot chocolate", ["weight"] = 150, ["type"] = "item", ["image"] = "lovely_hot_chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["matcha_powder"] = {["name"] = "matcha_powder", ["label"] = "Matcha powder", ["weight"] = 150, ["type"] = "item", ["image"] = "matcha_powder.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["matcha_coffee"] = {["name"] = "matcha_coffee", ["label"] = "Matcha coffee", ["weight"] = 150, ["type"] = "item", ["image"] = "matcha_coffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["meowchi_mochi_ice_cream"] = {["name"] = "meowchi_mochi_ice_cream", ["label"] = "Meowchi mochi ice cream", ["weight"] = 150, ["type"] = "item", ["image"] = "meowchi_mochi_ice_cream.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["noodles"] = {["name"] = "noodles", ["label"] = "Noodles", ["weight"] = 150, ["type"] = "item", ["image"] = "noodles.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["om_nom_omurice"] = {["name"] = "om_nom_omurice", ["label"] = "Om nom omurice", ["weight"] = 150, ["type"] = "item", ["image"] = "om_nom_omurice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["nuts"] = {["name"] = "nuts", ["label"] = "Nuts", ["weight"] = 150, ["type"] = "item", ["image"] = "nuts.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["rice_balls"] = {["name"] = "rice_balls", ["label"] = "Rice balls", ["weight"] = 150, ["type"] = "item", ["image"] = "rice_balls.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["rice_flour"] = {["name"] = "rice_flour", ["label"] = "Rice flour", ["weight"] = 150, ["type"] = "item", ["image"] = "rice_flour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sea_moss"] = {["name"] = "sea_moss", ["label"] = "Sea mossl", ["weight"] = 150, ["type"] = "item", ["image"] = "sea_moss.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["soy_sauce"] = {["name"] = "soy_sauce", ["label"] = "Soy saucesoy sauce", ["weight"] = 150, ["type"] = "item", ["image"] = "soy_sauce.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["strawberry"] = {["name"] = "strawberry", ["label"] = "Strawberry", ["weight"] = 150, ["type"] = "item", ["image"] = "strawberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["strawberry_shortcake"] = {["name"] = "strawberry_shortcake", ["label"] = "Strawberry shortcake", ["weight"] = 150, ["type"] = "item", ["image"] = "strawberry_shortcake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sugoi_katsu_sando"] = {["name"] = "sugoi_katsu_sando", ["label"] = "Sugoi katsu sando", ["weight"] = 150, ["type"] = "item", ["image"] = "sugoi_katsu_sando.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sweet_herbal_tea"] = {["name"] = "sweet_herbal_tea", ["label"] = "Sweet herbal tea", ["weight"] = 150, ["type"] = "item", ["image"] = "sweet_herbal_tea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["warm_chicken_noodle"] = {["name"] = "warm_chicken_noodle", ["label"] = "Warm chicken noodle", ["weight"] = 150, ["type"] = "item", ["image"] = "warm_chicken_noodle.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["glass_tall_dirty"] = {["name"] = "glass_tall_dirty", ["label"] = "Glass tall dirty", ["weight"] = 150, ["type"] = "item", ["image"] = "glass_tall_dirty.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["bar_bowl_dirty"] = {["name"] = "bar_bowl_dirty", ["label"] = "Bar bowl dirty", ["weight"] = 150, ["type"] = "item", ["image"] = "bar_bowl_dirty.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["bar_bowl"] = {["name"] = "bar_bowl", ["label"] = "Bar bowl", ["weight"] = 150, ["type"] = "item", ["image"] = "bar_bowl.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["steak"] = {["name"] = "steak", ["label"] = "Steak", ["weight"] = 150, ["type"] = "item", ["image"] = "steak.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["oxygen_cake"] = {["name"] = "oxygen_cake", ["label"] = "Oxygen cake", ["weight"] = 150, ["type"] = "item", ["image"] = "oxygen_cake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["dragos_fire_cupcake"] = {["name"] = "dragos_fire_cupcake", ["label"] = "Dragos fire cupcake", ["weight"] = 150, ["type"] = "item", ["image"] = "dragos_fire_cupcake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["kira_kira_currye"] = {["name"] = "kira_kira_currye", ["label"] = "Kira kira currye", ["weight"] = 150, ["type"] = "item", ["image"] = "kira_kira_currye.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["purrfect_parfait_ballaberry"] = {["name"] = "purrfect_parfait_ballaberry", ["label"] = "Purrfect parfait ballaberry", ["weight"] = 150, ["type"] = "item", ["image"] = "purrfect_parfait_ballaberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ballbarry_cupcake"] = {["name"] = "ballbarry_cupcake", ["label"] = "Ballbarry cupcake", ["weight"] = 150, ["type"] = "item", ["image"] = "ballbarry_cupcake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["purrfect_parfait"] = {["name"] = "purrfect_parfait", ["label"] = "Purrfect parfait", ["weight"] = 150, ["type"] = "item", ["image"] = "purrfect_parfait.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cat_macaroon_brown"] = {["name"] = "cat_macaroon_brown", ["label"] = "Cat macaroon brown", ["weight"] = 150, ["type"] = "item", ["image"] = "cat_macaroon_brown.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cat_macaroon_green"] = {["name"] = "cat_macaroon_green", ["label"] = "Cat macaroon green", ["weight"] = 150, ["type"] = "item", ["image"] = "cat_macaroon_green.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cat_macaroon_pink"] = {["name"] = "cat_macaroon_pink", ["label"] = "Cat macaroon pink", ["weight"] = 150, ["type"] = "item", ["image"] = "cat_macaroon_pink.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cat_macaroon_turquoise"] = {["name"] = "cat_macaroon_turquoise", ["label"] = "Cat macaroon turquoise", ["weight"] = 150, ["type"] = "item", ["image"] = "cat_macaroon_turquoise.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["brown_dye"] = {["name"] = "brown_dye", ["label"] = "Brown dye", ["weight"] = 150, ["type"] = "item", ["image"] = "brown_dye.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["pink_dye"] = {["name"] = "pink_dye", ["label"] = "Pink dye", ["weight"] = 150, ["type"] = "item", ["image"] = "pink_dye.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["green_dye"] = {["name"] = "green_dye", ["label"] = "Green dye", ["weight"] = 150, ["type"] = "item", ["image"] = "green_dye.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["turquoise_dye"] = {["name"] = "turquoise_dye", ["label"] = "Turquoise dye", ["weight"] = 150, ["type"] = "item", ["image"] = "turquoise_dye.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["plate"] = {["name"] = "plate", ["label"] = "Plate", ["weight"] = 150, ["type"] = "item", ["image"] = "plate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cup"] = {["name"] = "cup", ["label"] = "Cup", ["weight"] = 150, ["type"] = "item", ["image"] = "cup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["cup_dirty"] = {["name"] = "cup_dirty", ["label"] = "Cup dirty", ["weight"] = 150, ["type"] = "item", ["image"] = "cup_dirty.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["plate_dirty"] = {["name"] = "plate_dirty", ["label"] = "Plate dirty", ["weight"] = 150, ["type"] = "item", ["image"] = "cat_purple.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ice"] = {["name"] = "ice", ["label"] = "Ice", ["weight"] = 150, ["type"] = "item", ["image"] = "ice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["brewed_coffee"] = {["name"] = "brewed_coffee", ["label"] = "Brewed Coffee", ["weight"] = 150, ["type"] = "item", ["image"] = "brewed_coffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + + ----- md-coke + ["coke"] = {["name"] = "coke", ["label"] = "Raw Cocaine", ["weight"] = 1000, ["type"] = "item", ["image"] = "coke.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Processed cocaine"}, + ["coca_leaf"] = {["name"] = "coca_leaf", ["label"] = "Cocaine leaves", ["weight"] = 1500, ["type"] = "item", ["image"] = "coca_leaf.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Cocaine leaves that must be processed !"}, + ["poppyresin"] = {["name"] = "poppyresin", ["label"] = "Poppy resin", ["weight"] = 2000, ["type"] = "item", ["image"] = "poppyresin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "It sticks to your fingers when you handle it."}, + ["heroin"] = {["name"] = "heroin", ["label"] = "Weak Heroin Powder", ["weight"] = 500, ["type"] = "item", ["image"] = "loosecoke.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Really addictive depressant..."}, + ["bakingsoda"] = {["name"] = "bakingsoda", ["label"] = "Baking Soda", ["weight"] = 300, ["type"] = "item", ["image"] = "bakingsoda.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Household Baking Soda!"}, + ['loosecoke'] = {['name'] = 'loosecoke', ['label'] = 'loose coke', ['weight'] = 0, ['type'] = 'item', ['image'] = 'loosecoke.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Paper made specifically for encasing and smoking tobacco or cannabis.'}, + ['loosecokestagetwo'] = {['name'] = 'loosecokestagetwo', ['label'] = 'More Pure Loose Coke', ['weight'] = 100, ['type'] = 'item', ['image'] = 'loosecokestagetwo.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['loosecokestagethree'] = {['name'] = 'loosecokestagethree', ['label'] = 'Purest Loose Coke', ['weight'] = 100, ['type'] = 'item', ['image'] = 'loosecokestagethree.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['cokebaggystagetwo'] = {['name'] = 'cokebaggystagetwo', ['label'] = 'Bag of Good Coke', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cocaine_baggystagetwo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy real quick'}, + ['cokebaggystagethree'] = {['name'] = 'cokebaggystagethree', ['label'] = 'Bag of Great Coke', ['weight'] = 100, ['type'] = 'item', ['image'] = 'cocaine_baggystagethree.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy real quick'}, + ["cokestagetwo"] = {["name"] = "cokestagetwo", ["label"] = "Better Raw Cocaine", ["weight"] = 100, ["type"] = "item", ["image"] = "cokestagetwo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Processed cocaine"}, + ["cokestagethree"] = {["name"] = "cokestagethree", ["label"] = "Best Raw Cocaine", ["weight"] = 100, ["type"] = "item", ["image"] = "cokestagethree.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Processed cocaine"}, + + + ----md-lsd + ['lysergic_acid'] = {['name'] = 'lysergic_acid', ['label'] = 'Lysergic Acid', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lysergic_acid.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['diethylamide'] = {['name'] = 'diethylamide', ['label'] = 'Diethylamide', ['weight'] = 100, ['type'] = 'item', ['image'] = 'diethylamide.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_one_vial'] = {['name'] = 'lsd_one_vial', ['label'] = 'Weakest LSD Vial', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_one_vial.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_vial_two'] = {['name'] = 'lsd_vial_two', ['label'] = 'Slightly Better LSD Vial', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_vial_two.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_vial_three'] = {['name'] = 'lsd_vial_three', ['label'] = 'Good LSD', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_vial_three.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_vial_four'] = {['name'] = 'lsd_vial_four', ['label'] = 'Really Good LSD', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_vial_four.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_vial_five'] = {['name'] = 'lsd_vial_five', ['label'] = 'Amazing LSD', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_vial_five.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['lsd_vial_six'] = {['name'] = 'lsd_vial_six', ['label'] = 'Purest LSD', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lsd_vial_six.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['tab_paper'] = {['name'] = 'tab_paper', ['label'] = 'Tab Paper', ['weight'] = 100, ['type'] = 'item', ['image'] = 'tab_paper.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['smileyfacesheet'] = {['name'] = 'smileyfacesheet', ['label'] = 'Smiley Face Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smileysheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['wildcherrysheet'] = {['name'] = 'wildcherrysheet', ['label'] = 'Wild Cherry Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'wildcherrysheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['yinyangsheet'] = {['name'] = 'yinyangsheet', ['label'] = 'Yin and Yang Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'yinyangsheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['pineapplesheet'] = {['name'] = 'pineapplesheet', ['label'] = 'Pineapple Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pineapplesheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['bartsheet'] = {['name'] = 'bartsheet', ['label'] = 'Bart Simpson Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'bartsheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['gratefuldeadsheet'] = {['name'] = 'gratefuldeadsheet', ['label'] = 'Grateful Dead Sheet', ['weight'] = 100, ['type'] = 'item', ['image'] = 'gratefuldeadsheet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['smiley_tabs'] = {['name'] = 'smiley_tabs', ['label'] = 'Smiley tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'smiley_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['wildcherry_tabs'] = {['name'] = 'wildcherry_tabs', ['label'] = 'Wild Cherry Tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'wildcherry_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['yinyang_tabs'] = {['name'] = 'yinyang_tabs', ['label'] = 'Yin and Yang Tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'yinyang_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['pineapple_tabs'] = {['name'] = 'pineapple_tabs', ['label'] = 'Pineapple Tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pineapple_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['bart_tabs'] = {['name'] = 'bart_tabs', ['label'] = 'Bart Simpson Tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'bart_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['gratefuldead_tabs'] = {['name'] = 'gratefuldead_tabs', ['label'] = 'Grateful Dead Tabs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'gratefuldead_tabs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'DONT USE IF YOU GET SEIZURES'}, + ['lsdlabkit'] = {['name'] = 'lsdlabkit', ['label'] = 'LSD Mixing Table', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'labkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['dirtylsdlabkit'] = {['name'] = 'dirtylsdlabkit', ['label'] = 'Dirty LSD Mixing Table', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'labkit_dirty.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + + + ---- md heroin + ["heroinstagetwo"] = {["name"] = "heroinstagetwo", ["label"] = "Better Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinpowderstagetwo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroinstagethree"] = {["name"] = "heroinstagethree", ["label"] = "Best Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinpowderstagethree.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroincut"] = {["name"] = "heroincut", ["label"] = "Cut Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinpowder.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroincutstagetwo"] = {["name"] = "heroincutstagetwo", ["label"] = "Better Cut Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinpowderstagethree.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroincutstagethree"] = {["name"] = "heroincutstagethree", ["label"] = "Best Cut Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinpowderstagetwo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroinlabkit"] = {["name"] = "heroinlabkit", ["label"] = "Heroin Lab Kit", ["weight"] = 250, ["type"] = "item", ["image"] = "labkit.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["dirtyheroinlabkit"] = {["name"] = "dirtyheroinlabkit", ["label"] = "Dirty heroin Lab Kit", ["weight"] = 250, ["type"] = "item", ["image"] = "labkit_dirty.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroinvial"] = {["name"] = "heroinvial", ["label"] = "Vial Of Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroinvialstagetwo"] = {["name"] = "heroinvialstagetwo", ["label"] = "Better Vial of Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinstagetwo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroinvialstagethree"] = {["name"] = "heroinvialstagethree", ["label"] = "Best Vial Of Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroinstagethree.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroin_ready"] = {["name"] = "heroin_ready", ["label"] = "Syringe Of Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroin_ready.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroin_readystagetwo"] = {["name"] = "heroin_readystagetwo", ["label"] = "Syringe Of Better Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroin_readystagetwo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["heroin_readystagethree"] = {["name"] = "heroin_readystagethree", ["label"] = "Syringe Of Best Heroin", ["weight"] = 250, ["type"] = "item", ["image"] = "heroin_readystagethree.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emptyvial"] = {["name"] = "emptyvial", ["label"] = "empty vial", ["weight"] = 1, ["type"] = "item", ["image"] = "emptyvial.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ['combinable'] = nil, ["description"] = ""}, + ["needle"] = {["name"] = "needle", ["label"] = "Syringe", ["weight"] = 250, ["type"] = "item", ["image"] = "syringe.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + + ---- md crack + ["crackrock"] = {["name"] = "crackrock", ["label"] = "Crack Rock", ["weight"] = 250, ["type"] = "item", ["image"] = "crackrock1.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["crackrockstagetwo"] = {["name"] = "crackrockstagetwo", ["label"] = "Better Crack Rock", ["weight"] = 250, ["type"] = "item", ["image"] = "crackrock2.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["crackrockstagethree"] = {["name"] = "crackrockstagethree", ["label"] = "Best Crack Rock", ["weight"] = 250, ["type"] = "item", ["image"] = "crackrock3.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["baggedcracked"] = {["name"] = "baggedcracked", ["label"] = "Bag Of Crack", ["weight"] = 250, ["type"] = "item", ["image"] = "crackbag1.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["baggedcrackedstagetwo"] = {["name"] = "baggedcrackedstagetwo", ["label"] = "Better Bag Of Crack", ["weight"] = 250, ["type"] = "item", ["image"] = "crackbag2.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["baggedcrackedstagethree"] = {["name"] = "baggedcrackedstagethree", ["label"] = "Best Bag Of Crack", ["weight"] = 250, ["type"] = "item", ["image"] = "crackbag3.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ---- shrooms + ["shrooms"] = {["name"] = "shrooms", ["label"] = "Shrooms", ["weight"] = 250, ["type"] = "item", ["image"] = "shrooms.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + -- pharma + ['prescription_pad'] = {['name'] = 'prescription_pad', ['label'] = 'Prescription Pad', ['weight'] = 10, ['type'] = 'item', ['image'] = 'prescriptionpad.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = ''}, + ["vicodin_prescription"] = {["name"] = "vicodin_prescription", ["label"] = "Vicodin Prescription", ["weight"] = 250, ["type"] = "item", ["image"] = "vicodinprescription.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["adderal_prescription"] = {["name"] = "adderal_prescription", ["label"] = "Adderal Prescription", ["weight"] = 250, ["type"] = "item", ["image"] = "adderalprescription.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["morphine_prescription"] = {["name"] = "morphine_prescription", ["label"] = "Morphine Prescription", ["weight"] = 250, ["type"] = "item", ["image"] = "morphineprescription.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["xanax_prescription"] = {["name"] = "xanax_prescription", ["label"] = "Xanax Prescription", ["weight"] = 250, ["type"] = "item", ["image"] = "xanaxprescription.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ['adderal'] = {['name'] = 'adderal', ['label'] = 'Adderal', ['weight'] = 100, ['type'] = 'item', ['image'] = 'adderal.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['vicodin'] = {['name'] = 'vicodin', ['label'] = 'Vicodin', ['weight'] = 100, ['type'] = 'item', ['image'] = 'vicodin.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['morphine'] = {['name'] = 'morphine', ['label'] = 'Morphine', ['weight'] = 100, ['type'] = 'item', ['image'] = 'morphine.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['xanax'] = {['name'] = 'xanax', ['label'] = 'Xanax', ['weight'] = 100, ['type'] = 'item', ['image'] = 'xanax.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['adderalbottle'] = {['name'] = 'adderalbottle', ['label'] = 'Adderal Bottle', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pillbottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['vicodinbottle'] = {['name'] = 'vicodinbottle', ['label'] = 'Vicodin Bottle', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pillbottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['morphinebottle'] = {['name'] = 'morphinebottle', ['label'] = 'Morphine Bottle', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pillbottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + ['xanaxbottle'] = {['name'] = 'xanaxbottle', ['label'] = 'Xanax Bottle', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pillbottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ''}, + + + + + -- ATM Robbery + ['rfid_disruptor'] = {['name'] = 'rfid_disruptor', ['label'] = 'RFID Disruptor', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'rfid_disruptor.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = ' A Disruptor used for ATM transactions'}, + ['divingsuit'] = {['name'] = 'divingsuit', ['label'] = 'Diving Suit', ['weight'] = 1, ['type'] = 'item', ['image'] = 'divingsuit.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Diving suit and oxygen cylinder'}, + ['glove'] = {['name'] = 'glove', ['label'] = 'Glove', ['weight'] = 1, ['type'] = 'item', ['image'] = 'glove.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Glove'}, + ['crab'] = {['name'] = 'crab', ['label'] = 'Crab', ['weight'] = 1, ['type'] = 'item', ['image'] = 'crab.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Crab'}, + ['coral'] = {['name'] = 'coral', ['label'] = 'Coral', ['weight'] = 1, ['type'] = 'item', ['image'] = 'coral.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'coral'}, + ['lobster'] = {['name'] = 'lobster', ['label'] = 'Lobster', ['weight'] = 1, ['type'] = 'item', ['image'] = 'lobster.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'lobster'}, + ['Seashell'] = {['name'] = 'Seashell', ['label'] = 'Sea-shell', ['weight'] = 1, ['type'] = 'item', ['image'] = 'seashell.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Seashell'}, + ['sponge'] = {['name'] = 'sponge', ['label'] = 'Sponge', ['weight'] = 1, ['type'] = 'item', ['image'] = 'sponge.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sponge'}, + ['starfish'] = {['name'] = 'starfish', ['label'] = 'Starfish', ['weight'] = 1, ['type'] = 'item', ['image'] = 'starfish.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Urchin'}, + ['urchin'] = {['name'] = 'urchin', ['label'] = 'Urchin', ['weight'] = 1, ['type'] = 'item', ['image'] = 'urchin.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Urchin'}, + + ["laptop_green"] = {["name"] = "laptop_green", ["label"] = "Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "laptop_green.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop that you got from Ph03nix"}, + ["green-laptop"] = {["name"] = "green-laptop", ["label"] = "Green Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "laptop_green.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop that you got from Ph03nix"}, + + ["laptop_red"] = {["name"] = "laptop_red", ["label"] = "Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "laptop_red.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop that you got from Plague"}, + ["laptop_blue"] = {["name"] = "laptop_blue", ["label"] = "Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "laptop_blue.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop that you got from Ramsay"}, + ["laptop_gold"] = {["name"] = "laptop_gold", ["label"] = "Laptop", ["weight"] = 2500, ["type"] = "item", ["image"] = "laptop_gold.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop that you got from Trinity"}, + ["lowervaultcodes"] = {["name"] = "lowervaultcodes", ["label"] = "Access Codes", ["weight"] = 0, ["type"] = "item", ["image"] = "lowervaultcodes.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A copy of the Pacific Bank lower vault access code.."}, + ["explosive"] = {["name"] = "explosive", ["label"] = "Explosive", ["weight"] = 5000, ["type"] = "item", ["image"] = "explosive.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An improvised explosive of fireworks and thermite"}, + ["nightvision"] = {["name"] = "nightvision", ["label"] = "Night Vision Goggles", ["weight"] = 6000, ["type"] = "item", ["image"] = "nightvision.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "These allow you to see in the dark"}, + ['rgbc'] = {['name'] = 'rgbc', ['label'] = 'RGB Controller', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rgbc.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A rgb controller for use in vehicles!'}, + ['rgbkit'] = {['name'] = 'rgbkit', ['label'] = 'RGB Kit', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lightingkit.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fit a rgb lighting kit to your vehicle!'}, + ["syphoningkit"] = {["name"] = "syphoningkit", ["label"] = "Syphoning Kit", ["weight"] = 5000, ["type"] = "item", ["image"] = "syphoningkit.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A kit made to siphon gasoline from vehicles."}, + ["jerrycan"] = {["name"] = "jerrycan", ["label"] = "Jerry Can", ["weight"] = 15000, ["type"] = "item", ["image"] = "jerrycan.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Jerry Can made to hold gasoline."}, + ["alive_chicken"] = {["name"] = "alive_chicken", ["label"] = "Alive chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "alive_chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Alive Chicken"}, + ["slaughtered_chicken"] = {["name"] = "slaughtered_chicken", ["label"] = "Slaughtered chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "slaughteredchicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Slaughtered Chicken"}, + ["packagedchicken"] = {["name"] = "packagedchicken", ["label"] = "Packaged chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "packaged_chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Packaged Chicken"}, + ["petfood"] = {["name"] = "petfood", ["label"] = "Pet Food", ["weight"] = 500, ["type"] = "item", ["image"] = "petfood.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Food"}, + ["tennisball"] = {["name"] = "tennisball", ["label"] = "Tennis Ball", ["weight"] = 500, ["type"] = "item", ["image"] = "tennisball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Food"}, + ['towingrope'] = {['name'] = 'towingrope', ['label'] = 'Towing Rope', ['weight'] = 200, ['type'] = 'item', ['image'] = 'expert_towingrope.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Towing Rope'}, + ['atmobject'] = {['name'] = 'atmobject', ['label'] = 'ATM', ['weight'] = 200, ['type'] = 'item', ['image'] = 'expert_atmobj.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'ATM'}, + ['casino_usb1'] = {['name'] = 'casino_usb1', ['label'] = 'USB Device', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_usb.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A USB Device'}, + ['casino_usb2'] = {['name'] = 'casino_usb2', ['label'] = 'USB Device', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_usb.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A USB Device'}, + ['casino_magnet'] = {['name'] = 'casino_magnet', ['label'] = 'High Powered Magnet', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_magnet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A high powered magnet'}, + ['casino_accesscode1'] = {['name'] = 'casino_accesscode1', ['label'] = 'Casino Access Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Access Codes'}, + ['casino_accesscode2'] = {['name'] = 'casino_accesscode2', ['label'] = 'Casino Access Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Access Codes'}, + ['casino_keycard'] = {['name'] = 'casino_keycard', ['label'] = 'Executive Keycard', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_keycard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Grants unrestricted access..'}, + ['casino_green'] = {['name'] = 'casino_green', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_green.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Green Laptop'}, + ['casino_red'] = {['name'] = 'casino_red', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_red.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Red Laptop'}, + ['casino_blue'] = {['name'] = 'casino_blue', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_blue.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Blue Laptop'}, + ['casino_gold'] = {['name'] = 'casino_gold', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_gold.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Gold Laptop'}, + ['casino_bag'] = {['name'] = 'casino_bag', ['label'] = 'Duffel Bag', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_bag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Black Duffel Bag'}, + ['casino_vaultcode'] = {['name'] = 'casino_vaultcode', ['label'] = 'Casino Vault Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Vault Access Codes'}, + ['coca_leaves'] = {['name'] = 'coca_leaves', ['label'] = 'Feilles de Coca', ['weight'] = 50, ['type'] = 'item', ['image'] = 'cocaineleaf.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Feuilles de coca pour produire de la Cocaïne.'}, + ['cocaine_bag'] = {['name'] = 'cocaine_bag', ['label'] = 'Pochon de Cocaïne', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'cocaine_baggy.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Pochon de Cocaïne que vous pouvez vendre.'}, + ["bodycam"] = {["name"] = "bodycam", ["label"] = "Body Camera", ["weight"] = 20, ["type"] = "item", ["image"] = "bodycam.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Body Camera"}, + ["tree_lumber"] = {["name"] = "tree_lumber", ["label"] = "Lumber", ["weight"] = 50, ["type"] = "item", ["image"] = "lumber.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tree_bark"] = {["name"] = "tree_bark", ["label"] = "Tree Bark", ["weight"] = 50, ["type"] = "item", ["image"] = "treebark.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["wood_plank"] = {["name"] = "wood_plank", ["label"] = "Wood Plank", ["weight"] = 50, ["type"] = "item", ["image"] = "woodplank.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ['pickaxe'] = {['name'] = 'pickaxe', ['label'] = 'Mining Pickaxe', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_pickaxe.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Classic\'s pickaxe for mining'}, + ['uncutgem'] = {['name'] = 'uncutgem', ['label'] = 'Uncut Gem', ['weight'] = 100, ['type'] = 'item', ['image'] = 'uncutgem.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A Rough Gem'}, + ['emerald'] = {['name'] = 'emerald', ['label'] = 'Emerald', ['weight'] = 100, ['type'] = 'item', ['image'] = 'emerald.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A Emerald that shimmers'}, + ['ruby'] = {['name'] = 'ruby', ['label'] = 'Ruby', ['weight'] = 100, ['type'] = 'item', ['image'] = 'ruby.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A Ruby that shimmers'}, + ['mining_pan'] = {['name'] = 'mining_pan', ['label'] = 'Washing Pan', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_pan.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Classic\'s washing pan'}, + ['crushedstone'] = {['name'] = 'crushedstone', ['label'] = 'Crushed Stone', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'crushedstone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Left over crumbles of stone'}, + ['stone'] = {['name'] = 'stone', ['label'] = 'Mined Stone', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_stone.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mined Stone'}, + ['mining_washedstone'] = {['name'] = 'mining_washedstone', ['label'] = 'Washed Stone', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_washedstone.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Wasted Stone'}, + ['mining_ironfragment'] = {['name'] = 'mining_ironfragment', ['label'] = 'Iron Fragment', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_ironfragment.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Iron fragment from mining'}, + ['mining_ironbar'] = {['name'] = 'mining_ironbar', ['label'] = 'Iron Bar', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_ironbar.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Iron Bar'}, + ['mining_goldnugget'] = {['name'] = 'mining_goldnugget', ['label'] = 'Golden Nugget', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_goldnugget.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Golden nugget from mining'}, + ['mining_goldbar'] = {['name'] = 'mining_goldbar', ['label'] = 'Gold Bar', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_goldbar.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Gold Bar'}, + ['mining_copperfragment'] = {['name'] = 'mining_copperfragment', ['label'] = 'Copper Fragment', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_copperfragment.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Copper fragment from mining'}, + ['mining_copperbar'] = {['name'] = 'mining_copperbar', ['label'] = 'Copper Bar', ['weight'] = 500, ['type'] = 'item', ['image'] = 'mining_copperbar.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Copper Bar'}, + ['wallet'] = {['name'] = 'wallet', ['label'] = 'Wallet', ['weight'] = 0, ['type'] = 'item', ['image'] = 'wallet.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Your Wallet '}, + + + + --uwu cafe-- + ["uwubbessence"] = {["name"] = "uwubbessence", ["label"] = "BerryBlue Essence", ["weight"] = 200, ["type"] = "item", ["image"] = "uwubbessence.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Essence from the Blueberry Gods."}, + ["uwuroseessence"] = {["name"] = "uwuroseessence", ["label"] = "Rose Essence", ["weight"] = 200, ["type"] = "item", ["image"] = "uwuroseessence.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Essence from the Rose Gods."}, + ["uwumintessence"] = {["name"] = "uwumintessence", ["label"] = "Mint Essence", ["weight"] = 200, ["type"] = "item", ["image"] = "uwumintessence.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Essence from the Mint Gods."}, + ["uwububbleteablueberry"] = {["name"] = "uwububbleteablueberry", ["label"] = "Berry Blue B-T", ["weight"] = 200, ["type"] = "item", ["image"] = "uwububbleteablueberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Lavender Tea with Blueberry Boba."}, + ["uwububbletearose"] = {["name"] = "uwububbletearose", ["label"] = "Rosey B-T", ["weight"] = 200, ["type"] = "item", ["image"] = "uwububbletearose.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sakura Rose Tea with Vanilla Boba."}, + ["uwububbleteamint"] = {["name"] = "uwububbleteamint", ["label"] = "Minty B-T", ["weight"] = 200, ["type"] = "item", ["image"] = "uwububbleteamint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Matcha Tea with Mint Boba."}, + ["uwupancake"] = {["name"] = "uwupancake", ["label"] = "uWu Pancake", ["weight"] = 200, ["type"] = "item", ["image"] = "uwupancake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Korean savory pancake made with scallions."}, + ["uwucupcake"] = {["name"] = "uwucupcake", ["label"] = "uWu Cupcake", ["weight"] = 200, ["type"] = "item", ["image"] = "uwucupcake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sugar Kitty Cupcake!"}, + ["uwuvanillasandy"] = {["name"] = "uwuvanillasandy", ["label"] = "uWu V-Icecream Sandy", ["weight"] = 200, ["type"] = "item", ["image"] = "uwuvanillasandy.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sweet Vanilla Biscuit filled with Icecreamy!"}, + ["uwuchocsandy"] = {["name"] = "uwuchocsandy", ["label"] = "uWu C-Icecream Sandy", ["weight"] = 200, ["type"] = "item", ["image"] = "uwuchocsandy.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sweet Chocolate Biscuit filled with Icecreamy!"}, + ["uwubudhabowl"] = {["name"] = "uwubudhabowl", ["label"] = "uWu Budha Bowl", ["weight"] = 200, ["type"] = "item", ["image"] = "uwubudhabowl.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bowl of nourishment and balance."}, + ["uwusushi"] = {["name"] = "uwusushi", ["label"] = "uWu Sushi", ["weight"] = 200, ["type"] = "item", ["image"] = "uwusushi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Designed as a window to your soul."}, + ["uwumisosoup"] = {["name"] = "uwumisosoup", ["label"] = "uWu Miso Soup", ["weight"] = 200, ["type"] = "item", ["image"] = "uwumisosoup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Fungus never tasted so good!"}, + ["vanillabean"] = {["name"] = "vanillabean", ["label"] = "Vanilla Bean", ["weight"] = 200, ["type"] = "item", ["image"] = "vanillabean.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Vanilla Bean - cooking ingredient"}, + ["egg"] = {["name"] = "egg", ["label"] = "Chicken Egg", ["weight"] = 200, ["type"] = "item", ["image"] = "egg.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Egg - cooking ingredient"}, + ["flour"] = {["name"] = "flour", ["label"] = "Flour", ["weight"] = 200, ["type"] = "item", ["image"] = "flour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Flour - cooking ingredient"}, + ["misopaste"] = {["name"] = "misopaste", ["label"] = "Miso Paste", ["weight"] = 200, ["type"] = "item", ["image"] = "misopaste.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Miso Paste - cooking ingredient"}, + ["tapiokaballs"] = {["name"] = "tapiokaballs", ["label"] = "Tapioka Balls", ["weight"] = 200, ["type"] = "item", ["image"] = "tapiokaballs.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Tapioka Balls ingredient for Bubble Tea!"}, + ["tea"] = {["name"] = "tea", ["label"] = "Tempting Tea", ["weight"] = 200, ["type"] = "item", ["image"] = "tea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Its not just tea..."}, + ["tofu"] = {["name"] = "tofu", ["label"] = "Firm Tofu", ["weight"] = 200, ["type"] = "item", ["image"] = "tofu.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Tofu. Save a Cow and chow on Tofu!"}, + ["nori"] = {["name"] = "nori", ["label"] = "Nori Sheets", ["weight"] = 200, ["type"] = "item", ["image"] = "nori.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Gift from the Ocean, goes well with Rice"}, + ["rawsugar"] = {["name"] = "rawsugar", ["label"] = "Raw Sugar", ["weight"] = 200, ["type"] = "item", ["image"] = "rawsugar.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Raw Sugar - cooking ingredient"}, + ["rice"] = {["name"] = "rice", ["label"] = "Rice", ["weight"] = 200, ["type"] = "item", ["image"] = "rice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Rice - cooking ingredient"}, + ["tuna"] = {["name"] = "tuna", ["label"] = "Blue Fin Tuna", ["weight"] = 300, ["type"] = "item", ["image"] = "tuna.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Blue Fin Tuna - cooking ingredient"}, + ["umami"] = {["name"] = "umami", ["label"] = "Umami Beans", ["weight"] = 300, ["type"] = "item", ["image"] = "umami.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Healthy and Delicious"}, + ["mixedlettuce"] = {["name"] = "mixedlettuce", ["label"] = "Mixed Lettuce", ["weight"] = 250, ["type"] = "item", ["image"] = "mixedlettuce.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Crispy assortment of mixed lettuce"}, + ["mango"] = {["name"] = "mango", ["label"] = "Mango", ["weight"] = 300, ["type"] = "item", ["image"] = "mango.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Mango"}, + ["avocado"] = {["name"] = "avocado", ["label"] = "Avocado", ["weight"] = 300, ["type"] = "item", ["image"] = "avocado.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Avocado"}, + ["chocolate"] = {["name"] = "chocolate", ["label"] = "Chocolate", ["weight"] = 200, ["type"] = "item", ["image"] = "chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chocolate - cooking ingredient"}, + ["uwu_toy1"] = {["name"] = "uwu_toy1", ["label"] = "uWu Blitz", ["weight"] = 50, ["type"] = "item", ["image"] = "uwu_toy1.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Blitz "}, + ["uwu_toy2"] = {["name"] = "uwu_toy2", ["label"] = "uWu Scratzes", ["weight"] = 50, ["type"] = "item", ["image"] = "uwu_toy2.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Scratzes "}, + ["uwu_toy3"] = {["name"] = "uwu_toy3", ["label"] = "uWu Citruz", ["weight"] = 50, ["type"] = "item", ["image"] = "uwu_toy3.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Citruz "}, + ["uwu_toy4"] = {["name"] = "uwu_toy4", ["label"] = "uWu Zoxy", ["weight"] = 50, ["type"] = "item", ["image"] = "uwu_toy4.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Zoxy "}, + ["uwubentobox"] = {["name"] = "uwubentobox", ["label"] = "^=◕ᴥ◕=^ Bento Box", ["weight"] = 225, ["type"] = "item", ["image"] = "uwubentobox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A ◕ᴥ◕ Selection with a surprise!"}, + + -- Burger Shot + -- Food + ["burger-bleeder"] = {["name"] = "burger-bleeder", ["label"] = "Bleeder", ["weight"] = 250, ["type"] = "item", ["image"] = "bs_the-bleeder.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + ["burger-moneyshot"] = {["name"] = "burger-moneyshot", ["label"] = "Moneyshot", ["weight"] = 300, ["type"] = "item", ["image"] = "bs_money-shot.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + ["burger-torpedo"] = {["name"] = "burger-torpedo", ["label"] = "Torpedo", ["weight"] = 310, ["type"] = "item", ["image"] = "bs_torpedo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + ["burger-heartstopper"] = {["name"] = "burger-heartstopper", ["label"] = "Heartstopper", ["weight"] = 2500, ["type"] = "item", ["image"] = "bs_the-heart-stopper.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + ["burger-meatfree"] = {["name"] = "burger-meatfree", ["label"] = "MeatFree", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_meat-free.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + ["burger-fries"] = {["name"] = "burger-fries", ["label"] = "Fries", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_fries.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sates Hunger."}, + -- Drinks + ["burger-softdrink"] = {["name"] = "burger-softdrink", ["label"] = "Soft Drink", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_softdrink.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ice Cold Drink."}, + ["burger-mshake"] = {["name"] = "burger-mshake", ["label"] = "Milkshake", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_milkshake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Hand-scooped for you!"}, + + --Ingredients + ["burger-bun"] = {["name"] = "burger-bun", ["label"] = "Bun", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_bun.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-meat"] = {["name"] = "burger-meat", ["label"] = "Cooked Patty", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_patty.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-lettuce"] = {["name"] = "burger-lettuce", ["label"] = "Lettuce", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-tomato"] = {["name"] = "burger-tomato", ["label"] = "Tomato", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_tomato.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-raw"] = {["name"] = "burger-raw", ["label"] = "Raw Patty", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_patty_raw.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-potato"] = {["name"] = "burger-potato", ["label"] = "Bag of Potatoes", ["weight"] = 1500, ["type"] = "item", ["image"] = "bs_potato.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-mshakeformula"] = {["name"] = "burger-mshakeformula", ["label"] = "Milkshake Formula", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_ingredients_icecream.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + ["burger-sodasyrup"] = {["name"] = "burger-sodasyrup", ["label"] = "Soda Syrup", ["weight"] = 125, ["type"] = "item", ["image"] = "bs_ingredients_hfcs.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Ingredient"}, + + + + + -- Farming + ["apple"] = {["name"] = "apple", ["label"] = "Apple", ["weight"] = 25, ["type"] = "item", ["image"] = "apple.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["apple_juice"] = {["name"] = "apple_juice", ["label"] = "Apple Juice", ["weight"] = 100, ["type"] = "item", ["image"] = "apple_juice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["emptycowbucket"] = {["name"] = "emptycowbucket", ["label"] = "Empty Bucket", ["weight"] = 25, ["type"] = "item", ["image"] = "emptybucket.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["milkbucket"] = {["name"] = "milkbucket", ["label"] = "Milk Bucket", ["weight"] = 75, ["type"] = "item", ["image"] = "milkbucket.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["raw_beef"] = {["name"] = "raw_beef", ["label"] = "Raw Beef", ["weight"] = 25, ["type"] = "item", ["image"] = "raw_beef.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["beef"] = {["name"] = "beef", ["label"] = "Beef", ["weight"] = 25, ["type"] = "item", ["image"] = "beef.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["milk"] = {["name"] = "milk", ["label"] = "Milk", ["weight"] = 50, ["type"] = "item", ["image"] = "milk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["rawpumpkin"] = {["name"] = "rawpumpkin", ["label"] = "Raw Pumpkin", ["weight"] = 50, ["type"] = "item", ["image"] = "raw_pumpkin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["pumpkinpiebox"] = {["name"] = "pumpkinpiebox", ["label"] = "Box of Pie", ["weight"] = 25, ["type"] = "item", ["image"] = "pumpkinpiebox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = {accept = {'weapon_knife'}, reward = 'slicedpie', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = '', ['timeOut'] = 7500, }}, ["description"] = ""}, + ["slicedpie"] = {["name"] = "slicedpie", ["label"] = "Slice of Pie", ["weight"] = 10, ["type"] = "item", ["image"] = "slicedpie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["corncob"] = {["name"] = "corncob", ["label"] = "Corn Cob", ["weight"] = 15, ["type"] = "item", ["image"] = "corncob.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["canofcorn"] = {["name"] = "canofcorn", ["label"] = "Can Of Corn", ["weight"] = 15, ["type"] = "item", ["image"] = "canofcorn.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["grapes"] = {["name"] = "grapes", ["label"] = "Grapes", ["weight"] = 15, ["type"] = "item", ["image"] = "grapes.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + -- ["grapejuice"] = {["name"] = "grapejuice", ["label"] = "Grape Juice", ["weight"] = 15, ["type"] = "item", ["image"] = "grapejuice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["greenpepper"] = {["name"] = "greenpepper", ["label"] = "Green Pepper", ["weight"] = 15, ["type"] = "item", ["image"] = "greenpepper.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["chillypepper"] = {["name"] = "chillypepper", ["label"] = "Chilly Pepper", ["weight"] = 15, ["type"] = "item", ["image"] = "chillypepper.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["hotsauce"] = {["name"] = "hotsauce", ["label"] = "Hot Sauce", ["weight"] = 15, ["type"] = "item", ["image"] = "hotsauce.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tomato"] = {["name"] = "tomato", ["label"] = "tomato", ["weight"] = 15, ["type"] = "item", ["image"] = "tomato.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tomatopaste"] = {["name"] = "tomatopaste", ["label"] = "tomato Paste", ["weight"] = 25, ["type"] = "item", ["image"] = "tomatopaste.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["soybeans"] = {["name"] = "soybeans", ["label"] = "Soy Beans", ["weight"] = 10, ["type"] = "item", ["image"] = "soybeans.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["raw_bacon"] = {["name"] = "raw_bacon", ["label"] = "Raw Bacon", ["weight"] = 25, ["type"] = "item", ["image"] = "raw_bacon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["raw_sausage"] = {["name"] = "raw_sausage", ["label"] = "Raw Sausage", ["weight"] = 25, ["type"] = "item", ["image"] = "raw_sausage.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["raw_pork"] = {["name"] = "raw_pork", ["label"] = "Raw Pork", ["weight"] = 25, ["type"] = "item", ["image"] = "raw_pork.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["raw_ham"] = {["name"] = "raw_ham", ["label"] = "Raw Ham", ["weight"] = 25, ["type"] = "item", ["image"] = "raw_ham.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cooked_bacon"] = {["name"] = "cooked_bacon", ["label"] = "Cooked Bacon", ["weight"] = 25, ["type"] = "item", ["image"] = "cooked_bacon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cooked_sausage"] = {["name"] = "cooked_sausage", ["label"] = "Cooked Sausage", ["weight"] = 25, ["type"] = "item", ["image"] = "cooked_sausage.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cooked_pork"] = {["name"] = "cooked_pork", ["label"] = "Cooked Pork", ["weight"] = 25, ["type"] = "item", ["image"] = "cooked_pork.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cooked_ham"] = {["name"] = "cooked_ham", ["label"] = "Cooked Ham", ["weight"] = 25, ["type"] = "item", ["image"] = "cooked_ham.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["pig_leather"] = {["name"] = "pig_leather", ["label"] = "Pig Skin", ["weight"] = 50, ["type"] = "item", ["image"] = "pig_leather.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cow_leather"] = {["name"] = "cow_leather", ["label"] = "Cow Skin", ["weight"] = 50, ["type"] = "item", ["image"] = "cow_leather.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + + + -- Ammo ITEMS + ['pistol_ammo'] = {['name'] = 'pistol_ammo', ['label'] = 'Pistol ammo', ['weight'] = 400, ['type'] = 'item', ['image'] = 'np_pistol-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Pistols', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['rifle_ammo'] = {['name'] = 'rifle_ammo', ['label'] = 'Rifle ammo', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'np_rifle-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Rifles', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['smg_ammo'] = {['name'] = 'smg_ammo', ['label'] = 'SMG ammo', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'np_sub-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Sub Machine Guns', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['shotgun_ammo'] = {['name'] = 'shotgun_ammo', ['label'] = 'Shotgun ammo', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'np_shotgun-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Shotguns', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['mg_ammo'] = {['name'] = 'mg_ammo', ['label'] = 'MG ammo', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_lmg-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Machine Guns', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['snp_ammo'] = {['name'] = 'snp_ammo', ['label'] = 'Sniper ammo', ['weight'] = 3500, ['type'] = 'item', ['image'] = 'np_sniper-ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for Sniper Rifles', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['emp_ammo'] = {['name'] = 'emp_ammo', ['label'] = 'EMP Ammo', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'np_emp_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for EMP Launcher', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Addon Ammo Items AMMO_STAFF + ['paintball-ammo'] = {['name'] = 'paintball-ammo', ['label'] = 'Paintballs', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_paintball_ammo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ammo for a Paintball Gun', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["taserammo"] = {["name"] = "taserammo", ["label"] = "Taser Cartridges", ["weight"] = 500, ["type"] = "item", ["image"] = "taserammo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Government (PD/EMS/DOC) Issued Equipment", ['created'] = nil, ["decay"] = 0.0}, + ["rpg_ammo"] = {["name"] = "rpg_ammo", ["label"] = "Rocket", ["weight"] = 5000, ["type"] = "item", ["image"] = "np_rpgammo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "RPG Rocket - be careful", ['created'] = nil, ["decay"] = 0.0}, + ["firework_ammo"] = {["name"] = "rpg_ammo", ["label"] = "Firework Rocket", ["weight"] = 5000, ["type"] = "item", ["image"] = "np_rpgammo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Firework Rocket - be careful", ['created'] = nil, ["decay"] = 0.0}, + ["mana"] = {["name"] = "mana", ["label"] = "Mana", ["weight"] = 100, ["type"] = "item", ["image"] = "np_spellblue.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Mana Regen for a Staff", ['created'] = nil, ["decay"] = 0.0}, + + -- Card ITEMS + ['policecard'] = {['name'] = 'policecard', ['label'] = 'Police Badge', ['weight'] = 100, ['type'] = 'item', ['image'] = 'np_pd_badge.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A card containing all your information to identify yourself', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ['id_card'] = {['name'] = 'id_card', ['label'] = 'ID Card', ['weight'] = 100, ['type'] = 'item', ['image'] = 'id_card.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A card containing all your information to identify yourself', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['driver_license'] = {['name'] = 'driver_license', ['label'] = 'Drivers License', ['weight'] = 100, ['type'] = 'item', ['image'] = 'driver_license.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Permit to show you can drive a vehicle', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['lawyerpass'] = {['name'] = 'lawyerpass', ['label'] = 'Lawyer Pass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'lawyerpass.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Pass exclusive to lawyers to show they can represent a suspect', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weaponlicense'] = {['name'] = 'weaponlicense', ['label'] = 'Weapon License', ['weight'] = 100, ['type'] = 'item', ['image'] = 'weapon_license.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Weapon License', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["hlicence"] = {["name"] = "hlicence", ["label"] = "Hunting License", ["weight"] = 100, ["type"] = "item", ["image"] = "huntinglicense.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Permit to show officals that you can legally hunt.", ['created'] = nil, ["decay"] = 0.0}, + ['visa'] = {['name'] = 'visa', ['label'] = 'Visa Card', ['weight'] = 100, ['type'] = 'item', ['image'] = 'visacard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Visa can be used via ATM', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['mastercard'] = {['name'] = 'mastercard', ['label'] = 'Master Card', ['weight'] = 100, ['type'] = 'item', ['image'] = 'mastercard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'MasterCard can be used via ATM', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['security_card_01'] = {['name'] = 'security_card_01', ['label'] = 'Security Card A', ['weight'] = 100, ['type'] = 'item', ['image'] = 'security_card_01.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A security card... I wonder what it goes to', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['security_card_02'] = {['name'] = 'security_card_02', ['label'] = 'Security Card B', ['weight'] = 100, ['type'] = 'item', ['image'] = 'security_card_02.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A security card... I wonder what it goes to', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Eat ITEMS + ['tosti'] = {['name'] = 'tosti', ['label'] = 'Grilled Cheese Sandwich', ['weight'] = 200, ['type'] = 'item', ['image'] = 'tosti.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['twerks_candy'] = {['name'] = 'twerks_candy', ['label'] = 'Twerks', ['weight'] = 100, ['type'] = 'item', ['image'] = 'twerks_candy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some delicious candy :O', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['snikkel_candy'] = {['name'] = 'snikkel_candy', ['label'] = 'Snikkel', ['weight'] = 100, ['type'] = 'item', ['image'] = 'snikkel_candy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some delicious candy :O', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['sandwich'] = {['name'] = 'sandwich', ['label'] = 'Sandwich', ['weight'] = 200, ['type'] = 'item', ['image'] = 'sandwich.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice bread for your stomach', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Drink ITEMS + ['water_bottle'] = {['name'] = 'water_bottle', ['label'] = 'Bottle of Water', ['weight'] = 500, ['type'] = 'item', ['image'] = 'water_bottle.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['coffee'] = {['name'] = 'coffee', ['label'] = 'Coffee', ['weight'] = 200, ['type'] = 'item', ['image'] = 'coffee.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pump 4 Caffeine', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['kurkakola'] = {['name'] = 'kurkakola', ['label'] = 'Cola', ['weight'] = 500, ['type'] = 'item', ['image'] = 'cola.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Alcohol + ['beer'] = {['name'] = 'beer', ['label'] = 'Beer', ['weight'] = 500, ['type'] = 'item', ['image'] = 'beer.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nothing like a good cold beer!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['whiskey'] = {['name'] = 'whiskey', ['label'] = 'Whiskey', ['weight'] = 500, ['type'] = 'item', ['image'] = 'whiskey.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['vodka'] = {['name'] = 'vodka', ['label'] = 'Vodka', ['weight'] = 500, ['type'] = 'item', ['image'] = 'vodka.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For all the thirsty out there', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['grape'] = {['name'] = 'grape', ['label'] = 'Grape', ['weight'] = 100, ['type'] = 'item', ['image'] = 'grape.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Mmmmh yummie, grapes', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['wine'] = {['name'] = 'wine', ['label'] = 'Wine', ['weight'] = 300, ['type'] = 'item', ['image'] = 'wine.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Some good wine to drink on a fine evening', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- ['grapejuice'] = {['name'] = 'grapejuice', ['label'] = 'Grape Juice', ['weight'] = 200, ['type'] = 'item', ['image'] = 'grapejuice.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Grape juice is said to be healthy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Drugs + ['joint'] = {['name'] = 'joint', ['label'] = 'Joint', ['weight'] = 500, ['type'] = 'item', ['image'] = 'joint.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sidney would be very proud at you', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cokebaggy'] = {['name'] = 'cokebaggy', ['label'] = 'Bag of Coke', ['weight'] = 500, ['type'] = 'item', ['image'] = 'cocaine_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy real quick', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['crack_baggy'] = {['name'] = 'crack_baggy', ['label'] = 'Bag of Crack', ['weight'] = 500, ['type'] = 'item', ['image'] = 'crack_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To get happy faster', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['xtcbaggy'] = {['name'] = 'xtcbaggy', ['label'] = 'Bag of XTC', ['weight'] = 500, ['type'] = 'item', ['image'] = 'xtc_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pop those pills baby', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_brick'] = {['name'] = 'weed_brick', ['label'] = 'Weed Brick', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'weed_brick.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '1KG Weed Brick to sell to large customers.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['coke_brick'] = {['name'] = 'coke_brick', ['label'] = 'Coke Brick', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'coke_brick.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Heavy package of cocaine, mostly used for deals and takes a lot of space', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['oxy'] = {['name'] = 'oxy', ['label'] = 'Prescription Oxy', ['weight'] = 500, ['type'] = 'item', ['image'] = 'oxy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The Label Has Been Ripped Off', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['rolling_paper'] = {['name'] = 'rolling_paper', ['label'] = 'Rolling Paper', ['weight'] = 200, ['type'] = 'item', ['image'] = 'rolling_paper.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = {accept = {'weed_white-widow', 'weed_skunk', 'weed_purple-haze', 'weed_og-kush', 'weed_amnesia', 'weed_ak47', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, reward = 'joint', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Rolling joint', ['timeOut'] = 5000, }, ['created'] = nil, ["decay"] = 0.0}, ['description'] = 'Paper made specifically for encasing and smoking tobacco or cannabis.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Drug Processing + ["wet_weed"] = {["name"] = "wet_weed", ["label"] = "Moist Weed", ["weight"] = 3000, ["type"] = "item", ["image"] = "wet_weed.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Wet weed that needs to be treated!", ['created'] = nil, ["decay"] = 0.0}, + ["coca_leaf"] = {["name"] = "coca_leaf", ["label"] = "Cocaine leaves", ["weight"] = 1500, ["type"] = "item", ["image"] = "coca_leaf.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Cocaine leaves that must be processed !", ['created'] = nil, ["decay"] = 0.0}, + ["cannabis"] = {["name"] = "cannabis", ["label"] = "Cannabis", ["weight"] = 2500, ["type"] = "item", ["image"] = "cannabis.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Uncured cannabis", ['created'] = nil, ["decay"] = 0.0}, + ["marijuana"] = {["name"] = "marijuana", ["label"] = "Marijuana", ["weight"] = 500, ["type"] = "item", ["image"] = "marijuana.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Some fine smelling buds.", ['created'] = nil, ["decay"] = 0.0}, + ["chemicals"] = {["name"] = "chemicals", ["label"] = "Chemicals", ["weight"] = 1500, ["type"] = "item", ["image"] = "chemicals.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care...", ['created'] = nil, ["decay"] = 0.0}, + ["poppyresin"] = {["name"] = "poppyresin", ["label"] = "Poppy resin", ["weight"] = 2000, ["type"] = "item", ["image"] = "poppyresin.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "It sticks to your fingers when you handle it.", ['created'] = nil, ["decay"] = 0.0}, + ["heroin"] = {["name"] = "heroin", ["label"] = "Heroin", ["weight"] = 500, ["type"] = "item", ["image"] = "heroin.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Really addictive depressant...", ['created'] = nil, ["decay"] = 0.0}, + ["lsa"] = {["name"] = "lsa", ["label"] = "LSA", ["weight"] = 500, ["type"] = "item", ["image"] = "lsa.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Almost ready to party...", ['created'] = nil, ["decay"] = 0.0}, + ["lsd"] = {["name"] = "lsd", ["label"] = "LSD", ["weight"] = 500, ["type"] = "item", ["image"] = "lsd.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Lets get this party started!", ['created'] = nil, ["decay"] = 0.0}, + ["hydrochloric_acid"] = {["name"] = "hydrochloric_acid", ["label"] = "Hydrochloric Acid", ["weight"] = 1500, ["type"] = "item", ["image"] = "hydrochloric_acid.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care!", ['created'] = nil, ["decay"] = 0.0}, + ["sodium_hydroxide"] = {["name"] = "sodium_hydroxide", ["label"] = "Sodium Hydroxide", ["weight"] = 1500, ["type"] = "item", ["image"] = "sodium_hydroxide.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care!", ['created'] = nil, ["decay"] = 0.0}, + ["sulfuric_acid"] = {["name"] = "sulfuric_acid", ["label"] = "Sulfuric Acid", ["weight"] = 1500, ["type"] = "item", ["image"] = "sulfuric_acid.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care!", ['created'] = nil, ["decay"] = 0.0}, + ["thionyl_chloride"] = {["name"] = "thionyl_chloride", ["label"] = "Thionyl Chloride", ["weight"] = 1500, ["type"] = "item", ["image"] = "thionyl_chloride.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care!", ['created'] = nil, ["decay"] = 0.0}, + ["liquidmix"] = {["name"] = "liquidmix", ["label"] = "Liquid Chem Mix", ["weight"] = 1500, ["type"] = "item", ["image"] = "liquidmix.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Chemicals, handle with care!", ['created'] = nil, ["decay"] = 0.0}, + ["bakingsoda"] = {["name"] = "bakingsoda", ["label"] = "Baking Soda", ["weight"] = 1500, ["type"] = "item", ["image"] = "bakingsoda.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Household Baking Soda!", ['created'] = nil, ["decay"] = 0.0}, + ["chemicalvapor"] = {["name"] = "chemicalvapor", ["label"] = "Chemical Vapors", ["weight"] = 1500, ["type"] = "item", ["image"] = "chemicalvapor.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "High Pressure Chemical Vapors, Explosive!", ['created'] = nil, ["decay"] = 0.0}, + ["trimming_scissors"] = {["name"] = "trimming_scissors", ["label"] = "Trimming Scissors", ["weight"] = 1500, ["type"] = "item", ["image"] = "trimming_scissors.png", ['created'] = nil, ["decay"] = 0.0, ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["expire"] = 90, ["description"] = "Very Sharp Trimming Scissors", ['created'] = nil, ["decay"] = 0.0}, + ['methkey'] = {['name'] = 'methkey', ['label'] = 'Key A', ['weight'] = 200, ['type'] = 'item', ['image'] = 'keya.png', ['created'] = nil, ["decay"] = 0.0, ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Random Key, with "Walter" Engraved on the Back...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cocainekey'] = {['name'] = 'cocainekey', ['label'] = 'Key B', ['weight'] = 200, ['type'] = 'item', ['image'] = 'keyb.png', ['created'] = nil, ["decay"] = 0.0, ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Random Key, with a "Razorblade" Engraved on the Back...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weedkey'] = {['name'] = 'weedkey', ['label'] = 'Key C', ['weight'] = 200, ['type'] = 'item', ['image'] = 'keyc.png', ['created'] = nil, ["decay"] = 0.0, ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Random Key, with a "Seed" Engraved on the Back...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['finescale'] = {['name'] = 'finescale', ['label'] = 'Fine Scale', ['weight'] = 200, ['type'] = 'item', ['image'] = 'finescale.png', ['created'] = nil, ["decay"] = 0.0, ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Scale Used for Fine Powders and Materials.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['coke_small_brick'] = {['name'] = 'coke_small_brick', ['label'] = 'Coke Package', ['weight'] = 350, ['type'] = 'item', ['image'] = 'coke_small_brick.png', ['created'] = nil, ["decay"] = 0.0, ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Small package of cocaine, mostly used for deals and takes a lot of space', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Seed And Weed + ['weed_white-widow'] = {['name'] = 'weed_white-widow', ['label'] = 'White Widow 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g White Widow', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_skunk'] = {['name'] = 'weed_skunk', ['label'] = 'Skunk 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Skunk', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_purple-haze'] = {['name'] = 'weed_purple-haze', ['label'] = 'Purple Haze 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Purple Haze', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_og-kush'] = {['name'] = 'weed_og-kush', ['label'] = 'OGKush 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g OG Kush', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_amnesia'] = {['name'] = 'weed_amnesia', ['label'] = 'Amnesia 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g Amnesia', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_ak47'] = {['name'] = 'weed_ak47', ['label'] = 'AK47 2g', ['weight'] = 200, ['type'] = 'item', ['image'] = 'weed_baggy.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed bag with 2g AK47', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_white-widow_seed'] = {['name'] = 'weed_white-widow_seed', ['label'] = 'White Widow Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A weed seed of White Widow', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_skunk_seed'] = {['name'] = 'weed_skunk_seed', ['label'] = 'Skunk Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Skunk', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_purple-haze_seed'] = {['name'] = 'weed_purple-haze_seed', ['label'] = 'Purple Haze Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Purple Haze', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_og-kush_seed'] = {['name'] = 'weed_og-kush_seed', ['label'] = 'OGKush Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of OG Kush', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_amnesia_seed'] = {['name'] = 'weed_amnesia_seed', ['label'] = 'Amnesia Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of Amnesia', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_ak47_seed'] = {['name'] = 'weed_ak47_seed', ['label'] = 'AK47 Seed', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_seed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weed seed of AK47', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['empty_weed_bag'] = {['name'] = 'empty_weed_bag', ['label'] = 'Empty Bag', ['weight'] = 10, ['type'] = 'item', ['image'] = 'weed_baggy_empty.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A small empty bag', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['weed_nutrition'] = {['name'] = 'weed_nutrition', ['label'] = 'Plant Fertilizer', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'weed_nutrition.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Plant nutrition', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Material + ['plastic'] = {['name'] = 'plastic', ['label'] = 'Plastic', ['weight'] = 100, ['type'] = 'item', ['image'] = 'plastic.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'RECYCLE! - Greta Thunberg 2019', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['metalscrap'] = {['name'] = 'metalscrap', ['label'] = 'Metal Scrap', ['weight'] = 100, ['type'] = 'item', ['image'] = 'metalscrap.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'You can probably make something nice out of this', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['copper'] = {['name'] = 'copper', ['label'] = 'Copper', ['weight'] = 100, ['type'] = 'item', ['image'] = 'copper.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['aluminum'] = {['name'] = 'aluminum', ['label'] = 'Aluminium', ['weight'] = 100, ['type'] = 'item', ['image'] = 'aluminum.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['aluminumoxide'] = {['name'] = 'aluminumoxide', ['label'] = 'Aluminium Powder', ['weight'] = 100, ['type'] = 'item', ['image'] = 'aluminumoxide.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Some powder to mix with', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['iron'] = {['name'] = 'iron', ['label'] = 'Iron', ['weight'] = 100, ['type'] = 'item', ['image'] = 'iron.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Handy piece of metal that you can probably use for something', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['ironoxide'] = {['name'] = 'ironoxide', ['label'] = 'Iron Powder', ['weight'] = 100, ['type'] = 'item', ['image'] = 'ironoxide.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = {accept = {'aluminumoxide', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, reward = 'thermite', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Mixing powder..', ['timeOut'] = 10000}, ['created'] = nil, ["decay"] = 0.0}, ['description'] = 'Some powder to mix with.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['steel'] = {['name'] = 'steel', ['label'] = 'Steel', ['weight'] = 100, ['type'] = 'item', ['image'] = 'steel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Nice piece of metal that you can probably use for something', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['rubber'] = {['name'] = 'rubber', ['label'] = 'Rubber', ['weight'] = 100, ['type'] = 'item', ['image'] = 'rubber.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Rubber, I believe you can make your own rubber ducky with it :D', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['glass'] = {['name'] = 'glass', ['label'] = 'Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'glass.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'It is very fragile, watch out', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Tools + ['lockpick'] = {['name'] = 'lockpick', ['label'] = 'Lockpick', ['weight'] = 300, ['type'] = 'item', ['image'] = 'lockpick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = {accept = {'screwdriverset', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, reward = 'advancedlockpick', anim = {['dict'] = 'anim@amb@business@weed@weed_inspecting_high_dry@', ['lib'] = 'weed_inspecting_high_base_inspector', ['text'] = 'Crafting lockpick', ['timeOut'] = 7500, }, ['created'] = nil, ["decay"] = 0.0}, ['description'] = 'Very useful if you lose your keys a lot.. or if you want to use it for something else...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['advancedlockpick'] = {['name'] = 'advancedlockpick', ['label'] = 'Advanced Lockpick', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_advanced-lockpick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'If you lose your keys a lot this is very useful... Also useful to open your beers', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['security_system_device'] = {['name'] = 'security_system_device', ['label'] = 'Security Hacking Device', ['weight'] = 100, ['type'] = 'item', ['image'] = 'security_device.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'This device look sus', ["created"] = nil, ["decay"] = 0}, + ['electronickit'] = {['name'] = 'electronickit', ['label'] = 'Electronic Kit', ['weight'] = 100, ['type'] = 'item', ['image'] = 'electronickit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = {accept = {'gatecrack', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, reward = 'trojan_usb', anim = nil, ['created'] = nil, ["decay"] = 0.0}, ['description'] = 'If you\'ve always wanted to build a robot you can maybe start here. Maybe you\'ll be the new Elon Musk?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['gatecrack'] = {['name'] = 'gatecrack', ['label'] = 'Gatecrack', ['weight'] = 500, ['type'] = 'item', ['image'] = 'usb_device.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Handy software to tear down some fences', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['thermite'] = {['name'] = 'thermite', ['label'] = 'Thermite', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'thermite.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sometimes you\'d wish for everything to burn', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['trojan_usb'] = {['name'] = 'trojan_usb', ['label'] = 'Trojan USB', ['weight'] = 500, ['type'] = 'item', ['image'] = 'usb_device.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Handy software to shut down some systems', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['screwdriverset'] = {['name'] = 'screwdriverset', ['label'] = 'Toolkit', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'screwdriverset.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Very useful to screw... screws...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['drill'] = {['name'] = 'drill', ['label'] = 'Drill', ['weight'] = 15000, ['type'] = 'item', ['image'] = 'drill.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'The real deal...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["toolbox"] = {["name"] = "toolbox", ["label"] = "Toolbox", ["weight"] = 1000, ["type"] = "item", ["image"] = "toolbox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Needed for Performance part removal", ['created'] = nil, ["decay"] = 0.0}, + + -- Vehicle Tools + ['nitrous'] = {['name'] = 'nitrous', ['label'] = 'Nitrous', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'nitrous.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Gas Gas GAAAAAS!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['emptynitrous'] = {['name'] = 'emptynitrous', ['label'] = 'Empty Bottle', ['weight'] = 100, ['type'] = 'item', ['image'] = 'emptynitrous.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Slow Slow SLOOOOW!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["redusb"] = {["name"] = "redusb", ["label"] = "Red USB", ['weight'] = 100, ["type"] = "item", ["image"] = "redusb.png", ["unique"] = true, ["useable"] = false, ['shouldClose'] = false, ["combinable"] = nil, ["description"] = "A USB marked for police seizure", ['created'] = nil, ["decay"] = 0.0}, + ["racingusb"] = {["name"] = "racingusb", ["label"] = "Racing USB", ['weight'] = 100, ["type"] = "item", ["image"] = "racingusb.png", ["unique"] = true, ["useable"] = false, ['shouldClose'] = false, ["combinable"] = nil, ["description"] = "A USB marked for police seizure", ['created'] = nil, ["decay"] = 0.0}, + ["racingcreator"] = {["name"] = "racingcreator", ["label"] = "Racing Creator", ['weight'] = 100, ["type"] = "item", ["image"] = "racingcreator.png", ["unique"] = true, ["useable"] = false, ['shouldClose'] = false, ["combinable"] = nil, ["description"] = "A USB marked for police seizure", ['created'] = nil, ["decay"] = 0.0}, + ['repairkit'] = {['name'] = 'repairkit', ['label'] = 'Repairkit', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'repairkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice toolbox with stuff to repair your vehicle', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['advancedrepairkit'] = {['name'] = 'advancedrepairkit', ['label'] = 'Advanced Repairkit', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'advancedkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice toolbox with stuff to repair your vehicle', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cleaningkit'] = {['name'] = 'cleaningkit', ['label'] = 'Cleaning Kit', ['weight'] = 250, ['type'] = 'item', ['image'] = 'cleaningkit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A microfiber cloth with some soap will let your car sparkle again!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['tunerlaptop'] = {['name'] = 'tunerlaptop', ['label'] = 'Tuner Chip', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'np_tuner.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With this tunerchip you can get your car on steroids... If you know what you\'re doing', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['harness'] = {['name'] = 'harness', ['label'] = 'Race Harness', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'harness.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Racing Harness so no matter what you stay in the car', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['jerry_can'] = {['name'] = 'jerry_can', ['label'] = 'Jerrycan 20L', ['weight'] = 15000, ['type'] = 'item', ['image'] = 'jerry_can.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A can full of Fuel', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['dragy'] = {['name'] = 'dragy', ['label'] = 'Dragy', ['weight'] = 10, ['type'] = 'item', ['image'] = 'dragy.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'How fast are U ?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Medication + ['firstaid'] = {['name'] = 'firstaid', ['label'] = 'First Aid', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'firstaid.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You can use this First Aid kit to get people back on their feet', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bandage'] = {['name'] = 'bandage', ['label'] = 'Bandage', ['weight'] = 500, ['type'] = 'item', ['image'] = 'bandage.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bandage works every time', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['ifaks'] = {['name'] = 'ifaks', ['label'] = 'ifaks', ['weight'] = 200, ['type'] = 'item', ['image'] = 'ifak.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'ifaks for healing and a complete stress remover.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['painkillers'] = {['name'] = 'painkillers', ['label'] = 'Painkillers', ['weight'] = 250, ['type'] = 'item', ['image'] = 'painkillers.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'For pain you can\'t stand anymore, take this pill that\'d make you feel great again', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['walkstick'] = {['name'] = 'walkstick', ['label'] = 'Walking Stick', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'walkstick.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Walking stick for ya\'ll grannies out there.. HAHA', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['medicalbag'] = {['name'] = 'medicalbag', ['label'] = 'Medical Bag', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'np_medbag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its a prop, wow?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Communication + ['phone'] = {['name'] = 'phone', ['label'] = 'Phone', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'black_phone.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Neat phone ya got there', ['created'] = nil, ['decay'] = 28}, + ['radio'] = {['name'] = 'radio', ['label'] = 'Radio', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'np_radio.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You can communicate with this through a signal', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['iphone'] = {['name'] = 'iphone', ['label'] = 'iPhone', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'iphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Very expensive phone', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['samsungphone'] = {['name'] = 'samsungphone', ['label'] = 'Samsung S10', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'samsungphone.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Very expensive phone', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['laptop'] = {['name'] = 'laptop', ['label'] = 'Pixel Laptop', ['weight'] = 3000, ['type'] = 'item', ['image'] = 'pixellaptop.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Laptop used for many things', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ['tablet'] = {['name'] = 'tablet', ['label'] = 'Tablet', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'tablet.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Expensive tablet', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['mdt'] = {['name'] = 'mdt', ['label'] = 'MDT', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'mdt.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Expensive mdt', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['encryptedtablet'] = {['name'] = 'encryptedtablet', ['label'] = 'Encrypted Tablet', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'tablet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Expensive tablet', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ['fitbit'] = {['name'] = 'fitbit', ['label'] = 'Fitbit', ['weight'] = 500, ['type'] = 'item', ['image'] = 'fitbit.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I like fitbit', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['watch_black'] = {['name'] = 'watch_black', ['label'] = 'Apple Watch Black', ['weight'] = 500, ['type'] = 'item', ['image'] = 'watch_black.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I like Apple', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['watch_white'] = {['name'] = 'watch_white', ['label'] = 'Apple Watch White', ['weight'] = 500, ['type'] = 'item', ['image'] = 'watch_white.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'I like Apple', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ['radioscanner'] = {['name'] = 'radioscanner', ['label'] = 'Radio Scanner', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'radioscanner.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With this you can get some police alerts. Not 100% effective however', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['pinger'] = {['name'] = 'pinger', ['label'] = 'Pinger', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'pinger.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'With a pinger and your phone you can send out your location', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cryptostick'] = {['name'] = 'cryptostick', ['label'] = 'Crypto Stick', ['weight'] = 200, ['type'] = 'item', ['image'] = 'cryptostick.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Why would someone ever buy money that doesn\'t exist.. How many would it contain..?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Theft and Jewelry + ['rolex'] = {['name'] = 'rolex', ['label'] = 'Golden Watch', ['weight'] = 500, ['type'] = 'item', ['image'] = 'rolex.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A golden watch seems like the jackpot to me!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['diamond_ring'] = {['name'] = 'diamond_ring', ['label'] = 'Diamond Ring', ['weight'] = 500, ['type'] = 'item', ['image'] = 'diamond_ring.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A diamond ring seems like the jackpot to me!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['goldchain'] = {['name'] = 'goldchain', ['label'] = 'Golden Chain', ['weight'] = 500, ['type'] = 'item', ['image'] = 'goldchain.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A golden chain seems like the jackpot to me!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['10kgoldchain'] = {['name'] = '10kgoldchain', ['label'] = '10k Gold Chain', ['weight'] = 500, ['type'] = 'item', ['image'] = '10kgoldchain.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '10 carat golden chain', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['goldbar'] = {['name'] = 'goldbar', ['label'] = 'Gold Bar', ['weight'] = 100, ['type'] = 'item', ['image'] = 'goldbar.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Looks pretty expensive to me', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Cops Tools + ['armor'] = {['name'] = 'armor', ['label'] = 'Armor', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'armor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some protection won\'t hurt... right?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['heavyarmor'] = {['name'] = 'heavyarmor', ['label'] = 'Heavy Armor', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'armor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Some protection won\'t hurt... right?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['handcuffs'] = {['name'] = 'handcuffs', ['label'] = 'Handcuffs', ['weight'] = 100, ['type'] = 'item', ['image'] = 'handcuffs.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Comes in handy when people misbehave. Maybe it can be used for something else?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["handcuffkey"] = {["name"] = "handcuffkey", ["label"] = "Handcuff Key", ["weight"] = 100, ["type"] = "item", ["image"] = "np_mobilecratekey.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Good for getting a person out of cuffs", ['created'] = nil, ["decay"] = 0.0}, + ['police_stormram'] = {['name'] = 'police_stormram', ['label'] = 'Stormram', ['weight'] = 18000, ['type'] = 'item', ['image'] = 'police_stormram.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice tool to break into doors', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['empty_evidence_bag'] = {['name'] = 'empty_evidence_bag', ['label'] = 'Empty Evidence Bag', ['weight'] = 100, ['type'] = 'item', ['image'] = 'evidence.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Used a lot to keep DNA from blood, bullet shells and more', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['filled_evidence_bag'] = {['name'] = 'filled_evidence_bag', ['label'] = 'Evidence Bag', ['weight'] = 200, ['type'] = 'item', ['image'] = 'evidence.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A filled evidence bag to see who committed the crime >:(', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Firework Tools + ['firework1'] = {['name'] = 'firework1', ['label'] = '2Brothers', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'firework1.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['firework2'] = {['name'] = 'firework2', ['label'] = 'Poppelers', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'firework2.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['firework3'] = {['name'] = 'firework3', ['label'] = 'WipeOut', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'firework3.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['firework4'] = {['name'] = 'firework4', ['label'] = 'Weeping Willow', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'firework4.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fireworks', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Sea Tools + ['dendrogyra_coral'] = {['name'] = 'dendrogyra_coral', ['label'] = 'Dendrogyra', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'dendrogyra_coral.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its also known as pillar coral', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['antipatharia_coral'] = {['name'] = 'antipatharia_coral', ['label'] = 'Antipatharia', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'antipatharia_coral.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its also known as black corals or thorn corals', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['diving_gear'] = {['name'] = 'diving_gear', ['label'] = 'Diving Gear', ['weight'] = 20000, ['type'] = 'item', ['image'] = 'diving_gear.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'An oxygen tank and a rebreather', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + -- CASINO STUFF + ["casino_greenchip"] = {["name"] = "casino_greenchip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_green-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_redchip"] = {["name"] = "casino_redchip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_red-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Inside Track Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_whitechip"] = {["name"] = "casino_whitechip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_white-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Slot Machine Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_bluechip"] = {["name"] = "casino_bluechip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_blue-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Roulette Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_blackchip"] = {["name"] = "casino_blackchip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_black-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Blackjack Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_goldchip"] = {["name"] = "casino_goldchip", ["label"] = "Casino Chip", ["weight"] = 1, ["type"] = "item", ["image"] = "np_gold-chip.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Golden Chip", ['created'] = nil, ["decay"] = 0.0}, + ["casino_member"] = {["name"] = "casino_member", ["label"] = "Casino Membership", ["weight"] = 500, ["type"] = "item", ["image"] = "np_casino_member.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Member Card", ['created'] = nil, ["decay"] = 0.0}, + ["casino_vip"] = {["name"] = "casino_vip", ["label"] = "V.I.P Membership", ["weight"] = 500, ["type"] = "item", ["image"] = "np_casino_high_roller.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino V.I.P Card", ['created'] = nil, ["decay"] = 0.0}, + ["casino_panther"] = {["name"] = "casino_panther", ["label"] = "Panther", ["weight"] = 15000, ["type"] = "item", ["image"] = "np_casino_panther.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Someones personal panther... you are getting into trouble...", ['created'] = nil, ["decay"] = 0.0}, + ["casino_soap"] = {["name"] = "casino_soap", ["label"] = "Soap", ["weight"] = 1000, ["type"] = "item", ["image"] = "np_casino_soap.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino branded soap.. this should get you squeaky clean.", ['created'] = nil, ["decay"] = 0.0}, + ["casino_goldcoin"] = {["name"] = "casino_goldcoin", ["label"] = "Gold Coin", ["weight"] = 100, ["type"] = "item", ["image"] = "np_casinogoldcoin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Diamond Casino Gold Coin.. could be worth something.. or not.", ['created'] = nil, ["decay"] = 0.0}, + + + -- Other Tools + ['casinochips'] = {['name'] = 'casinochips', ['label'] = 'Casino Chips', ['weight'] = 1, ['type'] = 'item', ['image'] = 'np_green-chip.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Lucky Wheel Chip.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['stickynote'] = {['name'] = 'stickynote', ['label'] = 'Sticky note', ['weight'] = 10, ['type'] = 'item', ['image'] = 'stickynote.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Sometimes handy to remember something :)', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['moneybag'] = {['name'] = 'moneybag', ['label'] = 'Money Bag', ['weight'] = 10, ['type'] = 'item', ['image'] = 'moneybag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A bag with cash', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['parachute'] = {['name'] = 'parachute', ['label'] = 'Parachute', ['weight'] = 8000, ['type'] = 'item', ['image'] = 'parachute.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The sky is the limit! Woohoo!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['binoculars'] = {['name'] = 'binoculars', ['label'] = 'Binoculars', ['weight'] = 600, ['type'] = 'item', ['image'] = 'binoculars.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sneaky Breaky...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['snowball'] = {['name'] = 'snowball', ['label'] = 'Snowball', ['weight'] = 10, ['type'] = 'item', ['image'] = 'snowball.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Should have catched it :D', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['lighter'] = {['name'] = 'lighter', ['label'] = 'Lighter', ['weight'] = 10, ['type'] = 'item', ['image'] = 'lighter.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'On new years eve a nice fire to stand next to', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['certificate'] = {['name'] = 'certificate', ['label'] = 'Certificate', ['weight'] = 10, ['type'] = 'item', ['image'] = 'certificate.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Certificate that proves you own business', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['markedbills'] = {['name'] = 'markedbills', ['label'] = 'Marked Money', ['weight'] = 10, ['type'] = 'item', ['image'] = 'markedbills.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Money?', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['printerdocument'] = {['name'] = 'printerdocument', ['label'] = 'Document', ['weight'] = 500, ['type'] = 'item', ['image'] = 'printerdocument.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A nice document', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- CUSTOM SHIT BELOW -- + -- BOOSTING + ["boostinglaptop"] = {["name"] = "boostinglaptop", ["label"] = "Boosting Laptop", ["weight"] = 1000, ["type"] = "item", ["image"] = "boostinglaptop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A laptop used for boosting contracts.", ['created'] = nil, ["decay"] = 0.0}, + ["boostingdisabler"] = {["name"] = "boostingdisabler", ["label"] = "Tracking Disabler", ["weight"] = 1000, ["type"] = "item", ["image"] = "boostingdisabler.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "This small tool can disable these pesky trackers.", ['created'] = nil, ["decay"] = 0.0}, + --casino heist + ['casino_usb1'] = {['name'] = 'casino_usb1', ['label'] = 'USB Device', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_usb.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A USB Device', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_usb2'] = {['name'] = 'casino_usb2', ['label'] = 'USB Device', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_usb.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A USB Device', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_magnet'] = {['name'] = 'casino_magnet', ['label'] = 'High Powered Magnet', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_magnet.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A high powered magnet', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_accesscode1'] = {['name'] = 'casino_accesscode1', ['label'] = 'Casino Access Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Access Codes', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_accesscode2'] = {['name'] = 'casino_accesscode2', ['label'] = 'Casino Access Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Access Codes', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_keycard'] = {['name'] = 'casino_keycard', ['label'] = 'Executive Keycard', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_keycard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Grants unrestricted access..', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_green'] = {['name'] = 'casino_green', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_green.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Green Laptop', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_red'] = {['name'] = 'casino_red', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_red.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Red Laptop', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_blue'] = {['name'] = 'casino_blue', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_blue.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Blue Laptop', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_gold'] = {['name'] = 'casino_gold', ['label'] = 'Laptop', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'casino_gold.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Gold Laptop', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_bag'] = {['name'] = 'casino_bag', ['label'] = 'Duffel Bag', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_bag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A Black Duffel Bag', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_vaultcode'] = {['name'] = 'casino_vaultcode', ['label'] = 'Casino Vault Codes', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_accesscode.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Vault Access Codes', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --casiuno shit + ['krugerrand'] = {['name'] = 'krugerrand', ['label'] = 'Krugerrand', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'krugerrand.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A coin made from gold.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_soap'] = {['name'] = 'casino_soap', ['label'] = 'Soap', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'casino_soap.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Diamond Casino Hotel branded soap', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_towel'] = {['name'] = 'casino_towel', ['label'] = 'Towel', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'casino_towel.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Diamond Casino Hotel branded towels', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_shampoo'] = {['name'] = 'casino_shampoo', ['label'] = 'Shampoo', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'casino_shampoo.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Diamond Casino Hotel branded shampoo', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_showergel'] = {['name'] = 'casino_showergel', ['label'] = 'Showergel', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'casino_showergel.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Diamond Casino Hotel branded showergel', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['casino_membercard'] = {['name'] = 'casino_membercard', ['label'] = 'Membercard', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'casino_membercard.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Diamond Casino Membership Card', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + -- VOTING + ['np_voted_sticker'] = {['name'] = 'np_voted_sticker', ['label'] = 'Voting Sticker', ['weight'] = 10, ['type'] = 'item', ['image'] = 'np_voted_sticker.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'You have voted!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Magic + ['bookofmagic'] = {['name'] = 'bookofmagic', ['label'] = 'Book of Magic', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_spellblue.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['lightningbolt'] = {['name'] = 'lightningbolt', ['label'] = 'Lightning Bolt', ['weight'] = 500, ['type'] = 'item', ['image'] = 'lightningbolt.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bottleofforce'] = {['name'] = 'bottleofforce', ['label'] = 'Bottle of Force', ['weight'] = 500, ['type'] = 'item', ['image'] = 'bottleofforce.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['begonepotion'] = {['name'] = 'begonepotion', ['label'] = 'Be Gone Potion', ['weight'] = 500, ['type'] = 'item', ['image'] = 'begonepotion.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['healingstones'] = {['name'] = 'healingstones', ['label'] = 'Healing Stones', ['weight'] = 500, ['type'] = 'item', ['image'] = 'healingstones.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bookofdimensions'] = {['name'] = 'bookofdimensions', ['label'] = 'Booking of Dimensions', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_spellnormal.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bookofbadmagic'] = {['name'] = 'bookofbadmagic', ['label'] = 'Book of Bad Magic', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_spellred.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bookofcurses'] = {['name'] = 'bookofcurses', ['label'] = 'Book of Curses', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_spellnormal.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['potionofchanges'] = {['name'] = 'potionofchanges', ['label'] = 'Potion of Changes', ['weight'] = 500, ['type'] = 'item', ['image'] = 'potionofchanges.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['gravitygone'] = {['name'] = 'gravitygone', ['label'] = 'Gravity Gone', ['weight'] = 500, ['type'] = 'item', ['image'] = 'gravitygone.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['phasepotion'] = {['name'] = 'phasepotion', ['label'] = 'Phase Potion', ['weight'] = 500, ['type'] = 'item', ['image'] = 'phasepotion.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bookofwind'] = {['name'] = 'bookofwind', ['label'] = 'Book of Wind', ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_spellnormal.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Magic Item', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- METH TABLE + ["methtable"] = {["name"] = "methtable", ["label"] = "Meth Table", ["weight"] = 2000, ["type"] = "item", ["image"] = "methtable.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A Table", ['created'] = nil, ["decay"] = 0.0}, + ["methbag"] = {["name"] = "methbag", ["label"] = "Meth Bag", ["weight"] = 1000, ["type"] = "item", ["image"] = "meth10g.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Meth Bag", ['created'] = nil, ["decay"] = 0.0}, + + ['grapplegun'] = {['name'] = 'grapplegun', ['label'] = 'Grapple Gun', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'np_grapple.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Become Batman', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- WEARABLE MASKS / BANDANAS + ["bloodsbandana"] = {["name"] = "bloodsbandana", ["label"] = "Bloods Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "bloodsbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bloods Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["greenbandana"] = {["name"] = "greenbandana", ["label"] = "GSF Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "greenbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "GSF Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["ballasbandana"] = {["name"] = "ballasbandana", ["label"] = "Ballas Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "ballasbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ballas Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["vagosbandana"] = {["name"] = "vagosbandana", ["label"] = "Vagos Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "vagosbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Vagos Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["cripsbandana"] = {["name"] = "cripsbandana", ["label"] = "Crip Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "cripsbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Crips Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["whitebandana"] = {["name"] = "whitebandana", ["label"] = "White Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "whitebandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "White Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["blackbandana"] = {["name"] = "blackbandana", ["label"] = "Black Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "blackbandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Black Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + ["orangebandana"] = {["name"] = "orangebandana", ["label"] = "Orange Bandana", ["weight"] = 1000, ["type"] = "item", ["image"] = "orangebandana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Orange Gang Bandana", ['created'] = nil, ["decay"] = 0.0}, + + -- -- JIMS MECHANIC + ["mechanic_tools"] = {["name"] = "mechanic_tools", ["label"] = "Mechanic tools", ["weight"] = 0, ["type"] = "item", ["image"] = "mechanic_tools.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Needed for vehicle repairs", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["toolbox"] = {["name"] = "toolbox", ["label"] = "Toolbox", ["weight"] = 0, ["type"] = "item", ["image"] = "toolbox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Needed for Performance part removal", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ducttape"] = {["name"] = "ducttape", ["label"] = "Duct Tape", ["weight"] = 0, ["type"] = "item", ["image"] = "bodyrepair.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Good for quick fixes", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["mechboard"] = {["name"] = "mechboard", ["label"] = "Mechanic Sheet", ["weight"] = 0, ["type"] = "item", ["image"] = "mechboard.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Performance + ["turbo"] = {["name"] = "turbo", ["label"] = "Supercharger Turbo", ["weight"] = 0, ["type"] = "item", ["image"] = "turbo.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Who doesn't need a 65mm Turbo??", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["car_armor"] = {["name"] = "car_armor", ["label"] = "Vehicle Armor", ["weight"] = 0, ["type"] = "item", ["image"] = "armour.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["nos"] = {["name"] = "nos", ["label"] = "NOS Bottle", ["weight"] = 0, ["type"] = "item", ["image"] = "nos.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "A full bottle of NOS", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["noscan"] = {["name"] = "noscan", ["label"] = "Empty NOS Bottle", ["weight"] = 0, ["type"] = "item", ["image"] = "noscan.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["description"] = "An Empty bottle of NOS", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["noscolour"] = {["name"] = "noscolour", ["label"] = "NOS Colour Injector", ["weight"] = 0, ["type"] = "item", ["image"] = "noscolour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Make that purge spray", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["engine1"] = {["name"] = "engine1", ["label"] = "Tier 1 Engine", ["weight"] = 0, ["type"] = "item", ["image"] = "engine1.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["engine2"] = {["name"] = "engine2", ["label"] = "Tier 2 Engine", ["weight"] = 0, ["type"] = "item", ["image"] = "engine2.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["engine3"] = {["name"] = "engine3", ["label"] = "Tier 3 Engine", ["weight"] = 0, ["type"] = "item", ["image"] = "engine3.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["engine4"] = {["name"] = "engine4", ["label"] = "Tier 4 Engine", ["weight"] = 0, ["type"] = "item", ["image"] = "engine4.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["engine5"] = {["name"] = "engine5", ["label"] = "Tier 5 Engine", ["weight"] = 0, ["type"] = "item", ["image"] = "engine5.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["transmission1"] = {["name"] = "transmission1", ["label"] = "Tier 1 Transmission", ["weight"] = 0, ["type"] = "item", ["image"] = "transmission1.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = ""}, + ["transmission2"] = {["name"] = "transmission2", ["label"] = "Tier 2 Transmission", ["weight"] = 0, ["type"] = "item", ["image"] = "transmission2.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["transmission3"] = {["name"] = "transmission3", ["label"] = "Tier 3 Transmission", ["weight"] = 0, ["type"] = "item", ["image"] = "transmission3.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["transmission4"] = {["name"] = "transmission4", ["label"] = "Tier 4 Transmission", ["weight"] = 0, ["type"] = "item", ["image"] = "transmission4.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["brakes1"] = {["name"] = "brakes1", ["label"] = "Tier 1 Brakes", ["weight"] = 0, ["type"] = "item", ["image"] = "brakes1.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["brakes2"] = {["name"] = "brakes2", ["label"] = "Tier 2 Brakes", ["weight"] = 0, ["type"] = "item", ["image"] = "brakes2.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["brakes3"] = {["name"] = "brakes3", ["label"] = "Tier 3 Brakes", ["weight"] = 0, ["type"] = "item", ["image"] = "brakes3.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["suspension1"] = {["name"] = "suspension1", ["label"] = "Tier 1 Suspension", ["weight"] = 0, ["type"] = "item", ["image"] = "suspension1.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["suspension2"] = {["name"] = "suspension2", ["label"] = "Tier 2 Suspension", ["weight"] = 0, ["type"] = "item", ["image"] = "suspension2.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["suspension3"] = {["name"] = "suspension3", ["label"] = "Tier 3 Suspension", ["weight"] = 0, ["type"] = "item", ["image"] = "suspension3.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["suspension4"] = {["name"] = "suspension4", ["label"] = "Tier 4 Suspension", ["weight"] = 0, ["type"] = "item", ["image"] = "suspension4.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["suspension5"] = {["name"] = "suspension5", ["label"] = "Tier 5 Suspension", ["weight"] = 0, ["type"] = "item", ["image"] = "suspension5.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["bprooftires"] = {["name"] = "bprooftires", ["label"] = "Bulletproof Tires", ["weight"] = 0, ["type"] = "item", ["image"] = "bprooftires.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["drifttires"] = {["name"] = "drifttires", ["label"] = "Drift Tires", ["weight"] = 0, ["type"] = "item", ["image"] = "drifttires.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Cosmetics + ["underglow_controller"] = {["name"] = "underglow_controller", ["label"] = "Neon Controller", ["weight"] = 0, ["type"] = "item", ["image"] = "underglow_controller.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["description"] = "RGB LED Vehicle Remote", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["headlights"] = {["name"] = "headlights", ["label"] = "Xenon Headlights", ["weight"] = 0, ["type"] = "item", ["image"] = "headlights.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "8k HID headlights", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["tint_supplies"] = {["name"] = "tint_supplies", ["label"] = "Tint Supplies", ["weight"] = 0, ["type"] = "item", ["image"] = "tint_supplies.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["description"] = "Supplies for window tinting", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["customplate"] = {["name"] = "customplate", ["label"] = "Customized Plates", ["weight"] = 0, ["type"] = "item", ["image"] = "plate.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["hood"] = {["name"] = "hood", ["label"] = "Vehicle Hood", ["weight"] = 0, ["type"] = "item", ["image"] = "hood.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["roof"] = {["name"] = "roof", ["label"] = "Vehicle Roof", ["weight"] = 0, ["type"] = "item", ["image"] = "roof.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["spoiler"] = {["name"] = "spoiler", ["label"] = "Vehicle Spoiler", ["weight"] = 0, ["type"] = "item", ["image"] = "spoiler.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bumper"] = {["name"] = "bumper", ["label"] = "Vehicle Bumper", ["weight"] = 0, ["type"] = "item", ["image"] = "bumper.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["skirts"] = {["name"] = "skirts", ["label"] = "Vehicle Skirts", ["weight"] = 0, ["type"] = "item", ["image"] = "skirts.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["exhaust"] = {["name"] = "exhaust", ["label"] = "Vehicle Exhaust", ["weight"] = 0, ["type"] = "item", ["image"] = "exhaust.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["seat"] = {["name"] = "seat", ["label"] = "Seat Cosmetics", ["weight"] = 0, ["type"] = "item", ["image"] = "seat.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rollcage"] = {["name"] = "rollcage", ["label"] = "Roll Cage", ["weight"] = 0, ["type"] = "item", ["image"] = "rollcage.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["rims"] = {["name"] = "rims", ["label"] = "Custom Wheel Rims", ["weight"] = 0, ["type"] = "item", ["image"] = "rims.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["livery"] = {["name"] = "livery", ["label"] = "Livery Roll", ["weight"] = 0, ["type"] = "item", ["image"] = "livery.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["paintcan"] = {["name"] = "paintcan", ["label"] = "Vehicle Spray Can", ["weight"] = 0, ["type"] = "item", ["image"] = "spraycan.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["tires"] = {["name"] = "tires", ["label"] = "Drift Smoke Tires", ["weight"] = 0, ["type"] = "item", ["image"] = "tires.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["horn"] = {["name"] = "horn", ["label"] = "Custom Vehicle Horn", ["weight"] = 0, ["type"] = "item", ["image"] = "horn.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["internals"] = {["name"] = "internals", ["label"] = "Internal Cosmetics", ["weight"] = 0, ["type"] = "item", ["image"] = "internals.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["externals"] = {["name"] = "externals", ["label"] = "Exterior Cosmetics", ["weight"] = 0, ["type"] = "item", ["image"] = "mirror.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Repair Parts + ["newoil"] = {["name"] = "newoil", ["label"] = "Car Oil", ["weight"] = 0, ["type"] = "item", ["image"] = "caroil.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sparkplugs"] = {["name"] = "sparkplugs", ["label"] = "Spark Plugs", ["weight"] = 0, ["type"] = "item", ["image"] = "sparkplugs.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["carbattery"] = {["name"] = "carbattery", ["label"] = "Car Battery", ["weight"] = 0, ["type"] = "item", ["image"] = "carbattery.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["axleparts"] = {["name"] = "axleparts", ["label"] = "Axle Parts", ["weight"] = 0, ["type"] = "item", ["image"] = "axleparts.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sparetire"] = {["name"] = "sparetire", ["label"] = "Spare Tire", ["weight"] = 0, ["type"] = "item", ["image"] = "sparetire.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["description"] = "", ["created"] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- RANDOM SCRAP ITEMS RECYCLE CENTER + ["gascan"] = {["name"] = "gascan", ["label"] = "Gas Canister", ["weight"] = 500, ["type"] = "item", ["image"] = "gascan.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A useful gas canister that you can use for something", ['created'] = nil, ["decay"] = 0.0}, + ["cloth"] = {["name"] = "cloth", ["label"] = "Cloth", ["weight"] = 100, ["type"] = "item", ["image"] = "clothe.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A piece of cloth that you can probably use for something", ['created'] = nil, ["decay"] = 0.0}, + + -- POKEMON + ["boosterbox"] = {["name"] = "boosterbox", ["label"] = "Boosterbox", ["weight"] = 200, ["type"] = "item", ["image"] = "boosterBox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Box Of Card Packs", ['created'] = nil, ["decay"] = 0.0}, + ["boosterpack"] = {["name"] = "boosterpack", ["label"] = "Boosterpack", ["weight"] = 0, ["type"] = "item", ["image"] = "boosterPack.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pack of Cards", ['created'] = nil, ["decay"] = 0.0}, + ["abra"] = {["name"] = "abra", ["label"] = "Abra", ["weight"] = 0, ["type"] = "item", ["image"] = "abra.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Marsh Badge", ['created'] = nil, ["decay"] = 0.0}, + ["aerodactyl"] = {["name"] = "aerodactyl", ["label"] = "Aerodactyl", ["weight"] = 0, ["type"] = "item", ["image"] = "aerodactyl.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["alakazam"] = {["name"] = "alakazam", ["label"] = "Alakazam", ["weight"] = 0, ["type"] = "item", ["image"] = "alakazam.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Marsh Badge", ['created'] = nil, ["decay"] = 0.0}, + ["arbok"] = {["name"] = "arbok", ["label"] = "Arbok", ["weight"] = 0, ["type"] = "item", ["image"] = "arbok.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["arcanine"] = {["name"] = "arcanine", ["label"] = "Arcanine", ["weight"] = 0, ["type"] = "item", ["image"] = "arcanine.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Volcano Badge", ['created'] = nil, ["decay"] = 0.0}, + ["articuno"] = {["name"] = "articuno", ["label"] = "Articuno", ["weight"] = 0, ["type"] = "item", ["image"] = "articuno.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["beedrill"] = {["name"] = "beedrill", ["label"] = "Beedrill", ["weight"] = 0, ["type"] = "item", ["image"] = "beedrill.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["bellsprout"] = {["name"] = "bellsprout", ["label"] = "Bellsprout", ["weight"] = 0, ["type"] = "item", ["image"] = "bellsprout.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Rainbow Badge", ['created'] = nil, ["decay"] = 0.0}, + ["blastoise"] = {["name"] = "blastoise", ["label"] = "Blastoise", ["weight"] = 0, ["type"] = "item", ["image"] = "blastoise.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Cascade Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["boulderbadge"] = {["name"] = "boulderbadge", ["label"] = "boulderbadge", ["weight"] = 0, ["type"] = "item", ["image"] = "boulderBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["butterfree"] = {["name"] = "butterfree", ["label"] = "Butterfree", ["weight"] = 0, ["type"] = "item", ["image"] = "butterfree.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["cascadebadge"] = {["name"] = "cascadeBadge", ["label"] = "CascadeBadge", ["weight"] = 0, ["type"] = "item", ["image"] = "cascadeBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["caterpie"] = {["name"] = "caterpie", ["label"] = "Caterpie", ["weight"] = 0, ["type"] = "item", ["image"] = "caterpie.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["chansey"] = {["name"] = "chansey", ["label"] = "Chansey", ["weight"] = 0, ["type"] = "item", ["image"] = "chansey.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["charizard"] = {["name"] = "charizard", ["label"] = "Charizard", ["weight"] = 0, ["type"] = "item", ["image"] = "charizard.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Volcano Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["charmander"] = {["name"] = "charmander", ["label"] = "Charmander", ["weight"] = 0, ["type"] = "item", ["image"] = "charmander.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["charmeleon"] = {["name"] = "charmeleon", ["label"] = "Charmeleon", ["weight"] = 0, ["type"] = "item", ["image"] = "charmeleon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["clefable"] = {["name"] = "clefable", ["label"] = "Clefable", ["weight"] = 0, ["type"] = "item", ["image"] = "clefable.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["clefairy"] = {["name"] = "clefairy", ["label"] = "Clefairy", ["weight"] = 0, ["type"] = "item", ["image"] = "clefairy.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["cloyster"] = {["name"] = "cloyster", ["label"] = "Cloyster", ["weight"] = 0, ["type"] = "item", ["image"] = "cloyster.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["cubone"] = {["name"] = "cubone", ["label"] = "Cubone", ["weight"] = 0, ["type"] = "item", ["image"] = "cubone.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["dewgong"] = {["name"] = "dewgong", ["label"] = "Dewgong", ["weight"] = 0, ["type"] = "item", ["image"] = "dewgong.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["diglett"] = {["name"] = "diglett", ["label"] = "Diglett", ["weight"] = 0, ["type"] = "item", ["image"] = "diglett.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["ditto"] = {["name"] = "ditto", ["label"] = "Ditto", ["weight"] = 0, ["type"] = "item", ["image"] = "ditto.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["dodrio"] = {["name"] = "dodrio", ["label"] = "Dodrio", ["weight"] = 0, ["type"] = "item", ["image"] = "dodrio.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["doduo"] = {["name"] = "doduo", ["label"] = "Doduo", ["weight"] = 0, ["type"] = "item", ["image"] = "doduo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["dragonair"] = {["name"] = "dragonair", ["label"] = "Dragonair", ["weight"] = 0, ["type"] = "item", ["image"] = "dragonair.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["dragonite"] = {["name"] = "dragonite", ["label"] = "Dragonite", ["weight"] = 0, ["type"] = "item", ["image"] = "dragonite.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["dratini"] = {["name"] = "dratini", ["label"] = "Dratini", ["weight"] = 0, ["type"] = "item", ["image"] = "dratini.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["drowzee"] = {["name"] = "drowzee", ["label"] = "Drowzee", ["weight"] = 0, ["type"] = "item", ["image"] = "drowzee.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["dugtrio"] = {["name"] = "dugtrio", ["label"] = "Dugtrio", ["weight"] = 0, ["type"] = "item", ["image"] = "dugtrio.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Earth Badge", ['created'] = nil, ["decay"] = 0.0}, + ["earthbadge"] = {["name"] = "earthbadge", ["label"] = "Earth Badge", ["weight"] = 0, ["type"] = "item", ["image"] = "earthBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "8/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["eevee"] = {["name"] = "eevee", ["label"] = "Eevee", ["weight"] = 0, ["type"] = "item", ["image"] = "eevee.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["ekans"] = {["name"] = "ekans", ["label"] = "Ekans", ["weight"] = 0, ["type"] = "item", ["image"] = "ekans.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["electabuzz"] = {["name"] = "electabuzz", ["label"] = "Electabuzz", ["weight"] = 0, ["type"] = "item", ["image"] = "electabuzz.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Thunder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["electrode"] = {["name"] = "electrode", ["label"] = "Electrode", ["weight"] = 0, ["type"] = "item", ["image"] = "electrode.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Thunder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["exeggcute"] = {["name"] = "exeggcute", ["label"] = "Exeggcute", ["weight"] = 0, ["type"] = "item", ["image"] = "exeggcute.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["exeggutor"] = {["name"] = "exeggutor", ["label"] = "Exeggutor", ["weight"] = 0, ["type"] = "item", ["image"] = "exeggutor.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["farfetchd"] = {["name"] = "farfetchd", ["label"] = "Farfetchd", ["weight"] = 0, ["type"] = "item", ["image"] = "farfetchd.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["fearow"] = {["name"] = "fearow", ["label"] = "Fearow", ["weight"] = 0, ["type"] = "item", ["image"] = "fearow.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["flareon"] = {["name"] = "flareon", ["label"] = "Flareon", ["weight"] = 0, ["type"] = "item", ["image"] = "flareon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["gastly"] = {["name"] = "gastly", ["label"] = "Gastly", ["weight"] = 0, ["type"] = "item", ["image"] = "gastly.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["gengar"] = {["name"] = "gengar", ["label"] = "Gengar", ["weight"] = 0, ["type"] = "item", ["image"] = "gengar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["geodude"] = {["name"] = "geodude", ["label"] = "Geodude", ["weight"] = 0, ["type"] = "item", ["image"] = "geodude.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Boulder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["gloom"] = {["name"] = "gloom", ["label"] = "Gloom", ["weight"] = 0, ["type"] = "item", ["image"] = "gloom.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["golbat"] = {["name"] = "golbat", ["label"] = "Golbat", ["weight"] = 0, ["type"] = "item", ["image"] = "golbat.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Soul Badge", ['created'] = nil, ["decay"] = 0.0}, + ["goldeen"] = {["name"] = "goldeen", ["label"] = "Goldeen", ["weight"] = 0, ["type"] = "item", ["image"] = "goldeen.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["golduck"] = {["name"] = "golduck", ["label"] = "Golduck", ["weight"] = 0, ["type"] = "item", ["image"] = "golduck.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Cascade Badge", ['created'] = nil, ["decay"] = 0.0}, + ["golem"] = {["name"] = "golem", ["label"] = "Golem", ["weight"] = 0, ["type"] = "item", ["image"] = "golem.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["graveler"] = {["name"] = "graveler", ["label"] = "Graveler", ["weight"] = 0, ["type"] = "item", ["image"] = "graveler.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Boulder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["grimer"] = {["name"] = "grimer", ["label"] = "Grimer", ["weight"] = 0, ["type"] = "item", ["image"] = "grimer.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["growlithe"] = {["name"] = "growlithe", ["label"] = "Growlithe", ["weight"] = 0, ["type"] = "item", ["image"] = "growlithe.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["gyarados"] = {["name"] = "gyarados", ["label"] = "Gyarados", ["weight"] = 0, ["type"] = "item", ["image"] = "gyarados.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["haunter"] = {["name"] = "haunter", ["label"] = "Haunter", ["weight"] = 0, ["type"] = "item", ["image"] = "haunter.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["hitmonchan"] = {["name"] = "hitmonchan", ["label"] = "Hitmonchan", ["weight"] = 0, ["type"] = "item", ["image"] = "hitmonchan.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["hitmonlee"] = {["name"] = "hitmonlee", ["label"] = "Hitmonlee", ["weight"] = 0, ["type"] = "item", ["image"] = "hitmonlee.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["horsea"] = {["name"] = "horsea", ["label"] = "Horsea", ["weight"] = 0, ["type"] = "item", ["image"] = "horsea.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["hypno"] = {["name"] = "hypno", ["label"] = "Hypno", ["weight"] = 0, ["type"] = "item", ["image"] = "hypno.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Marsh Badge", ['created'] = nil, ["decay"] = 0.0}, + ["ivysaur"] = {["name"] = "ivysaur", ["label"] = "Ivysaur", ["weight"] = 0, ["type"] = "item", ["image"] = "ivysaur.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["jigglypuff"] = {["name"] = "jigglypuff", ["label"] = "Jigglypuff", ["weight"] = 0, ["type"] = "item", ["image"] = "jigglypuff.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["jolteon"] = {["name"] = "jolteon", ["label"] = "Jolteon", ["weight"] = 0, ["type"] = "item", ["image"] = "jolteon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Thunder Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["jynx"] = {["name"] = "jynx", ["label"] = "Jynx", ["weight"] = 0, ["type"] = "item", ["image"] = "jynx.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Marsh Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["kabuto"] = {["name"] = "kabuto", ["label"] = "Kabuto", ["weight"] = 0, ["type"] = "item", ["image"] = "kabuto.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["kabutops"] = {["name"] = "kabutops", ["label"] = "Kabutops", ["weight"] = 0, ["type"] = "item", ["image"] = "kabutops.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Boulder Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["kadabra"] = {["name"] = "kadabra", ["label"] = "Kadabra", ["weight"] = 0, ["type"] = "item", ["image"] = "kadabra.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Marsh Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["kakuna"] = {["name"] = "kakuna", ["label"] = "Kakuna", ["weight"] = 0, ["type"] = "item", ["image"] = "kakuna.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["kangaskhan"] = {["name"] = "kangaskhan", ["label"] = "Kangaskhan", ["weight"] = 0, ["type"] = "item", ["image"] = "kangaskhan.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["kingler"] = {["name"] = "kingler", ["label"] = "Kingler", ["weight"] = 0, ["type"] = "item", ["image"] = "kingler.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["koffing"] = {["name"] = "koffing", ["label"] = "Koffing", ["weight"] = 0, ["type"] = "item", ["image"] = "koffing.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Soul Badge", ['created'] = nil, ["decay"] = 0.0}, + ["krabby"] = {["name"] = "krabby", ["label"] = "Krabby", ["weight"] = 0, ["type"] = "item", ["image"] = "krabby.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["lapras"] = {["name"] = "lapras", ["label"] = "Lapras", ["weight"] = 0, ["type"] = "item", ["image"] = "lapras.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Cascade Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["lickitung"] = {["name"] = "lickitung", ["label"] = "Lickitung", ["weight"] = 0, ["type"] = "item", ["image"] = "lickitung.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["machamp"] = {["name"] = "machamp", ["label"] = "Machamp", ["weight"] = 0, ["type"] = "item", ["image"] = "machamp.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["machoke"] = {["name"] = "machoke", ["label"] = "Machoke", ["weight"] = 0, ["type"] = "item", ["image"] = "machoke.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["machop"] = {["name"] = "machop", ["label"] = "Machop", ["weight"] = 0, ["type"] = "item", ["image"] = "machop.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["magikarp"] = {["name"] = "magikarp", ["label"] = "Magikarp", ["weight"] = 0, ["type"] = "item", ["image"] = "magikarp.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["magmar"] = {["name"] = "magmar", ["label"] = "Magmar", ["weight"] = 0, ["type"] = "item", ["image"] = "magmar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Volcano Badge", ['created'] = nil, ["decay"] = 0.0}, + ["magnemite"] = {["name"] = "magnemite", ["label"] = "Magnemite", ["weight"] = 0, ["type"] = "item", ["image"] = "magnemite.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["magneton"] = {["name"] = "magneton", ["label"] = "Magneton", ["weight"] = 0, ["type"] = "item", ["image"] = "magneton.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Thunder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["mankey"] = {["name"] = "mankey", ["label"] = "Mankey", ["weight"] = 0, ["type"] = "item", ["image"] = "mankey.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["marowak"] = {["name"] = "marowak", ["label"] = "Marowak", ["weight"] = 0, ["type"] = "item", ["image"] = "marowak.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["marshbadge"] = {["name"] = "marshbadge", ["label"] = "MarshBadge", ["weight"] = 0, ["type"] = "item", ["image"] = "marshBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["meowth"] = {["name"] = "meowth", ["label"] = "Meowth", ["weight"] = 0, ["type"] = "item", ["image"] = "meowth.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["metapod"] = {["name"] = "metapod", ["label"] = "Metapod", ["weight"] = 0, ["type"] = "item", ["image"] = "metapod.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["mew"] = {["name"] = "mew", ["label"] = "Mew", ["weight"] = 0, ["type"] = "item", ["image"] = "mew.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["mewtwo"] = {["name"] = "mewtwo", ["label"] = "Mewtwo", ["weight"] = 0, ["type"] = "item", ["image"] = "mewtwo.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Earth Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["moltres"] = {["name"] = "moltres", ["label"] = "Moltres", ["weight"] = 0, ["type"] = "item", ["image"] = "moltres.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Volcano Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["mrmime"] = {["name"] = "mrmime", ["label"] = "Mr_mime", ["weight"] = 0, ["type"] = "item", ["image"] = "mrmime.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Marsh Badge", ['created'] = nil, ["decay"] = 0.0}, + ["muk"] = {["name"] = "muk", ["label"] = "Muk", ["weight"] = 0, ["type"] = "item", ["image"] = "muk.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["nidoking"] = {["name"] = "nidoking", ["label"] = "Nidoking", ["weight"] = 0, ["type"] = "item", ["image"] = "nidoking.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Earth Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["nidoqueen"] = {["name"] = "nidoqueen", ["label"] = "Nidoqueen", ["weight"] = 0, ["type"] = "item", ["image"] = "nidoqueen.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Earth Badge", ['created'] = nil, ["decay"] = 0.0}, + ["nidoran"] = {["name"] = "nidoran", ["label"] = "Nidoran", ["weight"] = 0, ["type"] = "item", ["image"] = "nidoran.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["nidorina"] = {["name"] = "nidorina", ["label"] = "Nidorina", ["weight"] = 0, ["type"] = "item", ["image"] = "nidorina.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["nidorino"] = {["name"] = "nidorino", ["label"] = "Nidorino", ["weight"] = 0, ["type"] = "item", ["image"] = "nidorino.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["ninetails"] = {["name"] = "ninetails", ["label"] = "Ninetails", ["weight"] = 0, ["type"] = "item", ["image"] = "ninetails.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Volcano badge", ['created'] = nil, ["decay"] = 0.0}, + ["oddish"] = {["name"] = "oddish", ["label"] = "Oddish", ["weight"] = 0, ["type"] = "item", ["image"] = "oddish.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["omanyte"] = {["name"] = "omanyte", ["label"] = "Omanyte", ["weight"] = 0, ["type"] = "item", ["image"] = "omanyte.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["omastar"] = {["name"] = "omastar", ["label"] = "Omastar", ["weight"] = 0, ["type"] = "item", ["image"] = "omastar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Boulder Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["onix"] = {["name"] = "onix", ["label"] = "Onix", ["weight"] = 0, ["type"] = "item", ["image"] = "onix.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Boulder Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["paras"] = {["name"] = "paras", ["label"] = "Paras", ["weight"] = 0, ["type"] = "item", ["image"] = "paras.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["parasect"] = {["name"] = "parasect", ["label"] = "Parasect", ["weight"] = 0, ["type"] = "item", ["image"] = "parasect.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["persian"] = {["name"] = "persian", ["label"] = "Persian", ["weight"] = 0, ["type"] = "item", ["image"] = "persian.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Earth Badge", ['created'] = nil, ["decay"] = 0.0}, + ["pidgeotto"] = {["name"] = "pidgeotto", ["label"] = "Pidgeotto", ["weight"] = 0, ["type"] = "item", ["image"] = "pidgeotto.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pidgey"] = {["name"] = "pidgey", ["label"] = "Pidgey", ["weight"] = 0, ["type"] = "item", ["image"] = "pidgey.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pikachu"] = {["name"] = "pikachu", ["label"] = "Pikachu", ["weight"] = 0, ["type"] = "item", ["image"] = "pikachu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Thunder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["pinsir"] = {["name"] = "pinsir", ["label"] = "Pinsir", ["weight"] = 0, ["type"] = "item", ["image"] = "pinsir.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["poliwag"] = {["name"] = "poliwag", ["label"] = "Poliwag", ["weight"] = 0, ["type"] = "item", ["image"] = "poliwag.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["polywhirl"] = {["name"] = "polywhirl", ["label"] = "Polywhirl", ["weight"] = 0, ["type"] = "item", ["image"] = "polywhirl.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["poliwrath"] = {["name"] = "poliwrath", ["label"] = "Poliwrath", ["weight"] = 0, ["type"] = "item", ["image"] = "poliwrath.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["ponyta"] = {["name"] = "ponyta", ["label"] = "Ponyta", ["weight"] = 0, ["type"] = "item", ["image"] = "ponyta.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["porygon"] = {["name"] = "porygon", ["label"] = "Porygon", ["weight"] = 0, ["type"] = "item", ["image"] = "porygon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["primeape"] = {["name"] = "primeape", ["label"] = "Primeape", ["weight"] = 0, ["type"] = "item", ["image"] = "primeape.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["psyduck"] = {["name"] = "psyduck", ["label"] = "Psyduck", ["weight"] = 0, ["type"] = "item", ["image"] = "psyduck.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Cascade Badge", ['created'] = nil, ["decay"] = 0.0}, + ["raichu"] = {["name"] = "raichu", ["label"] = "Raichu", ["weight"] = 0, ["type"] = "item", ["image"] = "raichu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["rainbowbadge"] = {["name"] = "rainbowbadge", ["label"] = "RainbowBadge", ["weight"] = 0, ["type"] = "item", ["image"] = "rainbowBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Rainbow Badge", ['created'] = nil, ["decay"] = 0.0}, + ["rapidash"] = {["name"] = "rapidash", ["label"] = "Rapidash", ["weight"] = 0, ["type"] = "item", ["image"] = "rapidash.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Volcano Badge", ['created'] = nil, ["decay"] = 0.0}, + ["raticate"] = {["name"] = "raticate", ["label"] = "Raticate", ["weight"] = 0, ["type"] = "item", ["image"] = "raticate.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["rattata"] = {["name"] = "rattata", ["label"] = "Rattata", ["weight"] = 0, ["type"] = "item", ["image"] = "rattata.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["rhydon"] = {["name"] = "rhydon", ["label"] = "Rhydon", ["weight"] = 0, ["type"] = "item", ["image"] = "rhydon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Earth Badge", ['created'] = nil, ["decay"] = 0.0}, + ["rhyhorn"] = {["name"] = "rhyhorn", ["label"] = "Rhyhorn", ["weight"] = 0, ["type"] = "item", ["image"] = "rhyhorn.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Boulder Badge", ['created'] = nil, ["decay"] = 0.0}, + ["sandshrew"] = {["name"] = "sandshrew", ["label"] = "Sandshrew", ["weight"] = 0, ["type"] = "item", ["image"] = "sandshrew.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["sandslash"] = {["name"] = "sandslash", ["label"] = "Sandslash", ["weight"] = 0, ["type"] = "item", ["image"] = "sandslash.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["scyther"] = {["name"] = "scyther", ["label"] = "Scyther", ["weight"] = 0, ["type"] = "item", ["image"] = "scyther.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Rainbow Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["seadra"] = {["name"] = "seadra", ["label"] = "Seadra", ["weight"] = 0, ["type"] = "item", ["image"] = "seadra.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["seaking"] = {["name"] = "seaking", ["label"] = "Seaking", ["weight"] = 0, ["type"] = "item", ["image"] = "seaking.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["seel"] = {["name"] = "seel", ["label"] = "Seel", ["weight"] = 0, ["type"] = "item", ["image"] = "seel.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["shellder"] = {["name"] = "shellder", ["label"] = "Shellder", ["weight"] = 0, ["type"] = "item", ["image"] = "shellder.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["slowbro"] = {["name"] = "slowbro", ["label"] = "Slowbro", ["weight"] = 0, ["type"] = "item", ["image"] = "slowbro.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["slowpoke"] = {["name"] = "slowpoke", ["label"] = "Slowpoke", ["weight"] = 0, ["type"] = "item", ["image"] = "slowpoke.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["snorlax"] = {["name"] = "snorlax", ["label"] = "Snorlax", ["weight"] = 0, ["type"] = "item", ["image"] = "snorlax.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Soul Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["soulbadge"] = {["name"] = "soulbadge", ["label"] = "SoulBadge", ["weight"] = 0, ["type"] = "item", ["image"] = "soulBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["spearow"] = {["name"] = "spearow", ["label"] = "Spearow", ["weight"] = 0, ["type"] = "item", ["image"] = "spearow.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["squirtle"] = {["name"] = "squirtle", ["label"] = "Squirtle", ["weight"] = 0, ["type"] = "item", ["image"] = "squirtle.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["starmie"] = {["name"] = "starmie", ["label"] = "Starmie", ["weight"] = 0, ["type"] = "item", ["image"] = "starmie.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Cascade Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["staryu"] = {["name"] = "staryu", ["label"] = "Staryu", ["weight"] = 0, ["type"] = "item", ["image"] = "staryu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["tangela"] = {["name"] = "tangela", ["label"] = "Tangela", ["weight"] = 0, ["type"] = "item", ["image"] = "tangela.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Rainbow Badge", ['created'] = nil, ["decay"] = 0.0}, + ["tauros"] = {["name"] = "tauros", ["label"] = "Tauros", ["weight"] = 0, ["type"] = "item", ["image"] = "tauros.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["tentacool"] = {["name"] = "tentacool", ["label"] = "Tentacool", ["weight"] = 0, ["type"] = "item", ["image"] = "tentacool.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["tentacruel"] = {["name"] = "tentacruel", ["label"] = "Tentacruel", ["weight"] = 0, ["type"] = "item", ["image"] = "tentacruel.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["thunderbadge"] = {["name"] = "thunderbadge", ["label"] = "ThunderBadge", ["weight"] = 0, ["type"] = "item", ["image"] = "thunderBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["togepi"] = {["name"] = "togepi", ["label"] = "Togepi", ["weight"] = 0, ["type"] = "item", ["image"] = "togepi.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Cascade Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["trophybadge"] = {["name"] = "trophybadge", ["label"] = "Trophy Badge", ["weight"] = 0, ["type"] = "item", ["image"] = "trophyBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "OwO You have a Trophy", ['created'] = nil, ["decay"] = 0.0}, + ["vaporeon"] = {["name"] = "vaporeon", ["label"] = "Vaporeon", ["weight"] = 0, ["type"] = "item", ["image"] = "vaporeon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["venomoth"] = {["name"] = "venomoth", ["label"] = "Venomoth", ["weight"] = 0, ["type"] = "item", ["image"] = "venomoth.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "4/6 for Soul Badge", ['created'] = nil, ["decay"] = 0.0}, + ["venonat"] = {["name"] = "venonat", ["label"] = "Venonat", ["weight"] = 0, ["type"] = "item", ["image"] = "venonat.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "5/6 for Soul Badge", ['created'] = nil, ["decay"] = 0.0}, + ["venusaur"] = {["name"] = "venusaur", ["label"] = "Venusaur", ["weight"] = 0, ["type"] = "item", ["image"] = "venusaur.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Rainbow Badge - Rare", ['created'] = nil, ["decay"] = 0.0}, + ["victreebel"] = {["name"] = "victreebel", ["label"] = "Victreebel", ["weight"] = 0, ["type"] = "item", ["image"] = "victreebel.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Rainbow Badge", ['created'] = nil, ["decay"] = 0.0}, + ["vileplume"] = {["name"] = "vileplume", ["label"] = "Vileplume", ["weight"] = 0, ["type"] = "item", ["image"] = "vileplume.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "3/6 for Rainbow Badge", ['created'] = nil, ["decay"] = 0.0}, + ["volcanobadge"] = {["name"] = "volcanobadge", ["label"] = "Volcano Badge", ["weight"] = 0, ["type"] = "item", ["image"] = "volcanoBadge.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "7/8 for Trophy Badge", ['created'] = nil, ["decay"] = 0.0}, + ["voltorb"] = {["name"] = "voltorb", ["label"] = "Voltorb", ["weight"] = 0, ["type"] = "item", ["image"] = "voltorb.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["vulpix"] = {["name"] = "vulpix", ["label"] = "Vulpix", ["weight"] = 0, ["type"] = "item", ["image"] = "vulpix.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["wartortle"] = {["name"] = "wartortle", ["label"] = "Wartortle", ["weight"] = 0, ["type"] = "item", ["image"] = "wartortle.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["weedle"] = {["name"] = "weedle", ["label"] = "Weedle", ["weight"] = 0, ["type"] = "item", ["image"] = "weedle.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["weepinbell"] = {["name"] = "weepinbell", ["label"] = "Weepinbell", ["weight"] = 0, ["type"] = "item", ["image"] = "weepinbell.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["weezing"] = {["name"] = "weezing", ["label"] = "Weezing", ["weight"] = 0, ["type"] = "item", ["image"] = "weezing.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "2/6 for Soul Badge", ['created'] = nil, ["decay"] = 0.0}, + ["wigglytuff"] = {["name"] = "wigglytuff", ["label"] = "Wigglytuff", ["weight"] = 0, ["type"] = "item", ["image"] = "wigglytuff.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rare", ['created'] = nil, ["decay"] = 0.0}, + ["zapdos"] = {["name"] = "zapdos", ["label"] = "Zapdos", ["weight"] = 0, ["type"] = "item", ["image"] = "zapdos.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "1/6 for Thunder Badge - Ultra Rare", ['created'] = nil, ["decay"] = 0.0}, + ["zubat"] = {["name"] = "zubat", ["label"] = "Zubat", ["weight"] = 0, ["type"] = "item", ["image"] = "zubat.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["bulbasaur"] = {["name"] = "bulbasaur", ["label"] = "Bulbasaur", ["weight"] = 0, ["type"] = "item", ["image"] = "bulbasaur.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pidgeot"] = {["name"] = "pidgeot", ["label"] = "Pidgeot", ["weight"] = 0, ["type"] = "item", ["image"] = "pidgeot.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "6/6 for Earth Badge", ['created'] = nil, ["decay"] = 0.0}, + ["blastoisev"] = {["name"] = "blastoisev", ["label"] = "Blastoise V", ["weight"] = 0, ["type"] = "item", ["image"] = "blastoisev.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["charizardv"] = {["name"] = "charizardv", ["label"] = "Charizard V", ["weight"] = 0, ["type"] = "item", ["image"] = "charizardv.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["mewv"] = {["name"] = "mewv", ["label"] = "Mew V", ["weight"] = 0, ["type"] = "item", ["image"] = "mewv.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["pikachuv"] = {["name"] = "pikachuv", ["label"] = "Pikachu V", ["weight"] = 0, ["type"] = "item", ["image"] = "pikachuv.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["snorlaxv"] = {["name"] = "snorlaxv", ["label"] = "Snorlax V", ["weight"] = 0, ["type"] = "item", ["image"] = "snorlaxv.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["venusaurv"] = {["name"] = "venusaurv", ["label"] = "Venusaur V", ["weight"] = 0, ["type"] = "item", ["image"] = "venusaurv.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "V Card", ['created'] = nil, ["decay"] = 0.0}, + ["blastoisevmax"] = {["name"] = "blastoisevmax", ["label"] = "Blastoise Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "blastoisevmax.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["mewtwogx"] = {["name"] = "mewtwogx", ["label"] = "Mewtwo Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "mewtwogx.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["snorlaxvmax"] = {["name"] = "snorlaxvmax", ["label"] = "Snorlax Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "snorlaxvmax.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["venusaurvmax"] = {["name"] = "venusaurvmax", ["label"] = "Venusaur Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "venusaurvmax.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["vmaxcharizard"] = {["name"] = "vmaxcharizard", ["label"] = "Charizard Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "vmaxcharizard.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["vmaxpikachu"] = {["name"] = "vmaxpikachu", ["label"] = "Pikachu Vmax", ["weight"] = 0, ["type"] = "item", ["image"] = "vmaxpikachu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Vmax Card", ['created'] = nil, ["decay"] = 0.0}, + ["rainbowmewtwogx"] = {["name"] = "rainbowmewtwogx", ["label"] = "Rainbow Mewtwo", ["weight"] = 0, ["type"] = "item", ["image"] = "rainbowmewtwogx.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rainbow Card", ['created'] = nil, ["decay"] = 0.0}, + ["rainbowvmaxcharizard"] = {["name"] = "rainbowvmaxcharizard", ["label"] = "Rainbow Charizard", ["weight"] = 0, ["type"] = "item", ["image"] = "rainbowvmaxcharizard.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rainbow Card", ['created'] = nil, ["decay"] = 0.0}, + ["rainbowvmaxpikachu"] = {["name"] = "rainbowvmaxpikachu", ["label"] = "Rainbow Pikachu", ["weight"] = 0, ["type"] = "item", ["image"] = "rainbowvmaxpikachu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rainbow Card", ['created'] = nil, ["decay"] = 0.0}, + ["snorlaxvmaxrainbow"] = {["name"] = "snorlaxvmaxrainbow", ["label"] = "Rainbox Snorlax", ["weight"] = 0, ["type"] = "item", ["image"] = "snorlaxvmaxrainbow.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rainbow Card", ['created'] = nil, ["decay"] = 0.0}, + ["pokebox"] = {["name"] = "pokebox", ["label"] = "Pokemon TCG Box", ["weight"] = 50, ["type"] = "item", ["image"] = "pokebox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pokemon TCG Storage Box", ['created'] = nil, ["decay"] = 0.0}, + + -- Bowling Shit -- REMOVED SCRIPT FOR NOW + ["bowlingball"] = {["name"] = "bowlingball", ["label"] = "Bowling Ball", ["weight"] = 10000, ["type"] = "item", ["image"] = "bowlingball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Strike!", ['created'] = nil, ["decay"] = 0.0}, + ["bowlingreceipt"] = {["name"] = "bowlingreceipt", ["label"] = "Bowling Receipt", ["weight"] = 100, ["type"] = "item", ["image"] = "bowlingreceipt.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Proof of purchase Bowling receipt.", ['created'] = nil, ["decay"] = 0.0}, + ['customs_receipt'] = {['name'] = 'customs_receipt', ['label'] = 'Receipt', ['weight'] = 10, ['type'] = 'item', ['image'] = 'customs_receipt.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Your car/s customization receipt'}, + + -- Rental + ["rentalpapers"] = {["name"] = "rentalpapers", ["label"] = "Rental Papers", ["weight"] = 100, ["type"] = "item", ["image"] = "rentalpapers.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Yea, this is my car i can prove it!", ['created'] = nil, ["decay"] = 0.0}, + + -- Funkopop Toys + ['funkopop_harrypotter'] = {['name'] = 'funkopop_harrypotter', ['label'] = 'Harry Potter Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_harrypotter.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Harry Potter Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_draco'] = {['name'] = 'funkopop_draco', ['label'] = 'Draco Malfoy Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_draco.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Draco Malfoy Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_hermione'] = {['name'] = 'funkopop_hermione', ['label'] = 'Hermione Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_hermione.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Hermione Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_ron'] = {['name'] = 'funkopop_ron', ['label'] = 'Ron Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_ron.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Ron Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_dumbledore'] = {['name'] = 'funkopop_dumbledore', ['label'] = 'Dumbledore Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_dumbledore.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Dumbledore Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_hedwig'] = {['name'] = 'funkopop_hedwig', ['label'] = 'Hedwig Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_hedwig.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Hedwig Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_hagrid'] = {['name'] = 'funkopop_hagrid', ['label'] = 'Hagrid Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_hagrid.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Hagrid Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_moaningmertle'] = {['name'] = 'funkopop_moaningmertle', ['label'] = 'Moaning Mertle Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_moaningmertle.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Moaning Mertle Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_voldemort'] = {['name'] = 'funkopop_voldemort', ['label'] = 'Voldemort Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_voldemort.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Voldemort Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['funkopop_snape'] = {['name'] = 'funkopop_snape', ['label'] = 'Severus Snape Funkopop', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'funkopop_snape.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Severus Snape Funkopop Toy', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Gang Chains + ['slothchain'] = {['name'] = 'slothchain', ['label'] = 'Sloth Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_sloth_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Sloth God.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cg_chain'] = {['name'] = 'cg_chain', ['label'] = 'CG Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_cg_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'This chain belongs to the legendary Chang Gang.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['gsf_chain'] = {['name'] = 'gsf_chain', ['label'] = 'GSF Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_gsf_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Grove Street Families gang chain.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cerberus_chain'] = {['name'] = 'cerberus_chain', ['label'] = 'Cerberus Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_cerberus_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Cerberus Business Chain.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['mdm_chain'] = {['name'] = 'mdm_chain', ['label'] = 'MDM Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_mdm_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The Mandem chain.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['esv_chain'] = {['name'] = 'esv_chain', ['label'] = 'ESV Chain', ['weight'] = 4000, ['type'] = 'item', ['image'] = 'np_vagos_chain.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'East Side Vagos gang chain.', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- qb-methlab + ["ephedrine"] = {["name"] = "ephedrine", ["label"] = "Ephedrine", ["weight"] = 500, ["type"] = "item", ["image"] = "chemical1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Prescription medicine used to treat the symptoms of low blood pressure", ['created'] = nil, ["decay"] = 0.0}, + ["hydrochloricacid"] = {["name"] = "hydrochloricacid", ["label"] = "Hydrochloric Acid", ["weight"] = 500, ["type"] = "item", ["image"] = "chemical1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Component of the gastric acid in the digestive systems of most animal species...including humans", ['created'] = nil, ["decay"] = 0.0}, + ["acetone"] = {["name"] = "acetone", ["label"] = "Acetone", ["weight"] = 500, ["type"] = "item", ["image"] = "chemical2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Breathing moderate amounts for a short amount of time can irritate your nose, throat, lungs and eyes", ['created'] = nil, ["decay"] = 0.0}, + ["puremeth"] = {["name"] = "puremeth", ["label"] = "Pure Meth", ["weight"] = 100, ["type"] = "item", ["image"] = "meth10g.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A baggie of Pure Meth", ['created'] = nil, ["decay"] = 0.0}, + ["meth"] = {["name"] = "meth", ["label"] = "Meth", ["weight"] = 100, ["type"] = "item", ["image"] = "meth10g.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A baggie of Meth", ['created'] = nil, ["decay"] = 0.0}, + ["methtray"] = {["name"] = "methtray", ["label"] = "Meth Tray", ["weight"] = 2000, ["type"] = "item", ["image"] = "methbrick.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "make some meth", ['created'] = nil, ["decay"] = 0.0}, + ["puremethtray"] = {["name"] = "puremethtray", ["label"] = "Pure Meth Tray", ["weight"] = 2600, ["type"] = "item", ["image"] = "methbrick.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "make some meth", ['created'] = nil, ["decay"] = 0.0}, + ["labkey"] = {["name"] = "labkey", ["label"] = "Key", ["weight"] = 500, ["type"] = "item", ["image"] = "labkey.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Key for a lock...?", ['created'] = nil, ["decay"] = 0.0}, + + -- qb-cokerun + ["stingray"] = {["name"] = "stingray", ["label"] = "Stingray", ["weight"] = 500, ["type"] = "item", ["image"] = "np_hacking_device.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Intercept messages from cellular towers", ['created'] = nil, ["decay"] = 0.0}, + ["coke"] = {["name"] = "coke", ["label"] = "Coke Powder", ["weight"] = 1000, ["type"] = "item", ["image"] = "coke.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cocaine processed powder", ['created'] = nil, ["decay"] = 0.0}, + + -- qb-containers + ["small_container"] = {["name"] = "small_container", ["label"] = "Small Container", ["weight"] = 5000, ["type"] = "item", ["image"] = "small_container.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Small Container", ['created'] = nil, ["decay"] = 0.0}, + ["medium_container"] = {["name"] = "medium_container", ["label"] = "Medium Container", ["weight"] = 10000, ["type"] = "item", ["image"] = "medium_container.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Medium Container", ['created'] = nil, ["decay"] = 0.0}, + ["large_container"] = {["name"] = "large_container", ["label"] = "Large Container", ["weight"] = 15000, ["type"] = "item", ["image"] = "large_container.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Large Container", ['created'] = nil, ["decay"] = 0.0}, + + -- Arcade stuff + ["arcadegreen"] = {["name"] = "arcadegreen", ["label"] = "Green Arcade Card", ["weight"] = 100, ["type"] = "item", ["image"] = "arcadegreen.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A green arcade card.", ['created'] = nil, ["decay"] = 0.0}, + ["arcadeblue"] = {["name"] = "arcadeblue", ["label"] = "Blue Arcade Card", ["weight"] = 100, ["type"] = "item", ["image"] = "arcadeblue.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A blue arcade card.", ['created'] = nil, ["decay"] = 0.0}, + ["arcadegold"] = {["name"] = "arcadegold", ["label"] = "Gold Arcade Card", ["weight"] = 100, ["type"] = "item", ["image"] = "arcadegold.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A gold arcade card", ['created'] = nil, ["decay"] = 0.0}, + + -- RANDOM SHIT + ["bong"] = {["name"] = "bong", ["label"] = "Bong", ["weight"] = 500, ["type"] = "item", ["image"] = "bong.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "In Australia this is called a \"Billy\"", ['created'] = nil, ["decay"] = 0.0}, + ["nightvision"] = {["name"] = "nightvision", ["label"] = "Night Vision Goggles", ["weight"] = 1000, ["type"] = "item", ["image"] = "nightvgoggles.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bravo Six, going dark.", ['created'] = nil, ["decay"] = 0.0}, + ['adrenshot'] = {['name'] = 'adrenshot', ['label'] = 'Adrenaline Shot', ['weight'] = 200, ['type'] = 'item', ['image'] = 'np_adrenaline.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Save someones heart or keep up with crims', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- don't use duffel for now (need new script, this one took backpacks off peoples backs after equipping in store lmao) + ["duffel-bag"] = {["name"] = "duffel-bag", ["label"] = "Bag", ["weight"] = 5000, ["type"] = "item", ["image"] = "duffel.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "im bag im baag im baaaaag", ['created'] = nil, ["decay"] = 0.0}, + ["ifak"] = {["name"] = "ifak", ["label"] = "IFAK", ["weight"] = 2000, ["type"] = "item", ["image"] = "ifak.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Heavy duty medical supplies", ['created'] = nil, ["decay"] = 0.0}, + ['slushy'] = {['name'] = 'slushy', ['label'] = 'Slushy', ['weight'] = 750, ['type'] = 'item', ['image'] = 'slushy.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Damn a Slushy...', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- ["cigarettes"] = {["name"] = "cigarette", ["label"] = "Marlboros", ["weight"] = 400, ["type"] = "item", ["image"] = "np_ciggypack.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Time for a smoke", ['created'] = nil, ["decay"] = 0.0}, + ["wheelchair"] = {["name"] = "wheelchair", ["label"] = "Wheelchair", ["weight"] = 8000, ["type"] = "item", ["image"] = "np_wheelchair.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "To assist you with all your handicapped needs.", ['created'] = nil, ["decay"] = 0.0}, + -- Sign Robbery + ["stopsign"] = {["name"] = "stopsign", ["label"] = "Stop Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "stopsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Stop Sign", ['created'] = nil, ["decay"] = 0.0}, + ["walkingmansign"] = {["name"] = "walkingmansign", ["label"] = "Pedestrian Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "walkingmansign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pedestrian Sign", ['created'] = nil, ["decay"] = 0.0}, + ["dontblockintersectionsign"] = {["name"] = "dontblockintersectionsign", ["label"] = "Intersection Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "dontblockintersectionsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Intersection Sign", ['created'] = nil, ["decay"] = 0.0}, + ["uturnsign"] = {["name"] = "uturnsign", ["label"] = "U Turn Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "uturnsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "U Turn Sign", ['created'] = nil, ["decay"] = 0.0}, + ["noparkingsign"] = {["name"] = "noparkingsign", ["label"] = "No Parking Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "noparkingsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "No Parking Sign", ['created'] = nil, ["decay"] = 0.0}, + ["leftturnsign"] = {["name"] = "leftturnsign", ["label"] = "Left Turn Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "leftturnsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Left Turn Sign", ['created'] = nil, ["decay"] = 0.0}, + ["rightturnsign"] = {["name"] = "rightturnsign", ["label"] = "Right Turn Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "rightturnsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Right Turn Sign", ['created'] = nil, ["decay"] = 0.0}, + ["notrespassingsign"] = {["name"] = "notrespassingsign", ["label"] = "No Trespassing Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "notrespassingsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "No Trespassing Sign", ['created'] = nil, ["decay"] = 0.0}, + ["yieldsign"] = {["name"] = "yieldsign", ["label"] = "Yield Sign", ["weight"] = 1, ["type"] = "item", ["image"] = "yieldsign.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Yield Sign", ['created'] = nil, ["decay"] = 0.0}, + + -- custom house robbery shit + ["stolentv"] = {["name"] = "stolentv", ["label"] = "TV", ["weight"] = 12000, ["type"] = "item", ["image"] = "np_stolentv.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "This is a nice looking TV, probably stolen though...", ['created'] = nil, ["decay"] = 0.0}, + ["safe"] = {["name"] = "safe", ["label"] = "Safe", ["weight"] = 30000, ["type"] = "item", ["image"] = "np_housesafe.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Fuck this shit is heavy...", ['created'] = nil, ["decay"] = 0.0}, + + ["package"] = {["name"] = "package", ["label"] = "Suspicious Package", ["weight"] = 5000, ["type"] = "item", ["image"] = "np_dark_market_package.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Package covered in tape and milk stickers.\nMarked for Police Seizure", ['created'] = nil, ["decay"] = 0.0}, + + --uWu Cafe + --Sandwiches + ["uwuhamcheesesandwich"] = {["name"] = "uwuhamcheesesandwich", ["label"] = "Ham and Cheese Sandwich", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuhamcheesesandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuvanillasandwich"] = {["name"] = "uwuvanillasandwich", ["label"] = "Vanilla Sandwich", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuvanillasandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuchocolatesandwich"] = {["name"] = "uwuchocolatesandwich", ["label"] = "Chocolate Sandwich", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuchocolatesandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwustrawberrysandwich"] = {["name"] = "uwustrawberrysandwich", ["label"] = "Strawberry Sandwich", ["weight"] = 100, ["type"] = "item", ["image"] = "uwustrawberrysandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + --Drinks + ["uwubobatea"] = {["name"] = "uwubobatea", ["label"] = "Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwubobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwubbobatea"] = {["name"] = "uwubbobatea", ["label"] = "Blue Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwubbobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwugbobatea"] = {["name"] = "uwugbobatea", ["label"] = "Green Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwugbobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwupbobatea"] = {["name"] = "uwupbobatea", ["label"] = "Pink Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwupbobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuobobatea"] = {["name"] = "uwuobobatea", ["label"] = "Orange Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuobobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunekolatte"] = {["name"] = "uwunekolatte", ["label"] = "Neko Latte", ["weight"] = 100, ["type"] = "item", ["image"] = "uwunekolatte.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuuwucapuchino"] = {["name"] = "uwuuwucapuchino", ["label"] = "Capuchino", ["weight"] = 100, ["type"] = "item", ["image"] = "uwucapuchino.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwucoffee"] = {["name"] = "uwucoffee", ["label"] = "Coffee", ["weight"] = 100, ["type"] = "item", ["image"] = "uwucoffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwusake"] = {["name"] = "uwusake", ["label"] = "Sake", ["weight"] = 100, ["type"] = "item", ["image"] = "uwusake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuhotchocolate"] = {["name"] = "uwuhotchocolate", ["label"] = "Hot Chocolate", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuhotchocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwurbobatea"] = {["name"] = "uwurbobatea", ["label"] = "Rose Boba Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwurbobatea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + --Oven Food + ["uwunekocake"] = {["name"] = "uwunekocake", ["label"] = "Cup Cake", ["weight"] = 100, ["type"] = "item", ["image"] = "uwunekocake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunekocookie"] = {["name"] = "uwunekocookie", ["label"] = "Neko Cookie", ["weight"] = 100, ["type"] = "item", ["image"] = "uwunekocookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwubmochi"] = {["name"] = "uwubmochi", ["label"] = "Blue Mochi", ["weight"] = 100, ["type"] = "item", ["image"] = "uwubmochi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwupmochi"] = {["name"] = "uwupmochi", ["label"] = "Pink Mochi", ["weight"] = 100, ["type"] = "item", ["image"] = "uwupmochi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwugmochi"] = {["name"] = "uwugmochi", ["label"] = "Green Mochi", ["weight"] = 100, ["type"] = "item", ["image"] = "uwugmochi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuomochi"] = {["name"] = "uwuomochi", ["label"] = "Orange Mochi", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuomochi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwurmochi"] = {["name"] = "uwurmochi", ["label"] = "Rose Mochi", ["weight"] = 100, ["type"] = "item", ["image"] = "uwurmochi.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + --Hot Plates + ["uwumisosoup"] = {["name"] = "uwumisosoup", ["label"] = "Miso Soup", ["weight"] = 100, ["type"] = "item", ["image"] = "uwumisosoup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwucatfood"] = {["name"] = "uwucatfood", ["label"] = "Cat Food", ["weight"] = 100, ["type"] = "item", ["image"] = "uwucatfood.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwupancakes"] = {["name"] = "uwupancakes", ["label"] = "Pancakes", ["weight"] = 100, ["type"] = "item", ["image"] = "uwupancakes.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunekodonut"] = {["name"] = "uwunekodonut", ["label"] = "Neko Donut", ["weight"] = 100, ["type"] = "item", ["image"] = "uwunekodonut.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuriceball"] = {["name"] = "uwuriceball", ["label"] = "Neko Onigiri", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuriceball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + --Ingredients + ["uwuham"] = {["name"] = "uwuham", ["label"] = "Ham", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuham.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwucheese"] = {["name"] = "uwucheese", ["label"] = "Cheese", ["weight"] = 100, ["type"] = "item", ["image"] = "uwucheese.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwubread"] = {["name"] = "uwubread", ["label"] = "Bread", ["weight"] = 100, ["type"] = "item", ["image"] = "uwubread.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuboba"] = {["name"] = "uwuboba", ["label"] = "Boba", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuboba.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuflour"] = {["name"] = "uwuflour", ["label"] = "Flour", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuflour.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwurice"] = {["name"] = "uwurice", ["label"] = "Bowl of Rice", ["weight"] = 100, ["type"] = "item", ["image"] = "uwurice.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwusugar"] = {["name"] = "uwusugar", ["label"] = "Sugar", ["weight"] = 100, ["type"] = "item", ["image"] = "uwusugar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunori"] = {["name"] = "uwunori", ["label"] = "Nori", ["weight"] = 100, ["type"] = "item", ["image"] = "uwunori.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwublueberry"] = {["name"] = "uwublueberry", ["label"] = "Blueberry", ["weight"] = 100, ["type"] = "item", ["image"] = "uwublueberry.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwustrawberry"] = {["name"] = "uwustrawberry", ["label"] = "Strawberry", ["weight"] = 100, ["type"] = "item", ["image"] = "uwustrawberry.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuvanilla"] = {["name"] = "uwuvanilla", ["label"] = "Vanilla", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuvanilla.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwurose"] = {["name"] = "uwurose", ["label"] = "Rose", ["weight"] = 100, ["type"] = "item", ["image"] = "uwurose.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One rose for beautiful lady", ['created'] = nil, ["decay"] = 0.0}, + ["uwumint"] = {["name"] = "uwumint", ["label"] = "Matcha", ["weight"] = 100, ["type"] = "item", ["image"] = "uwumatcha.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Mint thing", ['created'] = nil, ["decay"] = 0.0}, + ["uwutofu"] = {["name"] = "uwutofu", ["label"] = "Tofu", ["weight"] = 100, ["type"] = "item", ["image"] = "uwutofu.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Mmm tofu", ['created'] = nil, ["decay"] = 0.0}, + ["uwucup"] = {["name"] = "uwucup", ["label"] = "Cup", ["weight"] = 100, ["type"] = "item", ["image"] = "uwucup.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cup for everything", ['created'] = nil, ["decay"] = 0.0}, + ["uwuorange"] = {["name"] = "uwuorange", ["label"] = "Orange", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuorange.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An Orange.", ['created'] = nil, ["decay"] = 0.0}, + ["uwumilk"] = {["name"] = "uwumilk", ["label"] = "Milk", ["weight"] = 100, ["type"] = "item", ["image"] = "uwumilk.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bottle of Milk", ['created'] = nil, ["decay"] = 0.0}, + ["uwuonion"] = {["name"] = "uwuonion", ["label"] = "Onion", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuonion.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "An onion", ['created'] = nil, ["decay"] = 0.0}, + ["uwuchocolate"] = {["name"] = "uwuchocolate", ["label"] = "Chocolate", ["weight"] = 100, ["type"] = "item", ["image"] = "uwuchocolate.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sweet Chocolate", ['created'] = nil, ["decay"] = 0.0}, + ["uwutea"] = {["name"] = "uwutea", ["label"] = "Tea", ["weight"] = 100, ["type"] = "item", ["image"] = "uwutea.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cat Tea", ['created'] = nil, ["decay"] = 0.0}, + ["uwueggs"] = {["name"] = "uwueggs", ["label"] = "Eggs", ["weight"] = 100, ["type"] = "item", ["image"] = "uwueggs.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cat Eggs :)", ['created'] = nil, ["decay"] = 0.0}, + ["uwu-ticket"] = {["name"] = "uwu-ticket", ["label"] = "uWu Receipt", ["weight"] = 30, ["type"] = "item", ["image"] = "uwuticket.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cash these in at the bank!", ['created'] = nil, ["decay"] = 0.0}, + + --Mixtures + ["uwunekocakemixture"] = {["name"] = "uwunekocakemixture", ["label"] = "Neko Cake Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwunekocakemixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwubmochimixture"] = {["name"] = "uwubmochimixture", ["label"] = "Blue Mochi Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwubmochimixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwugmochimixture"] = {["name"] = "uwugmochimixture", ["label"] = "Green Mochi Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwugmochimixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuomochimixture"] = {["name"] = "uwuomochimixture", ["label"] = "Orange Mochi Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwuomochimixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwupmochimixture"] = {["name"] = "uwupmochimixture", ["label"] = "Pink Mochi Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwupmochimixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwuriceballmixture"] = {["name"] = "uwuriceballmixture", ["label"] = "Neko Onigiri Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwuriceballmixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunekocookiemixture"] = {["name"] = "uwunekocookiemixture", ["label"] = "Neko Cookie Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwunekocookiemixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwunekodonutmixture"] = {["name"] = "uwunekodonutmixture", ["label"] = "Neko Donut Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwunekodonutmixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwupancakesmixture"] = {["name"] = "uwupancakesmixture", ["label"] = "Pancakes Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwupancakesmixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwumisosoupmixture"] = {["name"] = "uwumisosoupmixture", ["label"] = "Miso Soup Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwumisosoupmixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["uwucatfoodmixture"] = {["name"] = "uwucatfoodmixture", ["label"] = "Cat Food Mixture", ["weight"] = 500, ["type"] = "item", ["image"] = "uwucatfoodmixture.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + --- uWu Toys + ["uwutoy1"] = {["name"] = "uwutoy1", ["label"] = "uWu Toy 1", ["weight"] = 200, ["type"] = "item", ["image"] = "uwutoy1.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One of uWu toys...", ['created'] = nil, ["decay"] = 0.0}, + ["uwutoy2"] = {["name"] = "uwutoy2", ["label"] = "uWu Toy 2", ["weight"] = 200, ["type"] = "item", ["image"] = "uwutoy2.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One of uWu toys...", ['created'] = nil, ["decay"] = 0.0}, + ["uwutoy3"] = {["name"] = "uwutoy3", ["label"] = "uWu Toy 3", ["weight"] = 200, ["type"] = "item", ["image"] = "uwutoy3.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One of uWu toys...", ['created'] = nil, ["decay"] = 0.0}, + ["uwutoy4"] = {["name"] = "uwutoy4", ["label"] = "uWu Toy 4", ["weight"] = 200, ["type"] = "item", ["image"] = "uwutoy4.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One of uWu toys...", ['created'] = nil, ["decay"] = 0.0}, + ["uwubox"] = {["name"] = "uwubox", ["label"] = "uWu Box", ["weight"] = 200, ["type"] = "item", ["image"] = "uwubox.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "One of uWu toys...", ['created'] = nil, ["decay"] = 0.0}, + + --qb-PizzaThis + --WINES + ["amarone"] = {["name"] = "amarone", ["label"] = "Amarone", ["weight"] = 100, ["type"] = "item", ["image"] = "amarone.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["barbera"] = {["name"] = "barbera", ["label"] = "Barbera D'Asti", ["weight"] = 100, ["type"] = "item", ["image"] = "barbera.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["dolceto"] = {["name"] = "dolceto", ["label"] = "Dolcetto D'Alba", ["weight"] = 100, ["type"] = "item", ["image"] = "dolceto.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["housered"] = {["name"] = "housered", ["label"] = "House Red Wine", ["weight"] = 100, ["type"] = "item", ["image"] = "housered.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["housewhite"] = {["name"] = "housewhite", ["label"] = "House White Wine", ["weight"] = 100, ["type"] = "item", ["image"] = "housewhite.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rosso"] = {["name"] = "rosso", ["label"] = "Rosso Del Montalcino", ["weight"] = 100, ["type"] = "item", ["image"] = "rosso.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --DESSERTS + ["tiramisu"] = {["name"] = "tiramisu", ["label"] = "Tiramisu", ["weight"] = 100, ["type"] = "item", ["image"] = "tiramisu.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["gelato"] = {["name"] = "gelato", ["label"] = "Choc and Vanilla Gelato", ["weight"] = 100, ["type"] = "item", ["image"] = "gelato.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["medfruits"] = {["name"] = "medfruits", ["label"] = "Fresh Fruit Medly", ["weight"] = 100, ["type"] = "item", ["image"] = "medfruits.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PASTA + ["bolognese"] = {["name"] = "bolognese", ["label"] = "Bolognese", ["weight"] = 100, ["type"] = "item", ["image"] = "bolognese.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["calamari"] = {["name"] = "calamari", ["label"] = "Calamari Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "calamari.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["meatball"] = {["name"] = "meatball", ["label"] = "Homemade Meatballs", ["weight"] = 100, ["type"] = "item", ["image"] = "meatball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["alla"] = {["name"] = "alla", ["label"] = "Alla Vodka", ["weight"] = 100, ["type"] = "item", ["image"] = "alla.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pescatore"] = {["name"] = "pescatore", ["label"] = "Pescatore", ["weight"] = 100, ["type"] = "item", ["image"] = "pescatore.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PIZZA SLICES + ["capricciosa"] = {["name"] = "capricciosa", ["label"] = "Capriccosa", ["weight"] = 100, ["type"] = "item", ["image"] = "capricciosa.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["diavola"] = {["name"] = "diavola", ["label"] = "Diavola", ["weight"] = 100, ["type"] = "item", ["image"] = "diavola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["marinara"] = {["name"] = "marinara", ["label"] = "Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "marinara.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["margherita"] = {["name"] = "margherita", ["label"] = "Margherita", ["weight"] = 100, ["type"] = "item", ["image"] = "margherita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["prosciuttio"] = {["name"] = "prosciuttio", ["label"] = "Prosciuttio E Funghi", ["weight"] = 100, ["type"] = "item", ["image"] = "proscuttio.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vegetariana"] = {["name"] = "vegetariana", ["label"] = "Vegetariana", ["weight"] = 100, ["type"] = "item", ["image"] = "vegetariana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PIZZA BOXES + ["capricciosabox"] = {["name"] = "capricciosabox", ["label"] = "Boxed Capriccosa", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["diavolabox"] = {["name"] = "diavolabox", ["label"] = "Boxed Diavola", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["marinarabox"] = {["name"] = "marinarabox", ["label"] = "Boxed Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["margheritabox"] = {["name"] = "margheritabox", ["label"] = "Boxed Margherita", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["prosciuttiobox"] = {["name"] = "prosciuttiobox", ["label"] = "Boxed Prosciuttio E Funghi", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["vegetarianabox"] = {["name"] = "vegetarianabox", ["label"] = "Boxed Vegetariana", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + --INGREDIENTS + ["pizzabase"] = {["name"] = "pizzabase", ["label"] = "Pizza Base", ["weight"] = 100, ["type"] = "item", ["image"] = "base2.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pizzadough"] = {["name"] = "pizzadough", ["label"] = "Pizza Dough", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzadough.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["mozz"] = {["name"] = "mozz", ["label"] = "Mozzeralla", ["weight"] = 100, ["type"] = "item", ["image"] = "mozz.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["sauce"] = {["name"] = "sauce", ["label"] = "Tomato Sauce", ["weight"] = 100, ["type"] = "item", ["image"] = "sauce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["salami"] = {["name"] = "salami", ["label"] = "Salami", ["weight"] = 100, ["type"] = "item", ["image"] = "salami.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["squid"] = {["name"] = "squid", ["label"] = "Calamari", ["weight"] = 100, ["type"] = "item", ["image"] = "squid.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pizzmushrooms"] = {["name"] = "pizzmushrooms", ["label"] = "Mushrooms", ["weight"] = 100, ["type"] = "item", ["image"] = "mushrooms.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["olives"] = {["name"] = "olives", ["label"] = "Olives", ["weight"] = 100, ["type"] = "item", ["image"] = "olives.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["basil"] = {["name"] = "basil", ["label"] = "Basil", ["weight"] = 100, ["type"] = "item", ["image"] = "basil.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["pasta"] = {["name"] = "pasta", ["label"] = "Bag of Pasta", ["weight"] = 200, ["type"] = "item", ["image"] = "pasta.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A bag of Pasta", ['created'] = nil, ["decay"] = 0.0}, + + -- osmium cameras + ['cctv'] = {['name'] = 'cctv', ['label'] = 'CCTV Camera', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'nmcctv.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Single Heading CCTV Camera (Manually Placeable)', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['360cctv'] = {['name'] = '360cctv', ['label'] = '360D CCTV Cam', ['weight'] = 10000, ['type'] = 'item', ['image'] = 'mcctv.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = '360 Degree Revolvable CCTV Camera (Manually Placeable)', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['camviewer'] = {['name'] = 'camviewer', ['label'] = 'CamViewer', ['weight'] = 7000, ['type'] = 'item', ['image'] = 'camviewer.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Remote Camera Viewer and Controller', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['pd_dashcam'] = {['name'] = 'pd_dashcam', ['label'] = 'Dash Camera [PD]', ['weight'] = 3000, ['type'] = 'item', ['image'] = 'dashcam.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Dash Cam, used for attaching to vehicles (MARKED FOR SEIZURE)', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + + -- portable chair + ["chair62"] = {["name"] = "chair62", ["label"] = "Green Camping Chair", ["weight"] = 100, ["type"] = "item", ["image"] = "np_props_lawnchair2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + ["chair63"] = {["name"] = "chair63", ["label"] = "Blue Camping Chair", ["weight"] = 100, ["type"] = "item", ["image"] = "np_props_lawnchair.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0}, + + -- jim-recycle stuff + ["recyclablematerial"] = {["name"] = "recyclablematerial", ["label"] = "Recycle Box", ["weight"] = 100, ["type"] = "item", ["image"] = "recyclablematerial.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A box of Recyclable Materials", ['created'] = nil, ["decay"] = 0.0}, + ["bottle"] = {["name"] = "bottle", ["label"] = "Empty Bottle", ["weight"] = 10, ["type"] = "item", ["image"] = "bottle.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A glass bottle", ['created'] = nil, ["decay"] = 0.0}, + ["can"] = {["name"] = "can", ["label"] = "Empty Can", ["weight"] = 10, ["type"] = "item", ["image"] = "can.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "An empty can, good for recycling", ['created'] = nil, ["decay"] = 0.0}, + + -- FAKE PLATE + ['fake_plate'] = {['name'] = 'fake_plate', ['label'] = 'Fake Plate', ['weight'] = 200, ['type'] = 'item', ['image'] = 'np_plate.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Good for hiding your identity', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- JL-BOOSTING JustLazzy + ['hacking_device'] = {['name'] = "hacking_device", ['label'] = "Hacking device", ['weight'] = 500, ['type'] = 'item', ['image'] = 'disabler.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A multi purpose hacking device", ['created'] = nil, ["decay"] = 0.0}, + + -- DeliveryBoxBruv + ["delivery-box"] = {["name"] = "delivery-box", ["label"] = "Delivery Package", ["weight"] = 10000, ["type"] = "item", ["image"] = "delivery-package.png", ["unique"] = true, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Package", ["created"] = nil, ["decay"] = 0.0}, + + -- HEIST SHIT + -- PAC BANK VAULT UPPER + ['inkedmoney'] = {['name'] = "inkedmoney", ['label'] = "Inked Money", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_inked-money-bag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Inked money bags", ['created'] = nil, ["decay"] = 0.0}, + ['thermitecharge'] = {['name'] = "thermitecharge", ['label'] = "Thermite Charge", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_thermite_charge.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "High powered thermite charge often used in criminal activity.", ['created'] = nil, ["decay"] = 0.0}, + ['redlaptop'] = {['name'] = "redlaptop", ['label'] = "Red Laptop", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_laptop04.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A red laptop used in PAC upper vault", ['created'] = nil, ["decay"] = 0.0}, + + -- PAC BANK VAULT LOWER + ['lvaultusb'] = {['name'] = "lvaultusb", ['label'] = "Lower Vault USB", ['weight'] = 500, ['type'] = 'item', ['image'] = 'lvaultusb.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Lower Vault USB Hacking Device", ['created'] = nil, ["decay"] = 0.0}, + ['lvaultusbcodes'] = {['name'] = "lvaultusbcodes", ['label'] = "Codes", ['weight'] = 500, ['type'] = 'item', ['image'] = 'lvaultusbcodes.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Vault Codes", ['created'] = nil, ["decay"] = 0.0}, + -- Vangelico Jewellery Robbery + ['goldlaptop'] = {['name'] = "goldlaptop", ['label'] = "Gold Laptop", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_laptop_prac.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A gold laptop used in PAC lower vault.", ['created'] = nil, ["decay"] = 0.0}, + ['diamond'] = {['name'] = 'diamond', ['label'] = 'Diamond', ['weight'] = 100, ['type'] = 'item', ['image'] = 'np_gallery_diamond.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Looks pretty expensive to me', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- FLEECA + ['greenlaptop'] = {['name'] = "greenlaptop", ['label'] = "Green Laptop", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_laptop03.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A green laptop used for fleecas", ['created'] = nil, ["decay"] = 0.0}, + + -- PALETO BANK + ['bluelaptop'] = {['name'] = "bluelaptop", ['label'] = "Blue Laptop", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_laptop02.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A blue laptop used for Paleto.", ['created'] = nil, ["decay"] = 0.0}, + + -- BOBCAT + ["bobcatsecuritycard"] = {["name"] = "bobcatsecuritycard", ["label"] = "Bobcat Security Card", ["weight"] = 1000, ["type"] = "item", ["image"] = "gruppe62.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Provides access to the Bobcat Security building.", ['created'] = nil, ["decay"] = 0.0}, + + -- VAR HEIST + ["var_helmet"] = {["name"] = "var_helmet", ["label"] = "VAR Headset", ["weight"] = 1000, ["type"] = "item", ["image"] = "np_var_headset.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "VAR Helmet", ['created'] = nil, ["decay"] = 0.0}, + ["var_medkit"] = {["name"] = "var_medkit", ["label"] = "CPR Medical Kit", ["weight"] = 1000, ["type"] = "item", ["image"] = "firstaid.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "VAR CPR Kit", ['created'] = nil, ["decay"] = 0.0}, + ["var_usb1"] = {["name"] = "var_usb1", ["label"] = "Master Key (25%)", ["weight"] = 1000, ["type"] = "item", ["image"] = "var_usb.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Combine multiple USBs to create a master encryption key.", ['created'] = nil, ["decay"] = 0.0}, + ["var_usb2"] = {["name"] = "var_usb2", ["label"] = "Master Key (25%)", ["weight"] = 1000, ["type"] = "item", ["image"] = "var_usb.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Combine multiple USBs to create a master encryption key.", ['created'] = nil, ["decay"] = 0.0}, + ["var_usb3"] = {["name"] = "var_usb3", ["label"] = "Master Key (25%)", ["weight"] = 1000, ["type"] = "item", ["image"] = "var_usb.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Combine multiple USBs to create a master encryption key.", ['created'] = nil, ["decay"] = 0.0}, + ["var_usb4"] = {["name"] = "var_usb4", ["label"] = "Master Key (25%)", ["weight"] = 1000, ["type"] = "item", ["image"] = "var_usb.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Combine multiple USBs to create a master encryption key.", ['created'] = nil, ["decay"] = 0.0}, + ["var_usb5"] = {["name"] = "var_usb5", ["label"] = "Master Key (100%)", ["weight"] = 1000, ["type"] = "item", ["image"] = "var_usb.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Master Key to access encrypted data.", ['created'] = nil, ["decay"] = 0.0}, + + -- OTHER LAPTOPS AND HEIST SHIT + ['golddongle'] = {['name'] = "golddongle", ['label'] = "Gold Dongle", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_heist_usb_gold.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A gold dongle used for aquiring tools.", ['created'] = nil, ["decay"] = 0.0}, + ['yellowlaptop'] = {['name'] = "yellowlaptop", ['label'] = "Yellow Laptop", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_laptop01.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A yellow laptop used for something.", ['created'] = nil, ["decay"] = 0.0}, + ['phonedongle'] = {['name'] = "phonedongle", ['label'] = "Phone Dongle", ['weight'] = 500, ['type'] = 'item', ['image'] = 'np_heist_usb_gold.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "A gold dongle used for aquiring tools.", ['created'] = nil, ["decay"] = 0.0}, + + -- BANK TRUCK ROBBERY + ["hacking-laptop"] = {["name"] = "hacking-laptop", ["label"] = "Hacking Laptop", ["weight"] = 1500, ["type"] = "item", ["image"] = "hacking-laptop.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0}, + ["gps-device"] = {["name"] = "gps-device", ["label"] = "Gps Device", ["weight"] = 1500, ["type"] = "item", ["image"] = "gps-device.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0}, + ["gps"] = {["name"] = "gps", ["label"] = "Gps", ["weight"] = 1500, ["type"] = "item", ["image"] = "gps-device.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0}, + ["kthermite"] = {["name"] = "kthermite", ["label"] = "Thermite", ["weight"] = 500, ["type"] = "item", ["image"] = "thermite.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ["created"] = nil, ["decay"] = 0.0}, + + -- Random Fun NP Items + ['wingsuit_open'] = {['name'] = "wingsuit_open", ['label'] = "Wingsuit Open", ['weight'] = 2500, ['type'] = 'item', ['image'] = 'np_wingsuit.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Falling, with style!", ['created'] = nil, ["decay"] = 0.0}, + ['wingsuit_closed'] = {['name'] = "wingsuit_closed", ['label'] = "Wingsuit Closed", ['weight'] = 2500, ['type'] = 'item', ['image'] = 'np_wingsuit.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Falling, with style!", ['created'] = nil, ["decay"] = 0.0}, + ['pailandshovel'] = {['name'] = "pailandshovel", ['label'] = "Pail & Shovel", ['weight'] = 2500, ['type'] = 'item', ['image'] = 'np_props_pail_shovel.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Do you wanna build a sand castle?", ['created'] = nil, ["decay"] = 0.0}, + + -- BEE KEEPING STUFF + ["beehive"] = {["name"] = "beehive", ["label"] = "Beehive", ["weight"] = 5000, ["type"] = "item", ["image"] = "np_beehive.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beehive"}, + ["queen_bee"] = {["name"] = "queen_bee", ["label"] = "Queen Bee", ["weight"] = 2000, ["type"] = "item", ["image"] = "np_bee_queen.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beehive"}, + ["honey"] = {["name"] = "honey", ["label"] = "Honey", ["weight"] = 2000, ["type"] = "item", ["image"] = "np_honey.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beehive"}, + ["wax"] = {["name"] = "wax", ["label"] = "Wax", ["weight"] = 2000, ["type"] = "item", ["image"] = "np_bees_wax.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beehive"}, + + -- FISHING SHIT DOJWUN + -- Regular Fish + ['stingray1'] = {['name'] = 'stingray1', ['label'] = 'Stingray', ['weight'] = 3500, ['type'] = 'item', ['image'] = 'stingray.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Stingray', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['flounder'] = {['name'] = 'flounder', ['label'] = 'Fish', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'flounder.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Flounder', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['codfish'] = {['name'] = 'codfish', ['label'] = 'Fish', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'codfish.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Cod', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['mackerel'] = {['name'] = 'mackerel', ['label'] = 'Fish', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'mackerel.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Mackerel', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['bass'] = {['name'] = 'bass', ['label'] = 'Fish', ['weight'] = 1250, ['type'] = 'item', ['image'] = 'bass.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'A normal fish Tatses pretty good!', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Trash Items + ['fishingtin'] = {['name'] = 'fishingtin', ['label'] = 'Fishing Tin', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'fishingtin.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Fishing Tin'}, + ['fishingboot'] = {['name'] = 'fishingboot', ['label'] = 'Fishing Boot', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'fishingboot.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Fishing Boot'}, + + -- Exotic Fish + ['killerwhale'] = {['name'] = 'killerwhale', ['label'] = 'Whale', ['weight'] = 14000, ['type'] = 'item', ['image'] = 'killerwhale.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Killer Whale', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['dolphin'] = {['name'] = 'dolphin', ['label'] = 'Dolphin', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'dolphin.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Dolphin', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['sharkhammer'] = {['name'] = 'sharkhammer', ['label'] = 'Shark', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'sharkhammer.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Hammerhead Shark', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['sharktiger'] = {['name'] = 'sharktiger', ['label'] = 'Shark', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'sharktiger.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = false, ['combinable'] = nil, ['description'] = 'Tigershark', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- Gear + ['fishbait'] = {['name'] = 'fishbait', ['label'] = 'Fish Bait', ['weight'] = 400, ['type'] = 'item', ['image'] = 'fishbait.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Fishing bait', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['fishingrod'] = {['name'] = 'fishingrod', ['label'] = 'Fishing Rod', ['weight'] = 750, ['type'] = 'item', ['image'] = 'fishingrod.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A fishing rod for adventures with friends!!'}, + ['anchor'] = {['name'] = 'anchor', ['label'] = 'Boat Anchor', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'anchor.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Boat Anchor'}, + ['fishicebox'] = {['name'] = 'fishicebox', ['label'] = 'Fishing Ice Chest', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'fishicebox.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Ice Box to store all of your fish'}, + + -- Fishing Rewards + ['fishingloot'] = {['name'] = 'fishingloot', ['label'] = 'Metal Box', ['weight'] = 500, ['type'] = 'item', ['image'] = 'fishingloot.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Seems to be a corroded from the salt water, Should be easy to open', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['fishinglootbig'] = {['name'] = 'fishinglootbig', ['label'] = 'Treasure Chest', ['weight'] = 2500, ['type'] = 'item', ['image'] = 'fishinglootbig.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The lock seems to be intact, Might need a key', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['fishingkey'] = {['name'] = 'fishingkey', ['label'] = 'Corroded Key', ['weight'] = 100, ['type'] = 'item', ['image'] = 'fishingkey.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A weathered key that looks usefull', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['fishtacklebox'] = {['name'] = 'fishtacklebox', ['label'] = 'Tackle Box', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'fishtacklebox.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Seems to be left over tackle box from another fisherman', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['pearlscard'] = {['name'] = 'pearlscard', ['label'] = 'Pearls Seafood', ['weight'] = 100, ['type'] = 'item', ['image'] = 'pearlscard.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A special member of Pearl\'s Seafood Restaurant'}, + + + --VANILLA UNICORN + --Drink Ingredients + ["cubasil"] = {["name"] = "cubasil", ["label"] = "Cucumber Basil", ["weight"] = 200, ["type"] = "item", ["image"] = "cubasil.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Hand full of Cucumber and Basil", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["mintleaf"] = {["name"] = "mintleaf", ["label"] = "Mint", ["weight"] = 200, ["type"] = "item", ["image"] = "mint.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Mint Leaves", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["peach"] = {["name"] = "peach", ["label"] = "Peach", ["weight"] = 200, ["type"] = "item", ["image"] = "peach.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A peach", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["strawberry"] = {["name"] = "strawberry", ["label"] = "Strawberries", ["weight"] = 200, ["type"] = "item", ["image"] = "strawberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Strawberries", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["lime"] = {["name"] = "lime", ["label"] = "Lime", ["weight"] = 200, ["type"] = "item", ["image"] = "lime.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Lime.", ['created'] = nil, ["decay"] = 0.0}, + ["lemon"] = {["name"] = "lemon", ["label"] = "Lemon", ["weight"] = 200, ["type"] = "item", ["image"] = "lemon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Lemon.", ['created'] = nil, ["decay"] = 0.0}, + + ["midori"] = {["name"] = "midori", ["label"] = "Midori", ["weight"] = 200, ["type"] = "item", ["image"] = "midori.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Midori", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pinejuice"] = {["name"] = "pinejuice", ["label"] = "Pineapple Juice", ["weight"] = 200, ["type"] = "item", ["image"] = "pinejuice.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pineapple Juice", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["prosecco"] = {["name"] = "prosecco", ["label"] = "Prosecco", ["weight"] = 200, ["type"] = "item", ["image"] = "prosecco.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Prosecco", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["tequila"] = {["name"] = "tequila", ["label"] = "Tequila", ["weight"] = 200, ["type"] = "item", ["image"] = "tequila.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Tequila", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["triplsec"] = {["name"] = "triplsec", ["label"] = "Triple Sec", ["weight"] = 200, ["type"] = "item", ["image"] = "triplesec.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Triple Sec", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["cranberry"] = {["name"] = "cranberry", ["label"] = "Cranberry Juice", ["weight"] = 200, ["type"] = "item", ["image"] = "cranberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cranberry Juice", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["gin"] = {["name"] = "gin", ["label"] = "Gin", ["weight"] = 200, ["type"] = "item", ["image"] = "gin.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Gin", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rum"] = {["name"] = "rum", ["label"] = "Rum", ["weight"] = 200, ["type"] = "item", ["image"] = "rum.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Rum", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["amaretto"] = {["name"] = "amaretto", ["label"] = "Amaretto", ["weight"] = 200, ["type"] = "item", ["image"] = "amaretto.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Amaretto", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Cocktails + ["amarettosour"] = {["name"] = "amarettosour", ["label"] = "Amaretto Sour", ["weight"] = 200, ["type"] = "item", ["image"] = "amarettosour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Amaretto Sour", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bellini"] = {["name"] = "bellini", ["label"] = "Bellini", ["weight"] = 200, ["type"] = "item", ["image"] = "bellini.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bellini", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cosmopolitan"] = {["name"] = "cosmopolitan", ["label"] = "Cosmopolitan", ["weight"] = 200, ["type"] = "item", ["image"] = "cosmopolitan.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cosmopolitan", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["longisland"] = {["name"] = "longisland", ["label"] = "Long Island Ice tea", ["weight"] = 200, ["type"] = "item", ["image"] = "longisland.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Long Island Ice Tea", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["margarita"] = {["name"] = "margarita", ["label"] = "Margarita", ["weight"] = 200, ["type"] = "item", ["image"] = "margarita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Margarita", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pinacolada"] = {["name"] = "pinacolada", ["label"] = "Pina Colada", ["weight"] = 200, ["type"] = "item", ["image"] = "pinacolada.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pine Colada", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sangria"] = {["name"] = "sangria", ["label"] = "Sangria", ["weight"] = 200, ["type"] = "item", ["image"] = "sangria.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sangria", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["screwdriver"] = {["name"] = "screwdriver", ["label"] = "Screwdriver", ["weight"] = 200, ["type"] = "item", ["image"] = "screwdriver.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Screwdriver", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["strawdaquiri"] = {["name"] = "strawdaquiri", ["label"] = "Strawberry Daquiri", ["weight"] = 200, ["type"] = "item", ["image"] = "strawdaquiri.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Strawberry Daquiri", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["strawmargarita"] = {["name"] = "strawmargarita", ["label"] = "Strawberry Margarita", ["weight"] = 200, ["type"] = "item", ["image"] = "strawmargarita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Starberry Margarita", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --BEERS + ["dusche"] = {["name"] = "dusche", ["label"] = "Dusche Gold", ["weight"] = 100, ["type"] = "item", ["image"] = "dusche.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["logger"] = {["name"] = "logger", ["label"] = "Logger Beer", ["weight"] = 100, ["type"] = "item", ["image"] = "logger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser"] = {["name"] = "pisswasser", ["label"] = "Pißwasser", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser2"] = {["name"] = "pisswasser2", ["label"] = "Pißwasser Stout", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser3"] = {["name"] = "pisswasser3", ["label"] = "Pißwasser Pale Ale", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Food + ["nplate"] = {["name"] = "nplate", ["label"] = "Nachos Plate", ["weight"] = 200, ["type"] = "item", ["image"] = "nplate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A plate of nachos and cheese", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vusliders"] = {["name"] = "vusliders", ["label"] = "Sliders", ["weight"] = 200, ["type"] = "item", ["image"] = "sliders.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Sliders", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vutacos"] = {["name"] = "vutacos", ["label"] = "Tacos", ["weight"] = 200, ["type"] = "item", ["image"] = "tacos.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Tacos", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["tots"] = {["name"] = "tots", ["label"] = "Tits or Tots", ["weight"] = 200, ["type"] = "item", ["image"] = "tots.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Sexy Tots", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Food Ingredients + ["nachos"] = {["name"] = "nachos", ["label"] = "Nachos", ["weight"] = 200, ["type"] = "item", ["image"] = "nachos.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bag of Nachos", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["potato"] = {["name"] = "potato", ["label"] = "Potatoes", ["weight"] = 500, ["type"] = "item", ["image"] = "potatoes.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Food", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Ingredients + ["jimsausages"] = {["name"] = "jimsausages", ["label"] = "Sausages", ["weight"] = 100, ["type"] = "item", ["image"] = "jimsausages.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["jimeggs"] = {["name"] = "jimeggs", ["label"] = "Eggs", ["weight"] = 100, ["type"] = "item", ["image"] = "jimeggs.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ham"] = {["name"] = "ham", ["label"] = "Ham", ["weight"] = 100, ["type"] = "item", ["image"] = "ham.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["fish"] = {["name"] = "fish", ["label"] = "CatFish", ["weight"] = 200, ["type"] = "item", ["image"] = "fish.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Catfish", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["meat"] = {["name"] = "meat", ["label"] = "Meat", ["weight"] = 200, ["type"] = "item", ["image"] = "meat.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A slab of Meat", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["lettuce"] = {["name"] = "lettuce", ["label"] = "Lettuce", ["weight"] = 100, ["type"] = "item", ["image"] = "lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Some big taco brother", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cheddar"] = {["name"] = "cheddar", ["label"] = "Cheddar Slice", ["weight"] = 500, ["type"] = "item", ["image"] = "cheddar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Slice of Cheese", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- jim tequila + --Cocktails + ["b52"] = {["name"] = "b52", ["label"] = "B-52", ["weight"] = 200, ["type"] = "item", ["image"] = "b52.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "B-52 Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["brussian"] = {["name"] = "brussian", ["label"] = "Black Russian", ["weight"] = 200, ["type"] = "item", ["image"] = "brussian.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Black Russian Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bkamikaze"] = {["name"] = "bkamikaze", ["label"] = "Blue Kamikaze", ["weight"] = 200, ["type"] = "item", ["image"] = "bkamikaze.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Blue Kamikaze Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cappucc"] = {["name"] = "cappucc", ["label"] = "Cappuccinotini", ["weight"] = 200, ["type"] = "item", ["image"] = "cappucc.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cappuccinotini Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ccookie"] = {["name"] = "ccookie", ["label"] = "Cranberry Cookie", ["weight"] = 200, ["type"] = "item", ["image"] = "ccookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cranberry Cookie Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["iflag"] = {["name"] = "iflag", ["label"] = "Irish Flag", ["weight"] = 200, ["type"] = "item", ["image"] = "iflag.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Irish Flag Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["kamikaze"] = {["name"] = "kamikaze", ["label"] = "Kamikaze", ["weight"] = 200, ["type"] = "item", ["image"] = "kamikaze.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Kamikase Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sbullet"] = {["name"] = "sbullet", ["label"] = "Silver Bullet", ["weight"] = 200, ["type"] = "item", ["image"] = "sbullet.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Silver Bullet Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["voodoo"] = {["name"] = "voodoo", ["label"] = "Voodoo", ["weight"] = 200, ["type"] = "item", ["image"] = "voodoo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Voodoo Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["woowoo"] = {["name"] = "woowoo", ["label"] = "Woo Woo", ["weight"] = 200, ["type"] = "item", ["image"] = "woowoo.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Woowoo Cocktail", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Drink Ingredients + ["orange"] = {["name"] = "orange", ["label"] = "Orange", ["weight"] = 200, ["type"] = "item", ["image"] = "orange.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "An Orange.", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["lime"] = {["name"] = "lime", ["label"] = "Lime", ["weight"] = 200, ["type"] = "item", ["image"] = "lime.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Lime.", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["chocolate"] = {["name"] = "chocolate", ["label"] = "Chocolate", ["weight"] = 200, ["type"] = "item", ["image"] = "chocolate.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Chocolate Bar", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["cranberry"] = {["name"] = "cranberry", ["label"] = "Cranberry Juice", ["weight"] = 200, ["type"] = "item", ["image"] = "cranberry.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cranberry Juice", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["schnapps"] = {["name"] = "schnapps", ["label"] = "Peach Schnapps", ["weight"] = 200, ["type"] = "item", ["image"] = "schnapps.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Peach Schnapps", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["gin"] = {["name"] = "gin", ["label"] = "Gin", ["weight"] = 200, ["type"] = "item", ["image"] = "gin.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Gin", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["scotch"] = {["name"] = "scotch", ["label"] = "Scotch", ["weight"] = 200, ["type"] = "item", ["image"] = "scotch.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Scotch", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rum"] = {["name"] = "rum", ["label"] = "Rum", ["weight"] = 200, ["type"] = "item", ["image"] = "rum.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Rum", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["icream"] = {["name"] = "icream", ["label"] = "Irish Cream", ["weight"] = 200, ["type"] = "item", ["image"] = "icream.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Irish Cream Liquer", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["amaretto"] = {["name"] = "amaretto", ["label"] = "Amaretto", ["weight"] = 200, ["type"] = "item", ["image"] = "amaretto.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Amaretto", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["curaco"] = {["name"] = "curaco", ["label"] = "Curaco", ["weight"] = 200, ["type"] = "item", ["image"] = "curaco.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bottle of Curaco", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --BEERS + ["ambeer"] = {["name"] = "ambeer", ["label"] = "AM Beer", ["weight"] = 100, ["type"] = "item", ["image"] = "ambeer.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["dusche"] = {["name"] = "dusche", ["label"] = "Dusche Gold", ["weight"] = 100, ["type"] = "item", ["image"] = "dusche.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["logger"] = {["name"] = "logger", ["label"] = "Logger Beer", ["weight"] = 100, ["type"] = "item", ["image"] = "logger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser"] = {["name"] = "pisswasser", ["label"] = "Pißwasser", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser2"] = {["name"] = "pisswasser2", ["label"] = "Pißwasser Stout", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pisswasser3"] = {["name"] = "pisswasser3", ["label"] = "Pißwasser Pale Ale", ["weight"] = 100, ["type"] = "item", ["image"] = "pisswaser3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --SODA + ["sprunk"] = {["name"] = "sprunk", ["label"] = "Sprunk", ["weight"] = 100, ["type"] = "item", ["image"] = "sprunk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sprunklight"] = {["name"] = "sprunklight", ["label"] = "Sprunk Light", ["weight"] = 100, ["type"] = "item", ["image"] = "sprunklight.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ecola"] = {["name"] = "ecola", ["label"] = "eCola", ["weight"] = 100, ["type"] = "item", ["image"] = "ecola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30)}, + ["ecolalight"] = {["name"] = "ecolalight", ["label"] = "eCola Light", ["weight"] = 100, ["type"] = "item", ["image"] = "ecolalight.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + + + + + ---- Jim Beanmachine + ["beancoffee"] = {["name"] = "beancoffee", ["label"] = "Coffe Beans", ["weight"] = 100, ["type"] = "item", ["image"] = "beancoffee.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["beandonut"] = {["name"] = "beandonut", ["label"] = "Donut", ["weight"] = 100, ["type"] = "item", ["image"] = "popdonut.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rhinohorn"] = {["name"] = "rhinohorn", ["label"] = "Rhino Horn", ["weight"] = 100, ["type"] = "item", ["image"] = "rhinohorn.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["oystershell"] = {["name"] = "oystershell", ["label"] = "Oyster Shell", ["weight"] = 100, ["type"] = "item", ["image"] = "oyster.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["watermelon"] = {["name"] = "watermelon", ["label"] = "WaterMelon Slice", ["weight"] = 100, ["type"] = "item", ["image"] = "watermelon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["bigfruit"] = {["name"] = "bigfruit", ["label"] = "The Big Fruit", ["weight"] = 100, ["type"] = "item", ["image"] = "bigfruit.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["highnoon"] = {["name"] = "highnoon", ["label"] = "Highnoon", ["weight"] = 100, ["type"] = "item", ["image"] = "highnoon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["speedball"] = {["name"] = "speedball", ["label"] = "The SpeedBall", ["weight"] = 100, ["type"] = "item", ["image"] = "speedball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["gunkaccino"] = {["name"] = "gunkaccino", ["label"] = "The Gunkaccino", ["weight"] = 100, ["type"] = "item", ["image"] = "gunkaccino.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bratte"] = {["name"] = "bratte", ["label"] = "The Bratte", ["weight"] = 100, ["type"] = "item", ["image"] = "bratte.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["flusher"] = {["name"] = "flusher", ["label"] = "The Flusher", ["weight"] = 100, ["type"] = "item", ["image"] = "flusher.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ecocoffee"] = {["name"] = "ecocoffee", ["label"] = "The Eco-ffee", ["weight"] = 100, ["type"] = "item", ["image"] = "ecoffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["caffeagra"] = {["name"] = "caffeagra", ["label"] = "Caffeagra", ["weight"] = 100, ["type"] = "item", ["image"] = "caffeagra.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["chocolate"] = {["name"] = "chocolate", ["label"] = "Chocolate", ["weight"] = 200, ["type"] = "item", ["image"] = "chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Chocolate Bar", ['hunger'] = math.random(10, 20), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cheesecake"] = {["name"] = "cheesecake", ["label"] = "Cheese Cake", ["weight"] = 100, ["type"] = "item", ["image"] = "cheesecake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["crisps"] = {["name"] = "crisps", ["label"] = "Crisps", ["weight"] = 100, ["type"] = "item", ["image"] = "chips.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sugar"] = {["name"] = "sugar", ["label"] = "Sugar", ["weight"] = 100, ["type"] = "item", ["image"] = "sugar.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(10, 20), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["orange"] = {["name"] = "orange", ["label"] = "Orange", ["weight"] = 200, ["type"] = "item", ["image"] = "orange.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "An Orange.", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["milk"] = {["name"] = "milk", ["label"] = "Milk", ["weight"] = 300, ["type"] = "item", ["image"] = "burger-milk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Carton of Milk", ['thirst'] = math.random(10, 20), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["chickenbreast"] = {["name"] = "chickenbreast", ["label"] = "Chicken Breast", ["weight"] = 100, ["type"] = "item", ["image"] = "chickenbreast.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(10, 20), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + -- Billiard + ["glasscup"] = {["name"] = "glasscup", ["label"] = "Glass Cup", ["weight"] = 400, ["type"] = "item", ["image"] = "glasscup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Glass Cup"}, + ["smallglasscup"] = {["name"] = "smallglasscup", ["label"] = "Small Glass Cup", ["weight"] = 400, ["type"] = "item", ["image"] = "smallglasscup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Small Glass Cup"}, + ["coffeecup"] = {["name"] = "coffeecup", ["label"] = "Empty Coffee Bottle", ["weight"] = 400, ["type"] = "item", ["image"] = "coffeecup.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Empty Coffee Bottle"}, + ["coffeebeans"] = {["name"] = "coffeebeans", ["label"] = "Regular Coffee Beans", ["weight"] = 400, ["type"] = "item", ["image"] = "coffeebeans.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Regular Coffee Beans"}, + + -- ATM ROBBERY + ['towingrope'] = {['name'] = 'towingrope', ['label'] = 'Towing Rope', ['weight'] = 200, ['type'] = 'item', ['image'] = 'expert_towingrope.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Towing Rope'}, + ['atmobject'] = {['name'] = 'atmobject', ['label'] = 'ATM', ['weight'] = 200, ['type'] = 'item', ['image'] = 'expert_atmobj.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'ATM'}, + + + -- Up N Atoms + -- Breakfast + ["atoms-bacon-eggs"] = {["name"] = "atoms-bacon-eggs", ["label"] = "Atoms Bacon n Eggs", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bacon-eggs.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Bacon n Eggs with Toast", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-bacon-rolls"] = {["name"] = "atoms-bacon-rolls", ["label"] = "Atoms Bacon Rolls", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bacon-rolls.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Bacon Rolls", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-eggs-benedict"] = {["name"] = "atoms-eggs-benedict", ["label"] = "Atoms Egg Benedict", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-eggs-benedict.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Eggs Benedict", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-eggs-florentine"] = {["name"] = "atoms-eggs-florentine", ["label"] = "Atoms Egg Florentine", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-eggs-florentine.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Eggs Florentine", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-french-toast-bacon"] = {["name"] = "atoms-french-toast-bacon", ["label"] = "Atoms French Toast", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-french-toast-bacon.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked French Toast With Bacon", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-hashbrown"] = {["name"] = "atoms-hashbrown", ["label"] = "Atoms Hashbrowns", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-hashbrown.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Hashbrowns", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-sausages"] = {["name"] = "atoms-sausages", ["label"] = "Atoms Sausages", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-sausages.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cooked Sausages", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Burgers + ["atoms-bacon-burger"] = {["name"] = "atoms-bacon-burger", ["label"] = "Atoms Bacon Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bacon-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Bacon Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-burger"] = {["name"] = "atoms-burger", ["label"] = "Atoms Cheese Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Classic Cheese Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-burger"] = {["name"] = "atoms-chicken-burger", ["label"] = "Atoms Chicken Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Chicken Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-db-burger"] = {["name"] = "atoms-db-burger", ["label"] = "Atoms Double Cheese Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-db-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Double Cheese Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-db-chicken-burger"] = {["name"] = "atoms-db-chicken-burger", ["label"] = "Atoms Double Chicken Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-db-chicken-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Double Chicken Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-pickle-burger"] = {["name"] = "atoms-pickle-burger", ["label"] = "Atoms Pickle Burger", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-pickle-burger.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Pickle Burger", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-sandwich"] = {["name"] = "atoms-sandwich", ["label"] = "Atoms Ham Sandwich", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-sandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Classic Ham Sandwich", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Chicken + ["atoms-chicken-fillets"] = {["name"] = "atoms-chicken-fillets", ["label"] = "Atoms Chicken Fillets", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-fillets.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Fillets", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-salad"] = {["name"] = "atoms-chicken-salad", ["label"] = "Atoms Chicken Salad", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-salad.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Salad", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-sandwich"] = {["name"] = "atoms-chicken-sandwich", ["label"] = "Atoms Chicken Sandwich", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-sandwich.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Classic Chicken Sandwich", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-stars"] = {["name"] = "atoms-chicken-stars", ["label"] = "Atoms Chicken Stars", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-stars.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Nuggets In The Shape Of A Star", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-grilled-chicken"] = {["name"] = "atoms-grilled-chicken", ["label"] = "Atoms Grilled Chicken", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-grilled-chicken.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Grilled Chicken Fillets", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-hunk-o-hen"] = {["name"] = "atoms-hunk-o-hen", ["label"] = "Atoms Hunks O Hen", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-hunk-o-hen.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Chunks", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Drinks + ["atoms-ecola"] = {["name"] = "atoms-ecola", ["label"] = "Atoms Ecola", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-ecola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ecola!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-hercules"] = {["name"] = "atoms-hercules", ["label"] = "Atoms Hercules", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-hercules.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Hercules!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-junk"] = {["name"] = "atoms-junk", ["label"] = "Atoms Junk Energy!", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-junk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Junk Energy!!!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-orangtang"] = {["name"] = "atoms-orangtang", ["label"] = "Atoms Orang O Tang", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-orangtang.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "OrangTang!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-raine"] = {["name"] = "atoms-raine", ["label"] = "Atoms Raine Water", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-raine.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ice Cold Water Bottle", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-sprunk"] = {["name"] = "atoms-sprunk", ["label"] = "Atoms Sprunk", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-sprunk.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Spunk!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-water"] = {["name"] = "atoms-water", ["label"] = "Atoms Water Bottle", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-water.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ice Cold Water Bottle", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Ingredients + ["atoms-bacon"] = {["name"] = "atoms-bacon", ["label"] = "Atoms Cooked Bacon", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bacon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-beef-patty"] = {["name"] = "atoms-beef-patty", ["label"] = "Atoms Cooked Beef Patty", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-beef-patty.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-bread"] = {["name"] = "atoms-bread", ["label"] = "Atoms Fresh Bread", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bread.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-bun"] = {["name"] = "atoms-bun", ["label"] = "Atoms Fresh Bun", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-bun.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-cheddar-cheese-slices"] = {["name"] = "atoms-cheddar-cheese-slices", ["label"] = "Atoms Fresh Cheddar Cheese", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-cheddar-cheese-slices.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-patty"] = {["name"] = "atoms-chicken-patty", ["label"] = "Atoms Cooked Chicken Patty", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-patty.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-slices"] = {["name"] = "atoms-chicken-slices", ["label"] = "Atoms Fresh Chicken Slices", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken-slices.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken"] = {["name"] = "atoms-chicken", ["label"] = "Atoms Cooked Chicken", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-eggs"] = {["name"] = "atoms-eggs", ["label"] = "Atoms Fresh Eggs", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-eggs.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-english-muffin"] = {["name"] = "atoms-english-muffin", ["label"] = "Atoms English Muffin", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-english-muffin.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-frozen-sausages"] = {["name"] = "atoms-frozen-sausages", ["label"] = "Atoms Frozen Sausages", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-frozen-sausages.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-ham-slices"] = {["name"] = "atoms-ham-slices", ["label"] = "Atoms Fresh Ham Slices", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-ham-slices.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-lettuce"] = {["name"] = "atoms-lettuce", ["label"] = "Atoms Fresh Lettuce", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-mozzarella-cheese-slices"] = {["name"] = "atoms-mozzarella-cheese-slices", ["label"] = "Atoms Fresh Mozzarella Cheese", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-mozzarella-cheese-slices.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-pickles"] = {["name"] = "atoms-pickles", ["label"] = "Atoms Fresh Pickles", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-pickles.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-potatos"] = {["name"] = "atoms-potatos", ["label"] = "Atoms Fresh Potatos", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-potatos.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-raw-bacon"] = {["name"] = "atoms-raw-bacon", ["label"] = "Atoms Frozen Bacon", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-raw-bacon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-raw-beef-patty"] = {["name"] = "atoms-raw-beef-patty", ["label"] = "Atoms Frozen Beef Patty", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-raw-beef-patty.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-raw-chicken-patty"] = {["name"] = "atoms-raw-chicken-patty", ["label"] = "Atoms Frozen Chicken Patty", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-raw-chicken-patty.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-raw-chicken"] = {["name"] = "atoms-raw-chicken", ["label"] = "Atoms Frozen Chicken", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-raw-chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-spinach"] = {["name"] = "atoms-spinach", ["label"] = "Atoms Fresh Spinach", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-spinach.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-tomato"] = {["name"] = "atoms-tomato", ["label"] = "Atoms Fresh Tomato", ["weight"] = 250, ["type"] = "item", ["image"] = "atoms-tomato.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient!", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Meal Deal Packages + ["atoms-bacon-burger-meal"] = {["name"] = "atoms-bacon-burger-meal", ["label"] = "Atoms Bacon Burger Meal", ["weight"] = 300, ["type"] = "item", ["image"] = "atoms-bacon-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Bacon Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-burger-meal"] = {["name"] = "atoms-burger-meal", ["label"] = "Atoms Burger Meal", ["weight"] = 300, ["type"] = "item", ["image"] = "atoms-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Classic Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-chicken-burger-meal"] = {["name"] = "atoms-chicken-burger-meal", ["label"] = "Atoms Chicken Burger Meal", ["weight"] = 300, ["type"] = "item", ["image"] = "atoms-chicken-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Classic Chicken Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-db-burger-meal"] = {["name"] = "atoms-db-burger-meal", ["label"] = "Atoms Double Burger Meal", ["weight"] = 450, ["type"] = "item", ["image"] = "atoms-db-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Double Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-db-chicken-burger-meal"] = {["name"] = "atoms-db-chicken-burger-meal", ["label"] = "Atoms Double Chicken Burger Meal", ["weight"] = 450, ["type"] = "item", ["image"] = "atoms-db-chicken-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Double Chicken Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["atoms-pickle-burger-meal"] = {["name"] = "atoms-pickle-burger-meal", ["label"] = "Atoms Pickle Burger Meal", ["weight"] = 300, ["type"] = "item", ["image"] = "atoms-pickle-burger-meal.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Contains A Pickle Burger, Hashbrown and a Drink", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- HUNTING + ["meatdeer"] = {["name"] = "meatdeer", ["label"] = "Deer Horns", ["weight"] = 100, ["type"] = "item", ["image"] = "deerhorns.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Deer Horns"}, + ["meatpig"] = {["name"] = "meatpig", ["label"] = "Pig Meat", ["weight"] = 100, ["type"] = "item", ["image"] = "pigpelt.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Pig Meat"}, + ["meatboar"] = {["name"] = "meatboar", ["label"] = "Boar Tusks", ["weight"] = 100, ["type"] = "item", ["image"] = "boartusks.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Boar Tusks"}, + ["meatlion"] = {["name"] = "meatlion", ["label"] = "Cougar Claws", ["weight"] = 100, ["type"] = "item", ["image"] = "cougarclaw.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Cougar Claw"}, + ["meatcow"] = {["name"] = "meatcow", ["label"] = "Cow Pelt", ["weight"] = 100, ["type"] = "item", ["image"] = "cowpelt.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Cow Pelt"}, + ["cowpelt"] = {["name"] = "cowpelt", ["label"] = "Cow Pelt", ["weight"] = 100, ["type"] = "item", ["image"] = "cowpelt.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Cow Pelt"}, + ["meatrabbit"] = {["name"] = "meatrabbit", ["label"] = "Rabbit Fur", ["weight"] = 100, ["type"] = "item", ["image"] = "rabbitfur.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Rabbit Fur"}, + ["meatbird"] = {["name"] = "meatbird", ["label"] = "Bird Feather", ["weight"] = 100, ["type"] = "item", ["image"] = "birdfeather.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Bird Feather"}, + ["meatcoyote"] = {["name"] = "meatcoyote", ["label"] = "Coyote Pelt", ["weight"] = 100, ["type"] = "item", ["image"] = "coyotepelt.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Coyote Pelt"}, + ["huntingbait"] = {["name"] = "huntingbait", ["label"] = "Hunting Bait", ["weight"] = 150, ["type"] = "item", ["image"] = "huntingbait.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Hunting Bait"}, + + -- QB-BEANMACHINE + --Drinks + ["bean-cafe"] = {["name"] = "bean-cafe", ["label"] = "Coffee", ["weight"] = 1000, ["type"] = "item", ["image"] = "coffee.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Coffee", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bean-latte"] = {["name"] = "bean-latte", ["label"] = "Latte", ["weight"] = 1000, ["type"] = "item", ["image"] = "latte.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Latte", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bean-cappuccino"] = {["name"] = "bean-cappuccino", ["label"] = "Cappuccino", ["weight"] = 1000, ["type"] = "item", ["image"] = "cappuccino.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cappuccino", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bean-mocha"] = {["name"] = "bean-mocha", ["label"] = "Mocha", ["weight"] = 1000, ["type"] = "item", ["image"] = "mocha.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Mocha", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bean-cmilkshake"] = {["name"] = "bean-cmilkshake", ["label"] = "Chocolate Milkshake", ["weight"] = 1000, ["type"] = "item", ["image"] = "cmilkshake.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chocolate Milkshake", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bean-icetea"] = {["name"] = "bean-icetea", ["label"] = "Ice Tea", ["weight"] = 1000, ["type"] = "item", ["image"] = "icetea.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Icetea", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --Foods + ["cookie"] = {["name"] = "cookies", ["label"] = "Cookie", ["weight"] = 500, ["type"] = "item", ["image"] = "cookies.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cookies", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["donut"] = {["name"] = "donut", ["label"] = "Donut", ["weight"] = 500, ["type"] = "item", ["image"] = "donut.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Donut", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["croissant"] = {["name"] = "croissant", ["label"] = "Croissant", ["weight"] = 500, ["type"] = "item", ["image"] = "croissant.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Croissant", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cupchocolate"] = {["name"] = "cupchocolate", ["label"] = "Chocolate Cupcake", ["weight"] = 500, ["type"] = "item", ["image"] = "cupchocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chocolate Cupcake", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --Ingrediants + ["cocabeans"] = {["name"] = "cocabeans", ["label"] = "Coca Beans", ["weight"] = 100, ["type"] = "item", ["image"] = "cocabeans.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Coca Beans", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["chocolate"] = {["name"] = "chocolate", ["label"] = "Chocolate", ["weight"] = 100, ["type"] = "item", ["image"] = "chocolate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chocolate", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["whipcream"] = {["name"] = "whipcream", ["label"] = "Whipcream", ["weight"] = 100, ["type"] = "item", ["image"] = "whipcream.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Whipcream", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["milkbottle"] = {["name"] = "milkbottle", ["label"] = "Milk Bottle", ["weight"] = 100, ["type"] = "item", ["image"] = "milkbottle.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Milk Bottle", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["teabag"] = {["name"] = "teabag", ["label"] = "Tea Bag", ["weight"] = 100, ["type"] = "item", ["image"] = "teabag.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Tea Bag", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sprinkles"] = {["name"] = "sprinkles", ["label"] = "Sprinkles", ["weight"] = 100, ["type"] = "item", ["image"] = "sprinkles.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sprinkles", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + -- Vangelico Heist + ['paintingg'] = {['name'] = 'paintingg', ['label'] = 'Painting G', ['weight'] = 120, ['type'] = 'item', ['image'] = 'paintingg.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Painting G'}, + ['paintingf'] = {['name'] = 'paintingf', ['label'] = 'Painting F', ['weight'] = 120, ['type'] = 'item', ['image'] = 'paintingf.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Painting F'}, + ['paintingh'] = {['name'] = 'paintingh', ['label'] = 'Painting H', ['weight'] = 120, ['type'] = 'item', ['image'] = 'paintingh.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Painting H'}, + ['paintingj'] = {['name'] = 'paintingj', ['label'] = 'Painting J', ['weight'] = 120, ['type'] = 'item', ['image'] = 'paintingj.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Painting J'}, + + ['vanDiamond'] = {['name'] = 'vanDiamond', ['label'] = 'Van Diamond', ['weight'] = 120, ['type'] = 'item', ['image'] = 'vandiamond.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Van Diamond'}, + ['vanPanther'] = {['name'] = 'vanPanther', ['label'] = 'Van Panther', ['weight'] = 120, ['type'] = 'item', ['image'] = 'vanpanther.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Van Panther'}, + ['vanNecklace'] = {['name'] = 'vanNecklace', ['label'] = 'Van Necklace', ['weight'] = 120, ['type'] = 'item', ['image'] = 'vannecklace.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Van Necklace'}, + ['vanBottle'] = {['name'] = 'vanBottle', ['label'] = 'Van Bottle', ['weight'] = 120, ['type'] = 'item', ['image'] = 'vanbottle.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Van Bottle'}, + + + -- Cigarettes + ['redwoodcigs'] = {['name'] = 'redwoodcigs', ['label'] = 'Redwood Cigarettes', ['weight'] = 250, ["degrade"] = 1.0, ['type'] = 'item', ['image'] = 'redwoodcigs.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pack of Cigarettes, Made in USA', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cardiaquecigs'] = {['name'] = 'cardiaquecigs', ['label'] = 'Cardiaque Cigarettes', ['weight'] = 250, ["degrade"] = 1.0, ['type'] = 'item', ['image'] = 'cardiaquecigs.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pack of Cigarettes, Made in USA', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['yukoncigs'] = {['name'] = 'yukoncigs', ['label'] = 'Yukon Cigarettes', ['weight'] = 250, ["degrade"] = 1.0, ['type'] = 'item', ['image'] = 'yukoncigs.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Pack of Menthol Cigarettes, Made in USA', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cigarette"] = {["name"] = "cigarette", ["label"] = "Cigarette", ["weight"] = 250, ["type"] = "item", ["image"] = "cigarette.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Smokeable Tobacco", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- GUNRACK + ["policegunrack"] = { + ["name"] = "policegunrack", + ["label"] = "Police Gun Rack", + ["weight"] = 15000, + ["type"] = "item", + ["image"] = "policegunrack.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Gun rack for police vehicles", + ['created'] = nil + }, + -- optional if you want to open rack by keys + ["gunrackkey"] = { + ["name"] = "gunrackkey", + ["label"] = "Police Gun Key", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "gunrackkey.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "A key to open gun rack", + ['created'] = nil + }, + ["keycuttingmachine"] = { + ["name"] = "keycuttingmachine", + ["label"] = "Key Cutting Machine", + ["weight"] = 40000, + ["type"] = "item", + ["image"] = "keycuttingmachine.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "A Machine to Cut Keys", + ['created'] = nil + }, + + ["backpack1"] = { + ["name"] = "backpack1", + ["label"] = "Backpack 1", + ["weight"] = 10000, + ["type"] = "item", + ["image"] = "backpack_girl.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Backpack", + ['created'] = nil + }, + ["backpack2"] = { + ["name"] = "backpack2", + ["label"] = "Backpack 2", + ["weight"] = 10000, + ["type"] = "item", + ["image"] = "backpack_boy.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Backpack", + ['created'] = nil + }, + ["briefcase"] = { + ["name"] = "briefcase", + ["label"] = "Briefcase", + ["weight"] = 10000, + ["type"] = "item", + ["image"] = "briefcase.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Briefcase", + ['created'] = nil + }, + ["paramedicbag"] = { + ["name"] = "paramedicbag", + ["label"] = "Paramedic bag", + ["weight"] = 10000, + ["type"] = "item", + ["image"] = "paramedic_bag.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Paramedic bag", + ['created'] = nil + }, + + --camera + ["camera"] = {["name"] = "camera", ["label"] = "Camera", ["weight"] = 1000, ["type"] = "item", ["image"] = "camera.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil}, + ["photo"] = {["name"] = "photo", ["label"] = "Photo", ["weight"] = 20, ["type"] = "item", ["image"] = "photo.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil}, + + --Cocktails + ["amarettosour"] = {["name"] = "amarettosour", ["label"] = "Amaretto Sour", ["weight"] = 200, ["type"] = "item", ["image"] = "amarettosour.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Amaretto Sour", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["bellini"] = {["name"] = "bellini", ["label"] = "Bellini", ["weight"] = 200, ["type"] = "item", ["image"] = "bellini.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Bellini", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cosmopolitan"] = {["name"] = "cosmopolitan", ["label"] = "Cosmopolitan", ["weight"] = 200, ["type"] = "item", ["image"] = "cosmopolitan.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Cosmopolitan", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["longisland"] = {["name"] = "longisland", ["label"] = "Long Island Ice tea", ["weight"] = 200, ["type"] = "item", ["image"] = "longisland.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Long Island Ice Tea", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["margarita"] = {["name"] = "margarita", ["label"] = "Margarita", ["weight"] = 200, ["type"] = "item", ["image"] = "margarita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Margarita", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pinacolada"] = {["name"] = "pinacolada", ["label"] = "Pina Colada", ["weight"] = 200, ["type"] = "item", ["image"] = "pinacolada.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Pine Colada", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sangria"] = {["name"] = "sangria", ["label"] = "Sangria", ["weight"] = 200, ["type"] = "item", ["image"] = "sangria.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sangria", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["screwdriver"] = {["name"] = "screwdriver", ["label"] = "Screwdriver", ["weight"] = 200, ["type"] = "item", ["image"] = "screwdriver.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Screwdriver", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["strawdaquiri"] = {["name"] = "strawdaquiri", ["label"] = "Strawberry Daquiri", ["weight"] = 200, ["type"] = "item", ["image"] = "strawdaquiri.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Strawberry Daquiri", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["strawmargarita"] = {["name"] = "strawmargarita", ["label"] = "Strawberry Margarita", ["weight"] = 200, ["type"] = "item", ["image"] = "strawmargarita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Starberry Margarita", ['thirst'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --BEERS + --SODA + ["crisps"] = {["name"] = "crisps", ["label"] = "Crisps", ["weight"] = 100, ["type"] = "item", ["image"] = "chips.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Food + ["nplate"] = {["name"] = "nplate", ["label"] = "Nachos Plate", ["weight"] = 200, ["type"] = "item", ["image"] = "nplate.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A plate of nachos and cheese", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vusliders"] = {["name"] = "vusliders", ["label"] = "Sliders", ["weight"] = 200, ["type"] = "item", ["image"] = "sliders.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sliders", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vutacos"] = {["name"] = "vutacos", ["label"] = "Tacos", ["weight"] = 200, ["type"] = "item", ["image"] = "tacos.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Tacos", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["tots"] = {["name"] = "tots", ["label"] = "Tits or Tots", ["weight"] = 200, ["type"] = "item", ["image"] = "tots.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Sexy Tots", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + --Food Ingredients + ["meat"] = {["name"] = "meat", ["label"] = "Meat", ["weight"] = 200, ["type"] = "item", ["image"] = "meat.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A slab of Meat", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["nachos"] = {["name"] = "nachos", ["label"] = "Nachos", ["weight"] = 200, ["type"] = "item", ["image"] = "nachos.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "A bag of Nachos", ['hunger'] = math.random(40, 50), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["lettuce"] = {["name"] = "lettuce", ["label"] = "Lettuce", ["weight"] = 100, ["type"] = "item", ["image"] = "lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Some big taco brother", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["cheddar"] = {["name"] = "cheddar", ["label"] = "Cheddar Slice", ["weight"] = 500, ["type"] = "item", ["image"] = "cheddar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Food", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["potato"] = {["name"] = "potato", ["label"] = "Potatoes", ["weight"] = 500, ["type"] = "item", ["image"] = "potatoes.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Food", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + --SODA + --WINES + ["amarone"] = {["name"] = "amarone", ["label"] = "Amarone", ["weight"] = 100, ["type"] = "item", ["image"] = "amarone.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["barbera"] = {["name"] = "barbera", ["label"] = "Barbera D'Asti", ["weight"] = 100, ["type"] = "item", ["image"] = "barbera.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["dolceto"] = {["name"] = "dolceto", ["label"] = "Dolcetto D'Alba", ["weight"] = 100, ["type"] = "item", ["image"] = "dolceto.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["housered"] = {["name"] = "housered", ["label"] = "House Red Wine", ["weight"] = 100, ["type"] = "item", ["image"] = "housered.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["housewhite"] = {["name"] = "housewhite", ["label"] = "House White Wine", ["weight"] = 100, ["type"] = "item", ["image"] = "housewhite.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["rosso"] = {["name"] = "rosso", ["label"] = "Rosso Del Montalcino", ["weight"] = 100, ["type"] = "item", ["image"] = "rosso.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['thirst'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --DESSERTS + ["tiramisu"] = {["name"] = "tiramisu", ["label"] = "Tiramisu", ["weight"] = 100, ["type"] = "item", ["image"] = "tiramisu.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["gelato"] = {["name"] = "gelato", ["label"] = "Choc and Vanilla Gelato", ["weight"] = 100, ["type"] = "item", ["image"] = "gelato.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["medfruits"] = {["name"] = "medfruits", ["label"] = "Fresh Fruit Medly", ["weight"] = 100, ["type"] = "item", ["image"] = "medfruits.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PASTA + ["bolognese"] = {["name"] = "bolognese", ["label"] = "Bolognese", ["weight"] = 100, ["type"] = "item", ["image"] = "bolognese.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["calamari"] = {["name"] = "calamari", ["label"] = "Calamari Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "calamari.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["meatball"] = {["name"] = "meatball", ["label"] = "Homemade Meatballs", ["weight"] = 100, ["type"] = "item", ["image"] = "meatball.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["alla"] = {["name"] = "alla", ["label"] = "Alla Vodka", ["weight"] = 100, ["type"] = "item", ["image"] = "alla.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pescatore"] = {["name"] = "pescatore", ["label"] = "Pescatore", ["weight"] = 100, ["type"] = "item", ["image"] = "pescatore.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PIZZA SLICES + ["capricciosa"] = {["name"] = "capricciosa", ["label"] = "Capriccosa", ["weight"] = 100, ["type"] = "item", ["image"] = "capricciosa.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["diavola"] = {["name"] = "diavola", ["label"] = "Diavola", ["weight"] = 100, ["type"] = "item", ["image"] = "diavola.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["marinara"] = {["name"] = "marinara", ["label"] = "Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "marinara.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["margherita"] = {["name"] = "margherita", ["label"] = "Margherita", ["weight"] = 100, ["type"] = "item", ["image"] = "margherita.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["prosciuttio"] = {["name"] = "prosciuttio", ["label"] = "Prosciuttio E Funghi", ["weight"] = 100, ["type"] = "item", ["image"] = "proscuttio.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vegetariana"] = {["name"] = "vegetariana", ["label"] = "Vegetariana", ["weight"] = 100, ["type"] = "item", ["image"] = "vegetariana.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['hunger'] = math.random(20, 30), ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --PIZZA BOXES + ["capricciosabox"] = {["name"] = "capricciosabox", ["label"] = "Boxed Capriccosa", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["diavolabox"] = {["name"] = "diavolabox", ["label"] = "Boxed Diavola", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["marinarabox"] = {["name"] = "marinarabox", ["label"] = "Boxed Marinara", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["margheritabox"] = {["name"] = "margheritabox", ["label"] = "Boxed Margherita", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["prosciuttiobox"] = {["name"] = "prosciuttiobox", ["label"] = "Boxed Prosciuttio E Funghi", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["vegetarianabox"] = {["name"] = "vegetarianabox", ["label"] = "Boxed Vegetariana", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzabox.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + --INGREDIENTS + ["pizzabase"] = {["name"] = "pizzabase", ["label"] = "Pizza Base", ["weight"] = 100, ["type"] = "item", ["image"] = "base2.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pizzadough"] = {["name"] = "pizzadough", ["label"] = "Pizza Dough", ["weight"] = 100, ["type"] = "item", ["image"] = "pizzadough.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["mozz"] = {["name"] = "mozz", ["label"] = "Mozzeralla", ["weight"] = 100, ["type"] = "item", ["image"] = "mozz.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["sauce"] = {["name"] = "sauce", ["label"] = "Tomato Sauce", ["weight"] = 100, ["type"] = "item", ["image"] = "sauce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["salami"] = {["name"] = "salami", ["label"] = "Salami", ["weight"] = 100, ["type"] = "item", ["image"] = "salami.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["ham"] = {["name"] = "ham", ["label"] = "Ham", ["weight"] = 100, ["type"] = "item", ["image"] = "ham.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["squid"] = {["name"] = "squid", ["label"] = "Calamari", ["weight"] = 100, ["type"] = "item", ["image"] = "squid.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pizzmushrooms"] = {["name"] = "pizzmushrooms", ["label"] = "Mushrooms", ["weight"] = 100, ["type"] = "item", ["image"] = "mushrooms.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["olives"] = {["name"] = "olives", ["label"] = "Olives", ["weight"] = 100, ["type"] = "item", ["image"] = "olives.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["basil"] = {["name"] = "basil", ["label"] = "Basil", ["weight"] = 100, ["type"] = "item", ["image"] = "basil.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["meat"] = {["name"] = "meat", ["label"] = "Meat", ["weight"] = 200, ["type"] = "item", ["image"] = "meat.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A slab of Meat", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ["pasta"] = {["name"] = "pasta", ["label"] = "Bag of Pasta", ["weight"] = 200, ["type"] = "item", ["image"] = "pasta.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A bag of Pasta", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + ["lettuce"] = {["name"] = "lettuce", ["label"] = "Lettuce", ["weight"] = 100, ["type"] = "item", ["image"] = "lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Some big taco brother", ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + + ['simcard'] = {['name'] = 'simcard', ['label'] = 'Sim Card', ['weight'] = 1, ['type'] = 'item', ['image'] = 'simcard.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Its a new sim.. That means a new number?'}, + + ['polaroid_camera'] = { + ['name'] = 'polaroid_camera', + ['label'] = 'Polaroid camera', + ['weight'] = 5000, + ['type'] = 'item', + ['image'] = 'polaroid.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'Did we just go back in time?' + }, + + ['polaroid'] = { + ['name'] = 'polaroid', + ['label'] = 'Polaroid image', + ['weight'] = 10, + ['type'] = 'item', + ['image'] = 'photo.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'Cool image bro' + }, + + ['polaroid_paper'] = { + ['name'] = 'polaroid_paper', + ['label'] = 'Polaroid paper', + ['weight'] = 10, + ['type'] = 'item', + ['image'] = 'photo.png', + ['unique'] = false, + ['useable'] = false, + ['shouldClose'] = false, + ['combinable'] = nil, + ['description'] = 'Some paper' + }, + ['cheap_lighter'] = {['name'] = 'cheap_lighter', ['label'] = 'cheap lighter', ['weight'] = 200, ['type'] = 'item', ['image'] = 'cheap_lighter.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil}, + ['gelatti'] = {['name'] = 'gelatti', ['label'] = 'gelatti', ['weight'] = 200, ['type'] = 'item', ['image'] = 'gelatti.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['gary_payton'] = {['name'] = 'gary_payton', ['label'] = 'gary payton', ['weight'] = 200, ['type'] = 'item', ['image'] = 'gary_payton.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cereal_milk'] = {['name'] = 'cereal_milk', ['label'] = 'cereal milk', ['weight'] = 200, ['type'] = 'item', ['image'] = 'cereal_milk.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cheetah_piss'] = {['name'] = 'cheetah_piss', ['label'] = 'cheetah piss', ['weight'] = 200, ['type'] = 'item', ['image'] = 'cheetah_piss.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['snow_man'] = {['name'] = 'snow_man', ['label'] = 'snow_man', ['weight'] = 200, ['type'] = 'item', ['image'] = 'snow_man.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['georgia_pie'] = {['name'] = 'georgia_pie', ['label'] = 'georgia_pie', ['weight'] = 200, ['type'] = 'item', ['image'] = 'georgia_pie.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['jefe'] = {['name'] = 'jefe', ['label'] = 'jefe', ['weight'] = 200, ['type'] = 'item', ['image'] = 'jefe.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['cake_mix'] = {['name'] = 'cake_mix', ['label'] = 'cake_mix', ['weight'] = 200, ['type'] = 'item', ['image'] = 'cake_mix.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['backwoods_honey'] = {['name'] = 'backwoods_honey', ['label'] = 'backwoods_honey', ['weight'] = 200, ['type'] = 'item', ['image'] = 'backwoods_honey.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['backwoods_grape'] = {['name'] = 'backwoods_grape', ['label'] = 'backwoods grape', ['weight'] = 200, ['type'] = 'item', ['image'] = 'backwoods_grape.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['blueberry_cruffin'] = {['name'] = 'backwoods_grape', ['label'] = 'blueberry cruffin', ['weight'] = 200, ['type'] = 'item', ['image'] = 'blueberry_cruffin.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['grabba_leaf'] = {['name'] = 'grabba_leaf', ['label'] = 'grabba leaf', ['weight'] = 200, ['type'] = 'item', ['image'] = 'grabba_leaf.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['whitecherry_gelato'] = {['name'] = 'whitecherry_gelato', ['label'] = 'whitecherry gelato', ['weight'] = 200, ['type'] = 'item', ['image'] = 'whitecherry_gelato.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['backwoods_russian_cream'] = {['name'] = 'backwoods_russian_cream', ['label'] = 'backwoods russian cream', ['weight'] = 200, ['type'] = 'item', ['image'] = 'backwoods_russian_cream.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['pooch_bag'] = {['name'] = 'pooch_bag', ['label'] = 'pooch bag', ['weight'] = 200, ['type'] = 'item', ['image'] = 'pooch_bag.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + ['seed_weed'] = {['name'] = 'seed_weed', ['label'] = 'seedweed', ['weight'] = 200, ['type'] = 'item', ['image'] = 'seed_weed.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Nice to eat', ['created'] = nil, ["decay"] = 0.0, ["delete"] = false}, + + -- ['cash'] = {['name'] = 'cash', ['label'] = 'Cash', ['weight'] = 0, ['type'] = 'item', ['image'] = 'cash.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'cash'}, + ["spray"] = {["name"] = "spray", ["label"] = "Bomboletta Spray", ["weight"] = 300, ["type"] = "item", ["image"] = "spray.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Una bomboletta spray di vernice"}, + ["spray_remover"] = {["name"] = "spray_remover", ["label"] = "Kit rimozione Spray", ["weight"] = 300, ["type"] = "item", ["image"] = "spray_remover.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Un kit di rimozione vernice spray"}, + + --Big Size + ['burgershot_bagbig'] = {['name'] = 'burgershot_bagbig', ['label'] = 'Big Size Package', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bagbig.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "1x Big King, 1x Big Size Cola, 1x Big Size Patato", }, + ['burgershot_bigking'] = {['name'] = 'burgershot_bigking', ['label'] = 'Big King Burger', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bigking.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big King", }, + ['burgershot_colab'] = {['name'] = 'burgershot_colab', ['label'] = 'Big Size Cola', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_colab.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big Size Cola", }, + ['burgershot_patatob'] = {['name'] = 'burgershot_patatob', ['label'] = 'Big Size Patato', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_patatob.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big Size Patato", }, + --Small Size + ['burgershot_bagsmall'] = {['name'] = 'burgershot_bagsmall', ['label'] = 'Small Size Package', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bagsmall.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "1x Bleeder Burger, 1x Small Size Cola, 1x Small Size Patato", }, + ['burgershot_bleeder'] = {['name'] = 'burgershot_bleeder', ['label'] = 'Bleeder Burger', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bleeder.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Bleeder Burger", }, + ['burgershot_colas'] = {['name'] = 'burgershot_colas', ['label'] = 'Small Size Cola', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_colas.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Small Size Cola", }, + ['burgershot_patatos'] = {['name'] = 'burgershot_patatos', ['label'] = 'Small Size Patato', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_patatos.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Small Size Patato", }, + --Goat Menu (Big Kola) + ['burgershot_baggoat'] = {['name'] = 'burgershot_baggoat', ['label'] = 'Goat Menu Package', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_baggoat.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "1x Goat Wrap, 1x Big Size Cola, 1x Shot Nuggets, 1x Shot Rings", }, + ['burgershot_goatwrap'] = {['name'] = 'burgershot_goatwrap', ['label'] = 'Goat Wrap', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_goatwrap.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Goat Wrap", }, + ['burgershot_shotnuggets'] = {['name'] = 'burgershot_shotnuggets', ['label'] = 'Shot Nuggets', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_shotnuggets.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Shot Nuggets", }, + ['burgershot_shotrings'] = {['name'] = 'burgershot_shotrings', ['label'] = 'Shot Rings', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_shotrings.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Shot Rings", }, + --Coffee Menu + ['burgershot_bagcoffe'] = {['name'] = 'burgershot_bagcoffe', ['label'] = 'Coffee Package', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bagcoffe.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "1x Coffee, 1x Macaroon", }, + ['burgershot_coffee'] = {['name'] = 'burgershot_coffee', ['label'] = 'Burger Shot Coffee', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_coffee.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Coffee", }, + ['burgershot_macaroon'] = {['name'] = 'burgershot_macaroon', ['label'] = 'Macaroon', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_macaroon.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Macaroon", }, + --Toys + ['burgershot_toy1'] = {['name'] = 'burgershot_toy1', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy1.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + ['burgershot_toy2'] = {['name'] = 'burgershot_toy2', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + ['burgershot_toy3'] = {['name'] = 'burgershot_toy3', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy3.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + ['burgershot_toy4'] = {['name'] = 'burgershot_toy4', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy4.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + ['burgershot_toy5'] = {['name'] = 'burgershot_toy5', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy5.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + ['burgershot_toy6'] = {['name'] = 'burgershot_toy6', ['label'] = 'Burger Shot Toy', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_toy6.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Burger Shot Toy", }, + --Fridge Items + ['burgershot_tomato'] = {['name'] = 'burgershot_tomato', ['label'] = 'Tomato', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_tomato.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Tomato", }, + ['burgershot_cheddar'] = {['name'] = 'burgershot_cheddar', ['label'] = 'Cheddar', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_cheddar.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Cheddar", }, + ['burgershot_curly'] = {['name'] = 'burgershot_curly', ['label'] = 'Curly', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_curly.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Curly", }, + ['burgershot_sauce'] = {['name'] = 'burgershot_sauce', ['label'] = 'Sauce', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_sauce.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Sauce", }, + ['burgershot_bread'] = {['name'] = 'burgershot_bread', ['label'] = 'Bread', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bread.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Bread", }, + ['burgershot_lavash'] = {['name'] = 'burgershot_lavash', ['label'] = 'Lavash', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_lavash.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Lavash", }, + ['burgershot_bigcardboard'] = {['name'] = 'burgershot_bigcardboard', ['label'] = 'Big Size Cardboard', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bigcardboard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big Size Cardboard", }, + ['burgershot_smallcardboard'] = {['name'] = 'burgershot_smallcardboard', ['label'] = 'Small Size Cardboard', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_smallcardboard.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Small Size Cardboard", }, + ['burgershot_smallemptyglass'] = {['name'] = 'burgershot_smallemptyglass', ['label'] = 'Small Size Empty Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_smallemptyglass.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Small Size Empty Glass", }, + ['burgershot_bigemptyglass'] = {['name'] = 'burgershot_bigemptyglass', ['label'] = 'Big Size Empty Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bigemptyglass.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big Size Empty Glass", }, + ['burgershot_coffeeemptyglass'] = {['name'] = 'burgershot_coffeeemptyglass', ['label'] = 'Coffee Empty Glass', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_coffeeemptyglass.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Coffee Empty Glass", }, + ['burgershot_frozenmeat'] = {['name'] = 'burgershot_frozenmeat', ['label'] = 'Frozen Meat', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_frozenmeat.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Frozen Meat", }, + ['burgershot_frozenrings'] = {['name'] = 'burgershot_frozenrings', ['label'] = 'Frozen Rings', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_frozenrings.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Frozen Rings", }, + ['burgershot_frozennuggets'] = {['name'] = 'burgershot_frozennuggets', ['label'] = 'Frozen Nuggets', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_frozennuggets.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Frozen Nuggets", }, + ['burgershot_smallfrozenpotato'] = {['name'] = 'burgershot_smallfrozenpotato', ['label'] = 'Small Size Frozen Potato', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_smallfrozenpotato.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Small Size Frozen Potato", }, + ['burgershot_bigfrozenpotato'] = {['name'] = 'burgershot_bigfrozenpotato', ['label'] = 'Big Size Frozen Potato', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_bigfrozenpotato.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Big Size Frozen Potato", }, + ['burgershot_meat'] = {['name'] = 'burgershot_meat', ['label'] = 'Meat', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_meat.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Meat", }, + --Ice Cream + ['burgershot_thesmurfsicecream'] = {['name'] = 'burgershot_thesmurfsicecream', ['label'] = 'The Smurfs Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_thesmurfsicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "The Smurfs Ice Cream", }, + ['burgershot_smurfetteicecream'] = {['name'] = 'burgershot_smurfetteicecream', ['label'] = 'Smurfette Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_smurfetteicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Smurfette Ice Cream", }, + ['burgershot_matchaicecream'] = {['name'] = 'burgershot_matchaicecream', ['label'] = 'Matcha Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_matchaicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Matcha Ice Cream", }, + ['burgershot_ubeicecream'] = {['name'] = 'burgershot_ubeicecream', ['label'] = 'Ube Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_ubeicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Ube Ice Cream", }, + ['burgershot_unicornicecream'] = {['name'] = 'burgershot_unicornicecream', ['label'] = 'Unicorn Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_unicornicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Unicorn Ice Cream", }, + ['burgershot_vanillaicecream'] = {['name'] = 'burgershot_vanillaicecream', ['label'] = 'Vanilla Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_vanillaicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Vanilla Ice Cream", }, + ['burgershot_chocolateicecream'] = {['name'] = 'burgershot_chocolateicecream', ['label'] = 'Chocolate Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_chocolateicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Chocolate Ice Cream", }, + ['burgershot_strawberryicecream'] = {['name'] = 'burgershot_strawberryicecream', ['label'] = 'Strawberry Ice Cream', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_strawberryicecream.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Strawberry Ice Cream", }, + ['burgershot_icecreamcone'] = {['name'] = 'burgershot_icecreamcone', ['label'] = 'Empty Cone', ['weight'] = 100, ['type'] = 'item', ['image'] = 'burgershot_icecreamcone.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = "Cone", }, + + -- Whitewidow items + ["weed_skunk_cbd_crop"] = {["name"] = "weed_skunk_cbd_crop", ["label"] = "CBD Skunk Crop", ["weight"] = 1200, ["type"] = "item", ["image"] = "weed_skunk_crop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A crop of CBD Skunk!"}, + ["weed_og-kush_cbd_crop"] = {["name"] = "weed_og-kush_cbd_crop", ["label"] = "CBD OG Kush Crop", ["weight"] = 1200, ["type"] = "item", ["image"] = "weed_og-kush_crop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A crop of CBD OG Kush"}, + ["weed_white-widow_cbd_crop"] = {["name"] = "weed_white-widow_cbd_crop", ["label"] = "CBD White Widow Crop", ["weight"] = 1200, ["type"] = "item", ["image"] = "weed_white-widow_crop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A crop of CBD White Widow"}, + ["weed_ak47_cbd_crop"] = {["name"] = "weed_ak47_cbd_crop", ["label"] = "CBD AK 47 Crop", ["weight"] = 1200, ["type"] = "item", ["image"] = "weed_ak47_crop.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A crop of CBD AK47!"}, + ["weed_skunk_cbd"] = {["name"] = "weed_skunk_cbd", ["label"] = "CBD Skunk 2g", ["weight"] = 5, ["type"] = "item", ["image"] = "weed_skunk_cbd.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A 2g bag of CBD Skunk!"}, + ["weed_og-kush_cbd"] = {["name"] = "weed_og-kush_cbd", ["label"] = "CBD OGKush 2g", ["weight"] = 5, ["type"] = "item", ["image"] = "weed_og-kush_cbd.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A 2g bag of CBD OG Kush!"}, + ["weed_white-widow_cbd"] = {["name"] = "weed_white-widow_cbd", ["label"] = "CBD White Widow 2g", ["weight"] = 5, ["type"] = "item", ["image"] = "weed_white-widow_cbd.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A 2g bag of CBD White Widow!"}, + ["weed_ak47_cbd"] = {["name"] = "weed_ak47_cbd", ["label"] = "CBD AK47 2g", ["weight"] = 5, ["type"] = "item", ["image"] = "weed_ak47_cbd.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A 2g bag of CBD 2g AK47!"}, + ["weed_skunk_cbd_joint"] = {["name"] = "weed_skunk_cbd_joint", ["label"] = "CBD Skunk Joint", ["weight"] = 1000, ["type"] = "item", ["image"] = "weed_skunk_cbd_joint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Light up that skunk son!"}, + ["weed_og-kush_cbd_joint"] = {["name"] = "weed_og-kush_cbd_joint", ["label"] = "CBD OG Kush Joint", ["weight"] = 1000, ["type"] = "item", ["image"] = "weed_og-kush_cbd_joint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Light up that og kush son!"}, + ["weed_white-widow_cbd_joint"] = {["name"] = "weed_white-widow_cbd_joint", ["label"] = "CBD White Widow Joint", ["weight"] = 1000, ["type"] = "item", ["image"] = "weed_white-widow_cbd_joint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Light up that white widow son!"}, + ["weed_ak47_cbd_joint"] = {["name"] = "weed_ak47_cbd_joint", ["label"] = "CBD AK 47 Joint", ["weight"] = 1000, ["type"] = "item", ["image"] = "weed_ak47_cbd_joint.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Light up that ak47 son!"}, + ["lighter"] = {["name"] = "lighter", ["label"] = "Lighter", ["weight"] = 5, ["type"] = "item", ["image"] = "lighter.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "On new years eve a nice fire to stand next to"}, + ["bong"] = {["name"] = "bong", ["label"] = "Bong", ["weight"] = 500, ["type"] = "item", ["image"] = "bong.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "In Australia this is called a \"Billy\""}, + ['empty_weed_bag'] = {['name'] = 'empty_weed_bag', ['label'] = 'Empty Weed Bag', ['weight'] = 0, ['type'] = 'item', ['image'] = 'weed_baggy_empty.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'A small empty bag'}, + ["bakingsoda"] = {["name"] = "bakingsoda", ["label"] = "Baking Soda", ["weight"] = 1500, ["type"] = "item", ["image"] = "bakingsoda.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Household Baking Soda!"}, + ["eggs"] = {["name"] = "eggs", ["label"] = "Eggs", ["weight"] = 100, ["type"] = "item", ["image"] = "eggs.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Eggs", }, + ["sugar"] = {["name"] = "sugar", ["label"] = "Sugar", ["weight"] = 100, ["type"] = "item", ["image"] = "sugar.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Sugar", }, + ["milk"] = {["name"] = "milk", ["label"] = "Milk", ["weight"] = 200, ["type"] = "item", ["image"] = "milk.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Carton of Milk", }, + ["strawberry"] = {["name"] = "strawberry", ["label"] = "Strawberries", ["weight"] = 100, ["type"] = "item", ["image"] = "strawberry.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Strawberries", }, + ["butter"] = {["name"] = "butter", ["label"] = "Butter", ["weight"] = 200, ["type"] = "item", ["image"] = "butter.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Butter", }, + ["gelatine"] = {["name"] = "gelatine", ["label"] = "Gelatine", ["weight"] = 100, ["type"] = "item", ["image"] = "gelatine.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Gelatine", }, + ["raspberry"] = {["name"] = "raspberry", ["label"] = "Raspberry", ["weight"] = 200, ["type"] = "item", ["image"] = "raspberry.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Raspberry", }, + ["gummymould"] = {["name"] = "gummymould", ["label"] = "Gummy Mould", ["weight"] = 400, ["type"] = "item", ["image"] = "gummymould.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Gummy Mould", }, + ["chocolatechips"] = {["name"] = "chocolatechips", ["label"] = "Chocolate Chips", ["weight"] = 400, ["type"] = "item", ["image"] = "chocolatechips.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chocolate Chips", }, + ["flour"] = {["name"] = "flour", ["label"] = "Flour", ["weight"] = 400, ["type"] = "item", ["image"] = "flour.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Flour", }, + ["strawberrygummybear"] = {["name"] = "strawberrygummybear", ["label"] = "Strawberry Gummy Bears", ["weight"] = 1000, ["type"] = "item", ["image"] = "wwgummybear.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Packet of..."}, + ["raspberrygummybear"] = {["name"] = "raspberrygummybear", ["label"] = "Raspberry Gummy Bears", ["weight"] = 1000, ["type"] = "item", ["image"] = "wwgummybear.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Packet of..."}, + ["ak47cookie"] = {["name"] = "ak47cookie", ["label"] = "AK47 Cookie", ["weight"] = 1000, ["type"] = "item", ["image"] = "wwcookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Yum Cookie..."}, + ["skunkcookie"] = {["name"] = "skunkcookie", ["label"] = "Skunk Cookie", ["weight"] = 1000, ["type"] = "item", ["image"] = "wwcookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Yum Cookie..."}, + ["wwcookie"] = {["name"] = "wwcookie", ["label"] = "WhiteWidow Cookie", ["weight"] = 1000, ["type"] = "item", ["image"] = "wwcookie.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Yum Cookie..."}, + + -- gun heist + ["goldenphone"] = {["name"] = "goldenphone", ["label"] = "Golden Satellite Phone", ["weight"] = 200, ["type"] = "item", ["image"] = "goldenphone.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A communication device used to contact russian mafia."}, + ["redphone"] = {["name"] = "redphone", ["label"] = "Red Satellite Phone", ["weight"] = 200, ["type"] = "item", ["image"] = "redphone.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A communication device used to contact russian mafia."}, + ["greenphone"] = {["name"] = "greenphone", ["label"] = "Green Satellite Phone", ["weight"] = 200, ["type"] = "item", ["image"] = "greenphone.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A communication device used to contact russian mafia."}, + + + ["vape"] = { + ["name"] = "vape", + ["label"] = "Vape", + ["weight"] = 2500, + ["type"] = "item", + ["image"] = "vape.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "For the kids who think clouds are cool." + }, + ["vapejuice"] = { + ["name"] = "vapejuice", + ["label"] = "Vape Juice", + ["weight"] = 100, + ["type"] = "item", + ["image"] = "vapejuice.png", + ["unique"] = false, + ['useable'] = false, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "100ml Vape Juice." + }, + ["emptyvape"] = { + ["name"] = "emptyvape", + ["label"] = "Juiceless Vape", + ["weight"] = 100, + ["type"] = "item", + ["image"] = "vape.png", + ["unique"] = false, + ['useable'] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "A juiceless vape." + }, + + -- jim-mining stuff + ["stone"] = {["name"] = "stone", ["label"] = "Stone", ["weight"] = 2000, ["type"] = "item", ["image"] = "stone.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Stone woo"}, + + ["uncut_emerald"] = {["name"] = "uncut_emerald", ["label"] = "Uncut Emerald", ["weight"] = 100, ["type"] = "item", ["image"] = "uncut_emerald.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A rough Emerald"}, + ["uncut_ruby"] = {["name"] = "uncut_ruby", ["label"] = "Uncut Ruby", ["weight"] = 100, ["type"] = "item", ["image"] = "uncut_ruby.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A rough Ruby"}, + ["uncut_diamond"] = {["name"] = "uncut_diamond", ["label"] = "Uncut Diamond", ["weight"] = 100, ["type"] = "item", ["image"] = "uncut_diamond.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A rough Diamond"}, + ["uncut_sapphire"] = {["name"] = "uncut_sapphire", ["label"] = "Uncut Sapphire", ["weight"] = 100, ["type"] = "item", ["image"] = "uncut_sapphire.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A rough Sapphire"}, + + ["emerald"] = {["name"] = "emerald", ["label"] = "Emerald", ["weight"] = 100, ["type"] = "item", ["image"] = "emerald.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Emerald that shimmers"}, + ["ruby"] = {["name"] = "ruby", ["label"] = "Ruby", ["weight"] = 100, ["type"] = "item", ["image"] = "ruby.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Ruby that shimmers"}, + ["diamond"] = {["name"] = "diamond", ["label"] = "Diamond", ["weight"] = 100, ["type"] = "item", ["image"] = "diamond.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Diamond that shimmers"}, + ["sapphire"] = {["name"] = "sapphire", ["label"] = "Sapphire", ["weight"] = 100, ["type"] = "item", ["image"] = "sapphire.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A Sapphire that shimmers"}, + + ["gold_ring"] = {["name"] = "gold_ring", ["label"] = "Gold Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "gold_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_ring"] = {["name"] = "diamond_ring", ["label"] = "Diamond Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_ring"] = {["name"] = "ruby_ring", ["label"] = "Ruby Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_ring"] = {["name"] = "sapphire_ring", ["label"] = "Sapphire Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_ring"] = {["name"] = "emerald_ring", ["label"] = "Emerald Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["silver_ring"] = {["name"] = "silver_ring", ["label"] = "Silver Ring", ["weight"] = 200, ["type"] = "item", ["image"] = "silver_ring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_ring_silver"] = {["name"] = "diamond_ring_silver", ["label"] = "Diamond Ring Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_ring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_ring_silver"] = {["name"] = "ruby_ring_silver", ["label"] = "Ruby Ring Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_ring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_ring_silver"] = {["name"] = "sapphire_ring_silver", ["label"] = "Sapphire Ring Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_ring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_ring_silver"] = {["name"] = "emerald_ring_silver", ["label"] = "Emerald Ring Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_ring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["goldchain"] = {["name"] = "goldchain", ["label"] = "Golden Chain", ["weight"] = 200, ["type"] = "item", ["image"] = "goldchain.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_necklace"] = {["name"] = "diamond_necklace", ["label"] = "Diamond Necklace", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_necklace.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_necklace"] = {["name"] = "ruby_necklace", ["label"] = "Ruby Necklace", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_necklace.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_necklace"] = {["name"] = "sapphire_necklace", ["label"] = "Sapphire Necklace", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_necklace.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_necklace"] = {["name"] = "emerald_necklace", ["label"] = "Emerald Necklace", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_necklace.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["silverchain"] = {["name"] = "silverchain", ["label"] = "Silver Chain", ["weight"] = 200, ["type"] = "item", ["image"] = "silverchain.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_necklace_silver"] = {["name"] = "diamond_necklace_silver", ["label"] = "Diamond Necklace Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_necklace_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_necklace_silver"] = {["name"] = "ruby_necklace_silver", ["label"] = "Ruby Necklace Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_necklace_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_necklace_silver"] = {["name"] = "sapphire_necklace_silver", ["label"] = "Sapphire Necklace Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_necklace_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_necklace_silver"] = {["name"] = "emerald_necklace_silver", ["label"] = "Emerald Necklace Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_necklace_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["goldearring"] = {["name"] = "goldearring", ["label"] = "Golden Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "gold_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_earring"] = {["name"] = "diamond_earring", ["label"] = "Diamond Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_earring"] = {["name"] = "ruby_earring", ["label"] = "Ruby Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_earring"] = {["name"] = "sapphire_earring", ["label"] = "Sapphire Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_earring"] = {["name"] = "emerald_earring", ["label"] = "Emerald Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["silverearring"] = {["name"] = "silverearring", ["label"] = "Silver Earrings", ["weight"] = 200, ["type"] = "item", ["image"] = "silver_earring.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["diamond_earring_silver"] = {["name"] = "diamond_earring_silver", ["label"] = "Diamond Earrings Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "diamond_earring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["ruby_earring_silver"] = {["name"] = "ruby_earring_silver", ["label"] = "Ruby Earrings Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "ruby_earring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["sapphire_earring_silver"] = {["name"] = "sapphire_earring_silver", ["label"] = "Sapphire Earrings Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "sapphire_earring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["emerald_earring_silver"] = {["name"] = "emerald_earring_silver", ["label"] = "Emerald Earrings Silver", ["weight"] = 200, ["type"] = "item", ["image"] = "emerald_earring_silver.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["carbon"] = {["name"] = "carbon", ["label"] = "Carbon", ["weight"] = 1000, ["type"] = "item", ["image"] = "carbon.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Carbon, a base ore."}, + ["ironore"] = {["name"] = "ironore", ["label"] = "Iron Ore", ["weight"] = 1000, ["type"] = "item", ["image"] = "ironore.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Iron, a base ore."}, + ["copperore"] = {["name"] = "copperore", ["label"] = "Copper Ore", ["weight"] = 1000, ["type"] = "item", ["image"] = "copperore.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Copper, a base ore."}, + ["goldore"] = {["name"] = "goldore", ["label"] = "Gold Ore", ["weight"] = 1000, ["type"] = "item", ["image"] = "goldore.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Gold Ore"}, + ["silverore"] = {["name"] = "silverore", ["label"] = "Silver Ore", ["weight"] = 1000, ["type"] = "item", ["image"] = "silverore.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Silver Ore"}, + + ["goldingot"] = {["name"] = "goldingot", ["label"] = "Gold Ingot", ["weight"] = 1000, ["type"] = "item", ["image"] = "goldingot.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["silveringot"] = {["name"] = "silveringot", ["label"] = "Silver Ingot", ["weight"] = 1000, ["type"] = "item", ["image"] = "silveringot.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["pickaxe"] = {["name"] = "pickaxe", ["label"] = "Pickaxe", ["weight"] = 1000, ["type"] = "item", ["image"] = "pickaxe.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["miningdrill"] = {["name"] = "miningdrill", ["label"] = "Mining Drill", ["weight"] = 1000, ["type"] = "item", ["image"] = "miningdrill.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["mininglaser"] = {["name"] = "mininglaser", ["label"] = "Mining Laser", ["weight"] = 900, ["type"] = "item", ["image"] = "mininglaser.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + ["drillbit"] = {["name"] = "drillbit", ["label"] = "Drill Bit", ["weight"] = 10, ["type"] = "item", ["image"] = "drillbit.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["goldpan"] = {["name"] = "goldpan", ["label"] = "Gold Panning Tray", ["weight"] = 10, ["type"] = "item", ["image"] = "goldpan.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = ""}, + + ["bottle"] = {["name"] = "bottle", ["label"] = "Empty Bottle", ["weight"] = 10, ["type"] = "item", ["image"] = "bottle.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "A glass bottle"}, + ["can"] = {["name"] = "can", ["label"] = "Empty Can", ["weight"] = 10, ["type"] = "item", ["image"] = "can.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "An empty can, good for recycling"}, + + + ["police_scanner"] = { + ["name"] = "police_scanner", + ["label"] = "Police Scanner", + ["weight"] = 0, + ["type"] = "item", + ["image"] = "police_scanner.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Scanner device for police officers" + }, + + -- ================ Keep-companion ================ + ["keepcompanionhusky"] = { + ["name"] = "keepcompanionhusky", + ["label"] = "Husky", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Husky.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Husky is your royal companion!" + }, + ["keepcompanionpoodle"] = { + ["name"] = "keepcompanionpoodle", + ["label"] = "Poodle", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Poodle.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Poodle is your royal companion!" + }, + ["keepcompanionrottweiler"] = { + ["name"] = "keepcompanionrottweiler", + ["label"] = "Rottweiler", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_Rottweiler.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Rottweiler is your royal companion!" + }, + ["keepcompanionwesty"] = { + ["name"] = "keepcompanionwesty", + ["label"] = "Westy", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Westy.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Westy is your royal companion!" + }, + ["keepcompanionmtlion"] = { + ["name"] = "keepcompanionmtlion", + ["label"] = "MtLion", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_MtLion.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "MtLion is your royal companion!" + }, + ["keepcompanionmtlion2"] = { + ["name"] = "keepcompanionmtlion2", + ["label"] = "Panter", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_MtLion.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Panter is your royal companion!" + }, + ["keepcompanioncat"] = { + ["name"] = "keepcompanioncat", + ["label"] = "Cat", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Cat_01.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Cat is your royal companion!" + }, + ["keepcompanionpug"] = { + ["name"] = "keepcompanionpug", + ["label"] = "Pug", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Pug.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Pug is your royal companion!" + }, + ["keepcompanionretriever"] = { + ["name"] = "keepcompanionretriever", + ["label"] = "Retriever", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Retriever.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Retriever is your royal companion!" + }, + ["keepcompanionshepherd"] = { + ["name"] = "keepcompanionshepherd", + ["label"] = "Shepherd", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_shepherd.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Shepherd is your royal companion!" + }, + -- new pets + ["keepcompanioncoyote"] = { + ["name"] = "keepcompanioncoyote", + ["label"] = "Coyote", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Coyote.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Coyote is your royal companion!" + }, + ["keepcompanionrabbit"] = { + ["name"] = "keepcompanionrabbit", + ["label"] = "Rabbit", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Rabbit_01.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Rabbit is your royal companion!" + }, + ["keepcompanionhen"] = { + ["name"] = "keepcompanionhen", + ["label"] = "Hen", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Hen.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Hen is your royal companion!" + }, + ["keepcompanionrat"] = { + ["name"] = "keepcompanionrat", + ["label"] = "Rat", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "A_C_Rat.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Your royal companion!" + }, + --- + ["petfood"] = { + ["name"] = "petfood", + ["label"] = "pet food", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "petfood.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "food for your companion!" + }, + ["collarpet"] = { + ["name"] = "collarpet", + ["label"] = "Pet collar", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "collarpet.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = true, + ["description"] = "Rename your pets!" + }, + ["firstaidforpet"] = { + ["name"] = "firstaidforpet", + ["label"] = "First aid for pet", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "firstaidforpet.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Revive your pet!" + }, + ["petnametag"] = { + ["name"] = "petnametag", + ["label"] = "Name tag", + ["weight"] = 500, + ["type"] = "item", + ["image"] = "petnametag.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Rename your pet" + }, + ["petwaterbottleportable"] = { + ["name"] = "petwaterbottleportable", + ["label"] = "Portable water bottle", + ["weight"] = 1000, + ["type"] = "item", + ["image"] = "petwaterbottleportable.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Flask to store water for your pets" + }, + ["petgroomingkit"] = { + ["name"] = "petgroomingkit", + ["label"] = "Pet Grooming Kit", + ["weight"] = 1000, + ["type"] = "item", + ["image"] = "petgroomingkit.png", + ["unique"] = true, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Pet Grooming Kit" + }, + ["stethascope"] = { + ["name"] = "stethascope", + ["label"] = "Stetha Scope", + ["weight"] = 100, + ["type"] = "item", + ["image"] = "stethascope.png", + ["unique"] = false, + ['useable'] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Doctor Equipment." + }, + ["specialwatch"] = { + ["name"] = "specialwatch", + ["label"] = "Special Watch", + ["weight"] = 100, + ["type"] = "item", + ["image"] = "specialwatch.png", + ["unique"] = false, + ['useable'] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Nice Watch. Must Be Rare" + }, + ["blueusb"] = { + ["name"] = "blueusb", + ["label"] = "Blue usb Device", + ["weight"] = 100, + ["type"] = "item", + ["image"] = "blueusb.png", + ["unique"] = false, + ['useable'] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Good To Store Data on" + }, + + -- Taco Shop Food + ["beef-taco"] = {["name"] = "beef-taco", ["label"] = "Beef Taco", ["weight"] = 250, ["type"] = "item", ["image"] = "beef-taco.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beef Taco!"}, + ["chicken-taco"] = {["name"] = "chicken-taco", ["label"] = "Chicken Taco", ["weight"] = 250, ["type"] = "item", ["image"] = "chicken-taco.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Taco!"}, + ["quesadilla"] = {["name"] = "quesadilla", ["label"] = "Quesadilla", ["weight"] = 250, ["type"] = "item", ["image"] = "quesadilla.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Quesadilla!"}, + ["chicken-burrito"] = {["name"] = "chicken-burrito", ["label"] = "Chicken Burrito", ["weight"] = 250, ["type"] = "item", ["image"] = "chicken-burrito.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Chicken Burrito!"}, + ["beef-burrito"] = {["name"] = "beef-burrito", ["label"] = "Beef Burrito", ["weight"] = 250, ["type"] = "item", ["image"] = "beef-burrito.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Beef Burrito!"}, + ["nachos"] = {["name"] = "nachos", ["label"] = "Nachos", ["weight"] = 250, ["type"] = "item", ["image"] = "nachos.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Nachos!"}, + + -- Taco Drinks + ["coke-soda"] = {["name"] = "coke-soda", ["label"] = "Coke Soda", ["weight"] = 180, ["type"] = "item", ["image"] = "coke-soda.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Coke Soda!"}, + ["fanta"] = {["name"] = "fanta", ["label"] = "Fanta", ["weight"] = 180, ["type"] = "item", ["image"] = "fanta.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Fanta!"}, + + --Ingredients + ["tortillas"] = {["name"] = "tortillas", ["label"] = "Tortillas", ["weight"] = 150, ["type"] = "item", ["image"] = "tortillas.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["ground-beef"] = {["name"] = "ground-beef", ["label"] = "Ground Beef", ["weight"] = 210, ["type"] = "item", ["image"] = "ground-beef.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["raw-ground-beef"] = {["name"] = "raw-ground-beef", ["label"] = "Raw Ground Beef", ["weight"] = 210, ["type"] = "item", ["image"] = "raw-ground-beef.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["cheddar-cheese"] = {["name"] = "cheddar-cheese", ["label"] = "Cheddar Cheese", ["weight"] = 125, ["type"] = "item", ["image"] = "cheddar-cheese.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["butter"] = {["name"] = "butter", ["label"] = "Butter", ["weight"] = 125, ["type"] = "item", ["image"] = "butter.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Smooth like butter, like a criminal undercover~"}, + ["chicken"] = {["name"] = "chicken", ["label"] = "Chicken", ["weight"] = 180, ["type"] = "item", ["image"] = "chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["raw-chicken"] = {["name"] = "raw-chicken", ["label"] = "Raw Chicken", ["weight"] = 180, ["type"] = "item", ["image"] = "raw-chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["lettuce"] = {["name"] = "lettuce", ["label"] = "Lettuce", ["weight"] = 150, ["type"] = "item", ["image"] = "lettuce.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["tortilla-chips"] = {["name"] = "tortilla-chips", ["label"] = "Tortilla Chips", ["weight"] = 150, ["type"] = "item", ["image"] = "tortilla-chips.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["carbonated-water"] = {["name"] = "carbonated-water", ["label"] = "Carbonated Water", ["weight"] = 125, ["type"] = "item", ["image"] = "carbonated-water.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["sugar-cubes"] = {["name"] = "sugar-cubes", ["label"] = "Sugar Cubes", ["weight"] = 100, ["type"] = "item", ["image"] = "sugar-cubes.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + ["taco-tomato"] = {["name"] = "taco-tomato", ["label"] = "Tomatoes", ["weight"] = 100, ["type"] = "item", ["image"] = "taco-tomato.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Ingredient"}, + + + ["oilbarell"] = { + ["name"] = "oilbarell", + ["label"] = "Oil barell", + ["weight"] = 15000, + ["type"] = "item", + ["image"] = "oilBarrel.png", + ["unique"] = true, + ["useable"] = false, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oil Barrel" + }, + ["oilwell"] = { + ["name"] = "oilwell", + ["label"] = "Oilwell", + ["weight"] = 50000, + ["type"] = "item", + ["image"] = "oilwell.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oilwell" + }, + ["reliefvalvestring"] = { + ["name"] = "reliefvalvestring", + ["label"] = "Relief Valve String", + ["weight"] = 4000, + ["type"] = "item", + ["image"] = "relief_valve_string.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Relief Valve String" + }, + ["oilfilter"] = { + ["name"] = "oilfilter", + ["label"] = "Oil Filter", + ["weight"] = 5000, + ["type"] = "item", + ["image"] = "oil_filter.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Oil Filter" + }, + ["skewgear"] = { + ["name"] = "skewgear", + ["label"] = "Skew Gear", + ["weight"] = 6000, + ["type"] = "item", + ["image"] = "skew_gear.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Skew Gear" + }, + ["timingchain"] = { + ["name"] = "timingchain", + ["label"] = "Timing Chain", + ["weight"] = 7000, + ["type"] = "item", + ["image"] = "timing_chain.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Timing Chain" + }, + ["driveshaft"] = { + ["name"] = "driveshaft", + ["label"] = "Drive Shaft", + ["weight"] = 5000, + ["type"] = "item", + ["image"] = "drive_shaft.png", + ["unique"] = false, + ["useable"] = true, + ["shouldClose"] = true, + ["combinable"] = nil, + ["description"] = "Drive Shaft" + }, + + ["notepad"] = {["name"] = "notepad", ["label"] = "Notepad", ["weight"] = 100, ["type"] = "item", ["image"] = "notepad.png", ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = ""}, + + -- AN Mechanic Job + ['car_wheel'] = { + ['name'] = 'car_wheel', + ['label'] = 'Wheel', + ['weight'] = 1000, + ['type'] = 'item', + ['image'] = 'car_wheel.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A multipurpose wheel' + }, + ['repairkit2'] = { + ['name'] = 'repairkit2', + ['label'] = 'Repair Kit', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'repairkit2.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A Special Repair Kit crafted by a Professional Mechanic.' + }, + ['advancedrepairkit2'] = { + ['name'] = 'advancedrepairkit2', + ['label'] = 'Advanced Repair Kit', + ['weight'] = 800, + ['type'] = 'item', + ['image'] = 'advancedrepairkit2.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A Special & Advanced Repair Kit crafted by a Professional Mechanic.' + }, + ['car_door'] = { + ['name'] = 'car_door', + ['label'] = 'Car Door', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'car_door.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A car door.' + }, + ['car_trunk'] = { + ['name'] = 'car_trunk', + ['label'] = 'Car Trunk', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'car_trunk.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A car trunk.' + }, + ['car_hood'] = { + ['name'] = 'car_hood', + ['label'] = 'Car Hood', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'car_hood.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A car hood.' + }, + ['car_window'] = { + ['name'] = 'car_window', + ['label'] = 'Car Window', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'car_window.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A car window.' + }, + ['toolbox'] = { + ['name'] = 'toolbox', + ['label'] = 'Tool Box', + ['weight'] = 500, + ['type'] = 'item', + ['image'] = 'toolbox.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A special Mechanic Tool box.' + }, + ['carjack'] = { + ['name'] = 'carjack', + ['label'] = 'Car Jack', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'carjack.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'A car jack used to elevate the car from the ground for quick repairs.' + }, + ['car_engine'] = { + ['name'] = 'car_engine', + ['label'] = 'Engine', + ['weight'] = 1500, + ['type'] = 'item', + ['image'] = 'car_engine.png', + ['unique'] = true, + ['useable'] = true, + ['shouldClose'] = true, + ['combinable'] = nil, + ['description'] = 'An Engine that can be placed inside vehicles to make them run ig?' + }, + ["corn_seed"] = {["name"] = "corn_seed", ["label"] = "Corn Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "corn_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["corn_raw"] = {["name"] = "corn_raw", ["label"] = "Raw Corn", ["weight"] = 25, ["type"] = "item", ["image"] = "corn_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["corn"] = {["name"] = "corn", ["label"] = "Corn", ["weight"] = 25, ["type"] = "item", ["image"] = "corn.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tomato_seed"] = {["name"] = "tomato_seed", ["label"] = "Tomato Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "tomato_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tomato_raw"] = {["name"] = "tomato_raw", ["label"] = "Tomato Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "tomato_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["tomato"] = {["name"] = "tomato", ["label"] = "Tomato", ["weight"] = 25, ["type"] = "item", ["image"] = "tomato.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["wheat_seed"] = {["name"] = "wheat_seed", ["label"] = "Wheat Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "wheat_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["wheat_raw"] = {["name"] = "wheat_raw", ["label"] = "Wheat Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "wheat_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["wheat"] = {["name"] = "wheat", ["label"] = "Wheat", ["weight"] = 25, ["type"] = "item", ["image"] = "wheat.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["broccoli_seed"] = {["name"] = "broccoli_seed", ["label"] = "Broccoli Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "broccoli_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["broccoli_raw"] = {["name"] = "broccoli_raw", ["label"] = "Broccoli Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "broccoli_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["broccoli"] = {["name"] = "broccoli", ["label"] = "Broccoli", ["weight"] = 25, ["type"] = "item", ["image"] = "broccoli.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["carrot_seed"] = {["name"] = "carrot_seed", ["label"] = "Carrot Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "carrot_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["carrot_raw"] = {["name"] = "carrot_raw", ["label"] = "Carrot Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "carrot_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["carrot"] = {["name"] = "carrot", ["label"] = "Carrot", ["weight"] = 25, ["type"] = "item", ["image"] = "carrot.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["potato_seed"] = {["name"] = "potato_seed", ["label"] = "Potato Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "potato_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["potato_raw"] = {["name"] = "potato_raw", ["label"] = "Potato Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "potato_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["potato"] = {["name"] = "potato", ["label"] = "Potato", ["weight"] = 25, ["type"] = "item", ["image"] = "potato.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["pickle_seed"] = {["name"] = "pickle_seed", ["label"] = "Pickle Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "pickle_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["pickle_raw"] = {["name"] = "pickle_raw", ["label"] = "Pickle Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "pickle_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["pickle"] = {["name"] = "pickle", ["label"] = "Pickle", ["weight"] = 25, ["type"] = "item", ["image"] = "pickle.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["weed_seed"] = {["name"] = "weed_seed", ["label"] = "Weed Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "weed_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["weed_raw"] = {["name"] = "weed_raw", ["label"] = "Weed Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "weed_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["weed"] = {["name"] = "weed", ["label"] = "Weed", ["weight"] = 25, ["type"] = "item", ["image"] = "weed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cocaine_seed"] = {["name"] = "cocaine_seed", ["label"] = "Cocaine Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "cocaine_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cocaine_raw"] = {["name"] = "cocaine_raw", ["label"] = "Cocaine Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "cocaine_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["cocaine"] = {["name"] = "cocaine", ["label"] = "Cocaine", ["weight"] = 25, ["type"] = "item", ["image"] = "cocaine.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["heroin_seed"] = {["name"] = "heroin_seed", ["label"] = "Heroin Seed", ["weight"] = 25, ["type"] = "item", ["image"] = "heroin_seed.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["heroin_raw"] = {["name"] = "heroin_raw", ["label"] = "Heroin Raw", ["weight"] = 25, ["type"] = "item", ["image"] = "heroin_raw.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["heroin"] = {["name"] = "heroin", ["label"] = "Heroin", ["weight"] = 25, ["type"] = "item", ["image"] = "heroin.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["garden_pitcher"] = {["name"] = "garden_pitcher", ["label"] = "Garden Pitcher", ["weight"] = 25, ["type"] = "item", ["image"] = "garden_pitcher.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["garden_shovel"] = {["name"] = "garden_shovel", ["label"] = "Garden Shovel", ["weight"] = 25, ["type"] = "item", ["image"] = "garden_shovel.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + + ["hunting_horn"] = {["name"] = "hunting_horn", ["label"] = "Hunting Horn", ["weight"] = 1, ["type"] = "item", ["image"] = "hunting_horn.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = "Shows the nearest animals to you on the map."}, + ["animal_hide_1"] = {["name"] = "animal_hide_1", ["label"] = "Animal Hide G1", ["weight"] = 100, ["type"] = "item", ["image"] = "animal_hide_1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["animal_hide_2"] = {["name"] = "animal_hide_2", ["label"] = "Animal Hide G2", ["weight"] = 100, ["type"] = "item", ["image"] = "animal_hide_2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["animal_hide_3"] = {["name"] = "animal_hide_3", ["label"] = "Animal Hide G3", ["weight"] = 100, ["type"] = "item", ["image"] = "animal_hide_3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["animal_meat_1"] = {["name"] = "animal_meat_1", ["label"] = "Animal Meat G1", ["weight"] = 1000, ["type"] = "item", ["image"] = "animal_meat_1.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["animal_meat_2"] = {["name"] = "animal_meat_2", ["label"] = "Animal Meat G2", ["weight"] = 1000, ["type"] = "item", ["image"] = "animal_meat_2.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + ["animal_meat_3"] = {["name"] = "animal_meat_3", ["label"] = "Animal Meat G3", ["weight"] = 1000, ["type"] = "item", ["image"] = "animal_meat_3.png", ["unique"] = false, ["useable"] = true, ["shouldClose"] = true, ["combinable"] = nil, ["description"] = ""}, + + ['chain_v'] = {['name'] = 'chain_v', ['label'] = 'Vlone | Silver/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'chain_v.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_v1'] = {['name'] = 'chain_v1', ['label'] = 'Vlone | Gold/Silver', ['weight'] = 1, ['type'] = 'item', ['image'] = 'chain_v.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_v2'] = {['name'] = 'chain_v2', ['label'] = 'Vlone | Silver/Black', ['weight'] = 1, ['type'] = 'item', ['image'] = 'chain_v.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_bdb'] = {['name'] = 'chain_bdb', ['label'] = 'BDB Chain', ['weight'] = 1, ['type'] = 'item', ['image'] = 'billiondollarbaby.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_cp1'] = {['name'] = 'chain_cp1', ['label'] = 'Cross Chain', ['weight'] = 1, ['type'] = 'item', ['image'] = 'crosschain1.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_cp2'] = {['name'] = 'chain_cp2', ['label'] = 'Cross Chain', ['weight'] = 1, ['type'] = 'item', ['image'] = 'crosschain2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull'] = {['name'] = 'chain_skull', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull1.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull2'] = {['name'] = 'chain_skull2', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull3'] = {['name'] = 'chain_skull3', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull3.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull4'] = {['name'] = 'chain_skull4', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull4.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull5'] = {['name'] = 'chain_skull5', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull5.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull6'] = {['name'] = 'chain_skull6', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull6.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_skull7'] = {['name'] = 'chain_skull7', ['label'] = 'Iced out Skull', ['weight'] = 1, ['type'] = 'item', ['image'] = 'skull7.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_nocap'] = {['name'] = 'chain_nocap', ['label'] = 'Iced out NOCAP', ['weight'] = 1, ['type'] = 'item', ['image'] = 'chain_nocap.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_snake'] = {['name'] = 'chain_snake', ['label'] = 'Iced out Snake Bite', ['weight'] = 1, ['type'] = 'item', ['image'] = 'trustnoone.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_link'] = {['name'] = 'chain_link', ['label'] = 'Iced out linked Chain', ['weight'] = 1, ['type'] = 'item', ['image'] = 'chain_link.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au1'] = {['name'] = 'chain_au1', ['label'] = 'Among Us | All Gold ', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus1.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au2'] = {['name'] = 'chain_au2', ['label'] = 'Among Us | Red/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au3'] = {['name'] = 'chain_au3', ['label'] = 'Among Us | Blue/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus3.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au4'] = {['name'] = 'chain_au4', ['label'] = 'Among Us | White/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus4.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au5'] = {['name'] = 'chain_au5', ['label'] = 'Among Us | Green/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus5.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au6'] = {['name'] = 'chain_au6', ['label'] = 'Among Us | Black/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus6.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au7'] = {['name'] = 'chain_au7', ['label'] = 'Among Us | Purple/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus7.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au8'] = {['name'] = 'chain_au8', ['label'] = 'Among Us | Cyan/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus8.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au9'] = {['name'] = 'chain_au9', ['label'] = 'Among Us | Orange/Gold', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus9.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au10'] = {['name'] = 'chain_au10', ['label'] = 'Among Us | Black/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus10.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au11'] = {['name'] = 'chain_au11', ['label'] = 'Among Us | Gold/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus11.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au12'] = {['name'] = 'chain_au12', ['label'] = 'Among Us | Red/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus12.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au13'] = {['name'] = 'chain_au13', ['label'] = 'Among Us | Green/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus13.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au14'] = {['name'] = 'chain_au14', ['label'] = 'Among Us | Pink/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus14.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au15'] = {['name'] = 'chain_au15', ['label'] = 'Among Us | Blue/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus15.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + ['chain_au16'] = {['name'] = 'chain_au16', ['label'] = 'Among Us | White/Diamond', ['weight'] = 1, ['type'] = 'item', ['image'] = 'amongus16.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Add a lil bit of drip'}, + + ["head_bag"] = {["name"] = "head_bag", ["label"] = "Head Bag", ["weight"] = 5, ["type"] = "item", ["image"] = "head_bag.png", ["unique"] = true, ["useable"] = true, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Put mask on hostage."}, + + ['potato'] = {['name'] = 'potato', ['label'] = 'Potato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'potato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Po-ta-to'}, + ['dirty_potato'] = {['name'] = 'dirty_potato', ['label'] = 'Dirty Potato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_potato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Po-ta-to'}, + ['tomato'] = {['name'] = 'tomato', ['label'] = 'Tomato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'tomato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To-ma-to'}, + ['dirty_tomato'] = {['name'] = 'dirty_tomato', ['label'] = 'Dirty Tomato', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_tomato.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'To-ma-to'}, + ['coffee_beans'] = {['name'] = 'coffee_beans', ['label'] = 'Coffee Beans', ['weight'] = 350, ['type'] = 'item', ['image'] = 'coffee_beans.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Wakey wakey!'}, + ['dirty_coffee_beans'] = {['name'] = 'dirty_coffee_beans', ['label'] = 'Dirty Coffee Beans', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_coffee_beans.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Wakey wakey!'}, + ['cabbage'] = {['name'] = 'cabbage', ['label'] = 'Cabbage', ['weight'] = 350, ['type'] = 'item', ['image'] = 'np_ingredients_cabbage.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Let-tuce? No!'}, + ['dirty_cabbage'] = {['name'] = 'dirty_cabbage', ['label'] = 'Dirty Cabbage', ['weight'] = 350, ['type'] = 'item', ['image'] = 'np_ingredients_cabbage.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Let-tuce? No!'}, + ['orange'] = {['name'] = 'orange', ['label'] = 'Orange', ['weight'] = 350, ['type'] = 'item', ['image'] = 'orange.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The talking orange!'}, + ['dirty_orange'] = {['name'] = 'dirty_orange', ['label'] = 'Dirty Orange', ['weight'] = 350, ['type'] = 'item', ['image'] = 'dirty_orange.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'The talking orange!'}, + ['trowel'] = {['name'] = 'trowel', ['label'] = 'Trowel', ['weight'] = 350, ['type'] = 'item', ['image'] = 'trowel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Mini-shovel yes'}, + ['shovel'] = {['name'] = 'shovel', ['label'] = 'Shovel', ['weight'] = 350, ['type'] = 'item', ['image'] = 'shovel.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Legit shovel yes'}, + + ["alive_chicken"] = {["name"] = "alive_chicken", ["label"] = "Alive chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "alive_chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Alive Chicken"}, + ["slaughtered_chicken"] = {["name"] = "slaughtered_chicken", ["label"] = "Slaughtered chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "slaughteredchicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Slaughtered Chicken"}, + ["packagedchicken"] = {["name"] = "packagedchicken", ["label"] = "Packaged chicken", ["weight"] = 2000, ["type"] = "item", ["image"] = "packaged_chicken.png", ["unique"] = false, ["useable"] = false, ["shouldClose"] = false, ["combinable"] = nil, ["description"] = "Packaged Chicken"}, + ['mdtcitation'] = {['name'] = 'mdtcitation', ['label'] = 'Bøde', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'citation.png', ['unique'] = true, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Bøde fra politiet'}, +} diff --git a/resources/[qb]/qb-core/shared/jobs.lua b/resources/[qb]/qb-core/shared/jobs.lua new file mode 100644 index 0000000..ad98bb2 --- /dev/null +++ b/resources/[qb]/qb-core/shared/jobs.lua @@ -0,0 +1,537 @@ +QBShared = QBShared or {} +QBShared.ForceJobDefaultDutyAtLogin = true -- true: Force duty state to jobdefaultDuty | false: set duty state from database last saved +QBShared.QBJobsStatus = false -- true: integrate qb-jobs into the whole of qb-core | false: treat qb-jobs as an add-on resource. +QBShared.Jobs = {} -- All of below has been migrated into qb-jobs +if QBShared.QBJobsStatus then return end +QBShared.Jobs = { + ['unemployed'] = { + label = 'Civil', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Arbejdsløs', + payment = 50 + }, + }, + }, + ["delivery"] = { + label = "Omdeler", + defaultDuty = true, + grades = { + ['0'] = { + name = "Pakkebud", + payment = 120 + }, + }, + }, + ["gardener"] = { + label = "Gartner", + defaultDuty = true, + grades = { + ['0'] = { + name = "Gartner", + payment = 120 + }, + ['1'] = { + name = "Leder", + payment = 120, + isboss = true, + }, + }, + }, + ['mechanic'] = { + label = 'Mekaniker', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Lærling', + payment = 50 + }, + ['1'] = { + name = 'Svend', + payment = 75 + }, + ['2'] = { + name = 'Leder', + payment = 100 + }, + ['3'] = { + name = 'Ejer', + isboss = true, + payment = 125 + }, + }, + }, + ['taco'] = { + label = 'Taco Shop', + defaultDuty = false, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Lærling', + payment = 75 + }, + ['1'] = { + name = 'Svend', + payment = 85 + }, + ['2'] = { + name = 'Kok', + payment = 100 + }, + ['3'] = { + name = 'Leder', + payment = 120 + }, + ['4'] = { + name = 'Ejer', + isboss = true, + payment = 135, + }, + }, + }, + ['oilwell'] = { + label = 'Oilebrønd', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Jr. Operatør', + payment = 50 + }, + ['1'] = { + name = 'Sr. Operatør', + payment = 75 + }, + ['2'] = { + name = 'Chauffør', + payment = 100 + }, + ['3'] = { + name = 'Sælger', + payment = 125 + }, + ['4'] = { + name = 'Ejer', + isboss = true, + payment = 150 + }, + }, + }, + ['whitewidow'] = { + label = 'Whitewidow', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { name = 'Samler', payment = 50 }, + ['1'] = { name = 'Levering', payment = 75 }, + ['2'] = { name = 'Ruller', payment = 100 }, + ['3'] = { name = 'Leder', payment = 125 }, + ['4'] = { name = 'Ejer', payment = 150 ,isboss = true,}, + }, + }, + ['burgershot'] = { + label = 'Burger Shot', + type = "burgershot", + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Medarbejder', + payment = 50 + }, + ['1'] = { + name = 'Leder', + payment = 150 + }, + ['2'] = { + name = 'Ejer', + isboss = true, + payment = 250 + }, + }, + }, + ['vanilla'] = { + label = 'Vanilla Unicorn', + type = "vanilla", + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Medarbejder', + payment = 50 + }, + ['1'] = { + name = 'Leder', + payment = 150 + }, + ['2'] = { + name = 'Ejer', + isboss = true, + payment = 250 + }, + }, + }, + ['tequilala'] = { + label = 'Tequilala', + defaultDuty = false, + grades = { + ['0'] = { name = 'Lærling', payment = 50 }, + ['1'] = { name = 'Jr. Staff', payment = 75 }, + ['2'] = { name = 'Sr. Staff', payment = 100 }, + ['3'] = { name = 'Leder', payment = 125 }, + ['4'] = { name = 'Ejer', payment = 150, isboss = true, }, + }, + }, + ['beanmachine'] = { + label = 'Bean Machine', + defaultDuty = true, + grades = { + ['0'] = { name = 'Lærling', payment = 100 }, + ['1'] = { name = 'Jr. Staff', payment = 175 }, + ['2'] = { name = 'Sr. Staff', payment = 200 }, + ['3'] = { name = 'Leder', payment = 225 }, + ['4'] = { name = 'Ejer', payment = 350, isboss = true, }, + }, + }, + ['fire'] = { + label = 'Brandmand', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Ansat', + payment = 100 + }, + ['1'] = { + name = 'Kaptajn', + isboss = true, + payment = 200 + }, + }, + }, + ["upnatoms"] = { + label = "Up-N-Atoms", + defaultDuty = false, + offDutyPay = false, + grades = { + ['0'] = { name = "Lærling", payment = 90 }, + ['1'] = { name = "Assistent", payment = 100 }, + ['2'] = { name = "Grillmester", payment = 110 }, + ['3'] = { name = "Manager", payment = 120 }, + ['4'] = { name = "CEO", isboss = true, payment = 135 }, + }, + }, + ['mesanuxta'] = { + label = 'Mesanuxta', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Lærling', + payment = 50 + }, + ['1'] = { + name = 'Ansat', + payment = 75 + }, + ['2'] = { + name = 'Manager', + payment = 100 + }, + ['3'] = { + name = 'Ejer', + isboss = true, + payment = 125 + }, + }, + }, + ['uwu'] = { + label = 'Cat Café', + defaultDuty = true, + grades = { + ['0'] = { name = 'Lærling', payment = 50 }, + ['1'] = { name = 'Tjener', payment = 75 }, + ['2'] = { name = 'Opvasker', payment = 100 }, + ['3'] = { name = 'Manager', payment = 125 }, + ['4'] = { name = 'Ejer', payment = 150, isboss = true, }, + }, + }, + ['pizzathis'] = { + label = 'Pizza This', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { name = 'Lærling', payment = 50 }, + ['1'] = { name = 'Tjener', payment = 75 }, + ['2'] = { name = 'Opvasker', payment = 100 }, + ['3'] = { name = 'Manager', payment = 125 }, + ['4'] = { name = 'Ejer', payment = 150, isboss = true, }, + }, + }, + ['police'] = { + label = 'Politi', + type = 'emergency', + defaultDuty = true, + grades = { + ['0'] = {name = "Kadet", payment = 200}, + ['1'] = {name = "Betjent", payment = 225}, + ['2'] = {name = "Assistent", payment = 250}, + ['3'] = {name = "Assistent 1.gr", payment = 275}, + ['4'] = {name = "Hundeføre", payment = 275}, + ['5'] = {name = "PET", payment = 300}, + ['6'] = {name = "AKS", payment = 400}, + ['7'] = {name = "Motorcykel", payment = 275}, + ['8'] = {name = "Kommissær", payment = 425}, + ['9'] = {name = "Viceinspektør", payment = 450}, + ['10'] = {name = "Inspektør", payment = 500}, + ['11'] = {name = "Vicemester", isboss = true, payment = 500}, + ['12'] = {name = "Chefinspektør", isboss = true, payment = 550}, + ['13'] = {name = "Chefanklager", isboss = true, payment = 550}, + ['14'] = {name = "Afdelingschef", isboss = true, payment = 550}, + ['15'] = {name = "Stabschef", isboss = true, payment = 550}, + ['16'] = {name = "Politimester", isboss = true, payment = 650}, + ['17'] = {name = "Direktør", isboss = true, payment = 650}, + ['18'] = {name = "Rigschef", isboss = true, payment = 750}, + }, + }, + ['ambulance'] = { + label = 'EMS', + type = 'emergency', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Recruit', + payment = 100 + }, + ['1'] = { + name = 'Paramedic', + payment = 200 + }, + ['2'] = { + name = 'Doctor', + payment = 300 + }, + ['3'] = { + name = 'Surgeon', + payment = 400 + }, + ['4'] = { + name = 'Chief', + isboss = true, + payment = 500 + }, + }, + }, + ['realestate'] = { + label = 'Mægler', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Lærling', + payment = 50 + }, + ['1'] = { + name = 'Hussalg', + payment = 75 + }, + ['2'] = { + name = 'Eventsalg', + payment = 100 + }, + ['3'] = { + name = 'Firmasalg', + payment = 125 + }, + ['4'] = { + name = 'Chef', + isboss = true, + payment = 150 + }, + }, + }, + ['taxi'] = { + label = 'Taxi', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Recruit', + payment = 50 + }, + ['1'] = { + name = 'Driver', + payment = 75 + }, + ['2'] = { + name = 'Event Driver', + payment = 100 + }, + ['3'] = { + name = 'Sales', + payment = 125 + }, + ['4'] = { + name = 'Manager', + isboss = true, + payment = 150 + }, + }, + }, + ['bus'] = { + label = 'Bus', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Chauffør', + isboss = true, + payment = 95 + }, + }, + }, + ['recycle'] = { + label = 'Genbrug', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Medarbejder', + isboss = true, + payment = 90 + }, + }, + }, + ['cardealer'] = { + label = 'Bilsælger', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Lærling', + payment = 50 + }, + ['1'] = { + name = 'Basis Sælger', + payment = 75 + }, + ['2'] = { + name = 'Luxury Sælger', + payment = 100 + }, + ['3'] = { + name = 'Leder', + payment = 125 + }, + ['4'] = { + name = 'Ejer', + isboss = true, + payment = 150 + }, + }, + }, + ['judge'] = { + label = 'Staten', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Dommer', + isboss = true, + payment = 325 + }, + }, + }, + ['lawyer'] = { + label = 'Advokater', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Jr. Advokat', + isboss = false, + payment = 250 + }, + ['1'] = { + name = 'Sr. Advokat', + isboss = false, + payment = 350 + }, + ['2'] = { + name = 'Chef', + isboss = true, + payment = 550 + }, + }, + }, + ['reporter'] = { + label = 'Nyheder', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Journalist', + payment = 100 + }, + }, + }, + ['trucker'] = { + label = 'Trucker', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Chauffør', + payment = 175 + }, + }, + }, + ['tow'] = { + label = 'Bugsering', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Chauffør', + payment = 150 + }, + }, + }, + ['garbage'] = { + label = 'Skraldemand', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Samler', + payment = 150 + }, + }, + }, + ['vineyard'] = { + label = 'Vingård', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Samler', + payment = 95 + }, + }, + }, + ['hotdog'] = { + label = 'Hotdog', + defaultDuty = true, + offDutyPay = false, + grades = { + ['0'] = { + name = 'Sælger', + payment = 75 + }, + }, + }, +} diff --git a/resources/[qb]/qb-core/shared/locale.lua b/resources/[qb]/qb-core/shared/locale.lua new file mode 100644 index 0000000..34fa835 --- /dev/null +++ b/resources/[qb]/qb-core/shared/locale.lua @@ -0,0 +1,145 @@ +--- @class Locale +Locale = {} +Locale.__index = Locale + +local function translateKey(phrase, subs) + if type(phrase) ~= 'string' then + error('TypeError: translateKey function expects arg #1 to be a string') + end + + -- Substituions + if not subs then + return phrase + end + + -- We should be escaping gsub just in case of any + -- shenanigans with nested template patterns or injection + + -- Create and copy our return string + local result = phrase + + -- Initial Scan over result looking for substituions + for k, v in pairs(subs) do + local templateToFind = '%%{' .. k .. '}' + result = result:gsub(templateToFind, tostring(v)) -- string to allow all types + end + + return result +end + +--- Constructor function for a new Locale class instance +--- @param opts table - Constructor opts param +--- @return Locale +function Locale.new(_, opts) + local self = setmetatable({}, Locale) + + self.fallback = opts.fallbackLang and Locale:new({ + warnOnMissing = false, + phrases = opts.fallbackLang.phrases, + }) or false + + self.warnOnMissing = type(opts.warnOnMissing) ~= 'boolean' and true or opts.warnOnMissing + + self.phrases = {} + self:extend(opts.phrases or {}) + + return self +end + +--- Method for extending an instances phrases map. This is also, used +--- internally for initial population of phrases field. +--- @param phrases table - Table of phrase definitions +--- @param prefix string | nil - Optional prefix used for recursive calls +--- @return nil +function Locale:extend(phrases, prefix) + for key, phrase in pairs(phrases) do + local prefixKey = prefix and ('%s.%s'):format(prefix, key) or key + -- If this is a nested table, we need to go reeeeeeeeeeeecursive + if type(phrase) == 'table' then + self:extend(phrase, prefixKey) + else + self.phrases[prefixKey] = phrase + end + end +end + +--- Clear locale instance phrases +--- Might be useful for memory management of large phrase maps. +--- @return nil +function Locale:clear() + self.phrases = {} +end + +--- Clears all phrases and replaces it with the passed phrases table +--- @param phrases table +function Locale:replace(phrases) + phrases = phrases or {} + self:clear() + self:extend(phrases) +end + +--- Gets & Sets a locale depending on if an argument is passed +--- @param newLocale string - Optional new locale to set +--- @return string +function Locale:locale(newLocale) + if (newLocale) then + self.currentLocale = newLocale + end + return self.currentLocale +end + +--- Primary translation method for a phrase of given key +--- @param key string - The phrase key to target +--- @param subs table | nil +--- @return string +function Locale:t(key, subs) + local phrase, result + subs = subs or {} + + -- See if the passed key resolves to a valid phrase string + if type(self.phrases[key]) == 'string' then + phrase = self.phrases[key] + -- At this point we know whether the phrase does not exist for this key + else + if self.warnOnMissing then + print(('^3Warning: Missing phrase for key: "%s"'):format(key)) + end + if self.fallback then + return self.fallback:t(key, subs) + end + result = key + end + + if type(phrase) == 'string' then + result = translateKey(phrase, subs) + end + + return result +end + +--- Check if a phrase key has already been defined within the Locale instance phrase maps. +--- @return boolean +function Locale:has(key) + return self.phrases[key] ~= nil +end + +--- Will remove phrase keys from a Locale instance, using recursion/ +--- @param phraseTarget string | table +--- @param prefix string +function Locale:delete(phraseTarget, prefix) + -- If the target is a string, we know that this is the end + -- of nested table tree. + if type(phraseTarget) == 'string' then + self.phrases[phraseTarget] = nil + else + for key, phrase in pairs(phraseTarget) do + local prefixKey = prefix and prefix .. '.' .. key or key + + if type(phrase) == 'table' then + self:delete(phrase, prefixKey) + else + self.phrases[prefixKey] = nil + end + end + end +end \ No newline at end of file diff --git a/resources/[qb]/qb-core/shared/locations.lua b/resources/[qb]/qb-core/shared/locations.lua new file mode 100644 index 0000000..1317991 --- /dev/null +++ b/resources/[qb]/qb-core/shared/locations.lua @@ -0,0 +1,47 @@ +QBShared.Locations = { + -- Unknown/Random/Vanilla + ['burgershot'] = vector4(-1199.0568, -882.4495, 13.3500, 209.1105), + ['casino'] = vector4(923.2289, 47.3113, 81.1063, 237.6052), + + -- Gabz + ['arcade'] = vector4(-1649.6089, -1083.9313, 13.1575, 46.4121), + ['beanmachinelegion'] = vector4(116.16, -1022.99, 29.3, 0.0), + ['bowling'] = vector4(761.5008, -777.7256, 26.3078, 90.5581), + ['pizzaria'] = vector4(790.4561, -758.4601, 26.7424, 270.2329), + ['catcafe'] = vector4(-580.8388, -1072.7872, 22.3296, 359.0078), + ['carmeet'] = vector4(958.8237, -1699.6659, 29.5574, 71.2731), + ['popsdiner'] = vector4(1595.9753, 6448.6421, 25.3170, 28.3026), + ['harmony'] = vector4(1183.0693, 2648.5313, 37.8363, 194.0603), + ['haters'] = vector4(-1117.1525, -1439.4297, 5.1075, 103.4411), + ['hayes'] = vector4(-1435.7040, -445.7360, 35.5964, 220.1762), + ['pdm'] = vector4(-48.2113, -1105.4769, 27.2634, 339.5899), + ['bennys'] = vector4(-47.5289, -1042.6086, 28.3532, 247.9748), + ['lamesaauto'] = vector4(720.4776, -1092.1934, 22.2866, 310.1469), + ['lostmc'] = vector4(982.6339, -104.7095, 74.8488, 30.8738), + ['pillbox'] = vector4(298.1153, -584.2825, 43.2609, 252.7553), + ['mirrorparkhouse1'] = vector4(945.9535, -652.9119, 58.0228, 90.5541), + ['pacificbank'] = vector4(229.9529, 214.3890, 105.5561, 294.6791), + ['paletoliquor'] = vector4(-154.2287, 6328.8682, 31.5665, 133.1992), + ['paletogasstation'] = vector4(120.2420, 6625.4722, 31.9580, 36.5687), + ['pinkcage'] = vector4(323.9055, -203.2524, 54.0866, 186.8505), + ['ponsonbys1'] = vector4(-165.2497, -304.3988, 38.07126, 0.0), + ['ponsonbys2'] = vector4(-1448.1, -236.8420, 48.15098, 0.0), + ['ponsonbys3'] = vector4(-709.8120, -150.6267, 35.75312, 0.0), + ['rangerstation'] = vector4(387.3204, 790.1508, 187.6927, 4.7656), + ['recordastudio'] = vector4(473.3006, -109.4360, 62.7418, 350.8488), + ['suburban1'] = vector4(124.9756, -217.6290, 55.81879, 0.0), + ['suburban2'] = vector4(617.4776, 2757.4810, 43.34935, 0.0), + ['suburban3'] = vector4(-1195.8690, -773.5746, 18.58485, 0.0), + ['suburban4'] = vector4(-3170.9670, 1049.9310, 22.12445, 0.0), + ['triadrecords'] = vector4(-829.0061, -698.2049, 28.0583, 291.2052), + ['tuner'] = vector4(157.5888, -3017.9968, 7.0400, 94.0695), + ['vu'] = vector4(129.4555, -1299.6754, 29.2327, 27.6378), + + -- Patoche + ['luxerydealership'] = vector4(-1273.22, -371.11, 36.64, 301.8), + + -- Unclejust + ['digitalden'] = vector4(-656.28, -849.92, 24.51, 167.42), + ['ifruitstore1'] = vector4(-646.78, -288.17, 35.49, 297.73), + ['ifruitstore2'] = vector4(-778.7451, -598.2717, 30.2772, 181.0197) +} \ No newline at end of file diff --git a/resources/[qb]/qb-core/shared/main.lua b/resources/[qb]/qb-core/shared/main.lua new file mode 100644 index 0000000..c0329b1 --- /dev/null +++ b/resources/[qb]/qb-core/shared/main.lua @@ -0,0 +1,163 @@ +QBShared = QBShared or {} + +local StringCharset = {} +local NumberCharset = {} + +QBShared.StarterItems = { + ['phone'] = { amount = 1, item = 'phone' }, + -- ['id_card'] = { amount = 1, item = 'id_card' }, + -- ['driver_license'] = { amount = 1, item = 'driver_license' }, +} + +for i = 48, 57 do NumberCharset[#NumberCharset + 1] = string.char(i) end +for i = 65, 90 do StringCharset[#StringCharset + 1] = string.char(i) end +for i = 97, 122 do StringCharset[#StringCharset + 1] = string.char(i) end + +function QBShared.RandomStr(length) + if length <= 0 then return '' end + return QBShared.RandomStr(length - 1) .. StringCharset[math.random(1, #StringCharset)] +end + +function QBShared.RandomInt(length) + if length <= 0 then return '' end + return QBShared.RandomInt(length - 1) .. NumberCharset[math.random(1, #NumberCharset)] +end + +function QBShared.SplitStr(str, delimiter) + local result = {} + local from = 1 + local delim_from, delim_to = string.find(str, delimiter, from) + while delim_from do + result[#result + 1] = string.sub(str, from, delim_from - 1) + from = delim_to + 1 + delim_from, delim_to = string.find(str, delimiter, from) + end + result[#result + 1] = string.sub(str, from) + return result +end + +function QBShared.Trim(value) + if not value then return nil end + return (string.gsub(value, '^%s*(.-)%s*$', '%1')) +end + +function QBShared.FirstToUpper(value) + if not value then return nil end + return (value:gsub("^%l", string.upper)) +end + +function QBShared.Round(value, numDecimalPlaces) + if not numDecimalPlaces then return math.floor(value + 0.5) end + local power = 10 ^ numDecimalPlaces + return math.floor((value * power) + 0.5) / (power) +end + +function QBShared.ChangeVehicleExtra(vehicle, extra, enable) + if DoesExtraExist(vehicle, extra) then + if enable then + SetVehicleExtra(vehicle, extra, false) + if not IsVehicleExtraTurnedOn(vehicle, extra) then + QBShared.ChangeVehicleExtra(vehicle, extra, enable) + end + else + SetVehicleExtra(vehicle, extra, true) + if IsVehicleExtraTurnedOn(vehicle, extra) then + QBShared.ChangeVehicleExtra(vehicle, extra, enable) + end + end + end +end + +function QBShared.SetDefaultVehicleExtras(vehicle, config) + -- Clear Extras + for i = 1, 20 do + if DoesExtraExist(vehicle, i) then + SetVehicleExtra(vehicle, i, 1) + end + end + + for id, enabled in pairs(config) do + QBShared.ChangeVehicleExtra(vehicle, tonumber(id), type(enabled) == 'boolean' and enabled or true) + end +end + +QBShared.MaleNoGloves = { + [0] = true, + [1] = true, + [2] = true, + [3] = true, + [4] = true, + [5] = true, + [6] = true, + [7] = true, + [8] = true, + [9] = true, + [10] = true, + [11] = true, + [12] = true, + [13] = true, + [14] = true, + [15] = true, + [18] = true, + [26] = true, + [52] = true, + [53] = true, + [54] = true, + [55] = true, + [56] = true, + [57] = true, + [58] = true, + [59] = true, + [60] = true, + [61] = true, + [62] = true, + [112] = true, + [113] = true, + [114] = true, + [118] = true, + [125] = true, + [132] = true +} + +QBShared.FemaleNoGloves = { + [0] = true, + [1] = true, + [2] = true, + [3] = true, + [4] = true, + [5] = true, + [6] = true, + [7] = true, + [8] = true, + [9] = true, + [10] = true, + [11] = true, + [12] = true, + [13] = true, + [14] = true, + [15] = true, + [19] = true, + [59] = true, + [60] = true, + [61] = true, + [62] = true, + [63] = true, + [64] = true, + [65] = true, + [66] = true, + [67] = true, + [68] = true, + [69] = true, + [70] = true, + [71] = true, + [129] = true, + [130] = true, + [131] = true, + [135] = true, + [142] = true, + [149] = true, + [153] = true, + [157] = true, + [161] = true, + [165] = true +} diff --git a/resources/[qb]/qb-core/shared/vehicles.lua b/resources/[qb]/qb-core/shared/vehicles.lua new file mode 100644 index 0000000..84bbfc5 --- /dev/null +++ b/resources/[qb]/qb-core/shared/vehicles.lua @@ -0,0 +1,5585 @@ +QBShared = QBShared or {} +QBShared.VehicleHashes = {} + +QBShared.Vehicles = { + --- Compacts + ['asbo'] = { -- This has to match the spawn code of the vehicle + ['name'] = 'Asbo', -- This is the display of the vehicle + ['brand'] = 'Maxwell', -- This is the vehicle's brand (Ford, Chevrolet, BMW, Mercedes, etc) + ['model'] = 'asbo', -- This must match the spawn code of the vehicle + ['price'] = 4000, -- The price that the vehicle sells for + ['category'] = 'Compacts', -- This must match "VehicleClass" in vehicles.meta for the vehicle and must also exist in https://docs.fivem.net/natives/?_0x29439776AAA00A62 + ['categoryLabel'] = 'Compacts', -- Customize for your Vehicle Shop headings (can even include spaces) + ['hash'] = `asbo`, -- This has to match the spawn code of the vehicle and must be surrounded by backticks. Example of a Backtick: ` + ['shop'] = 'pdm', -- Can be a single shop or multiple shops. For multiple shops for example {'shopname1','shopname2','shopname3'} + }, + ['blista'] = { + ['name'] = 'Blista', + ['brand'] = 'Dinka', + ['model'] = 'blista', + ['price'] = 13000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `blista`, + ['shop'] = 'pdm', + }, + ['blista2'] = { + ['name'] = 'Blista Compact', + ['brand'] = 'Dinka', + ['model'] = 'blista2', + ['price'] = 18950, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `blista2`, + ['shop'] = 'pdm', + }, + ['blista3'] = { + ['name'] = 'Blista Go Go Monkey', + ['brand'] = 'Dinka', + ['model'] = 'blista3', + ['price'] = 15000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `blista3`, + ['shop'] = 'pdm', + }, + ['kanjo'] = { + ['name'] = 'Blista Kanjo', + ['brand'] = 'Dinka', + ['model'] = 'kanjo', + ['price'] = 12000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `kanjo`, + ['shop'] = 'pdm', + }, + ['brioso2'] = { + ['name'] = 'Brioso 300', + ['brand'] = 'Grotti', + ['model'] = 'brioso2', + ['price'] = 12000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `brioso2`, + ['shop'] = 'pdm', + }, + ['brioso3'] = { --DLC +set sv_enforceGameBuild 2699 (and below) + ['name'] = 'Brioso 300 Widebody', + ['brand'] = 'Grotti', + ['model'] = 'brioso3', + ['price'] = 125000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `brioso3`, + ['shop'] = 'pdm', + }, + ['brioso'] = { + ['name'] = 'Brioso R/A', + ['brand'] = 'Grotti', + ['model'] = 'brioso', + ['price'] = 20000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `brioso`, + ['shop'] = 'pdm', + }, + ['club'] = { + ['name'] = 'Club', + ['brand'] = 'BF', + ['model'] = 'club', + ['price'] = 8000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `club`, + ['shop'] = 'pdm', + }, + ['dilettante'] = { + ['name'] = 'Dilettante', + ['brand'] = 'Karin', + ['model'] = 'dilettante', + ['price'] = 9000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `dilettante`, + ['shop'] = 'pdm', + }, + ['dilettante2'] = { + ['name'] = 'Dilettante Patrol', + ['brand'] = 'Karin', + ['model'] = 'dilettante2', + ['price'] = 12000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `dilettante2`, + ['shop'] = 'pdm', + }, + ['issi2'] = { + ['name'] = 'Issi', + ['brand'] = 'Weeny', + ['model'] = 'issi2', + ['price'] = 7000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi2`, + ['shop'] = 'pdm', + }, + ['issi4'] = { --DLC + ['name'] = 'Issi Arena', + ['brand'] = 'Weeny', + ['model'] = 'issi4', + ['price'] = 80000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi4`, + ['shop'] = 'pdm', + }, + ['issi3'] = { + ['name'] = 'Issi Classic', + ['brand'] = 'Weeny', + ['model'] = 'issi3', + ['price'] = 5000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi3`, + ['shop'] = 'pdm', + }, + ['issi5'] = { --DLC + ['name'] = 'Issi Future Shock', + ['brand'] = 'Weeny', + ['model'] = 'issi5', + ['price'] = 80000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi5`, + ['shop'] = 'pdm', + }, + ['issi6'] = { --DLC + ['name'] = 'Issi Nightmare', + ['brand'] = 'Weeny', + ['model'] = 'issi6', + ['price'] = 80000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi6`, + ['shop'] = 'pdm', + }, + ['issi7'] = { --DLC + ['name'] = 'Issi Sport', + ['brand'] = 'Weeny', + ['model'] = 'issi7', + ['price'] = 100000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `issi7`, + ['shop'] = 'pdm', + }, + ['panto'] = { + ['name'] = 'Panto', + ['brand'] = 'Benefactor', + ['model'] = 'panto', + ['price'] = 3200, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `panto`, + ['shop'] = 'pdm', + }, + ['prairie'] = { + ['name'] = 'Prairie', + ['brand'] = 'Bollokan', + ['model'] = 'prairie', + ['price'] = 30000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `prairie`, + ['shop'] = 'pdm', + }, + ['rhapsody'] = { + ['name'] = 'Rhapsody', + ['brand'] = 'Declasse', + ['model'] = 'rhapsody', + ['price'] = 10000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `rhapsody`, + ['shop'] = 'pdm', + }, + ['weevil'] = { + ['name'] = 'Weevil', + ['brand'] = 'BF', + ['model'] = 'weevil', + ['price'] = 9000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `weevil`, + ['shop'] = 'pdm', + }, + ['boor'] = { + ['name'] = 'Boor', + ['brand'] = 'Karin', + ['model'] = 'boor', + ['price'] = 23000, + ['category'] = 'Compacts', + ['categoryLabel'] = 'Compacts', + ['hash'] = `boor`, + ['shop'] = 'pdm', + }, + + --- Coupes + ['cogcabrio'] = { + ['name'] = 'Cognoscenti Cabrio', + ['brand'] = 'Enus', + ['model'] = 'cogcabrio', + ['price'] = 30000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `cogcabrio`, + ['shop'] = 'pdm', + }, + ['exemplar'] = { + ['name'] = 'Exemplar', + ['brand'] = 'Dewbauchee', + ['model'] = 'exemplar', + ['price'] = 40000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `exemplar`, + ['shop'] = 'pdm', + }, + ['f620'] = { + ['name'] = 'F620', + ['brand'] = 'Ocelot', + ['model'] = 'f620', + ['price'] = 32500, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `f620`, + ['shop'] = 'pdm', + }, + ['felon'] = { + ['name'] = 'Felon', + ['brand'] = 'Lampadati', + ['model'] = 'felon', + ['price'] = 31000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `felon`, + ['shop'] = 'pdm', + }, + ['felon2'] = { + ['name'] = 'Felon GT', + ['brand'] = 'Lampadati', + ['model'] = 'felon2', + ['price'] = 37000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `felon2`, + ['shop'] = 'pdm', + }, + ['jackal'] = { + ['name'] = 'Jackal', + ['brand'] = 'Ocelot', + ['model'] = 'jackal', + ['price'] = 19000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `jackal`, + ['shop'] = 'pdm', + }, + ['oracle2'] = { + ['name'] = 'Oracle XS', + ['brand'] = 'Übermacht', + ['model'] = 'oracle2', + ['price'] = 28000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `oracle2`, + ['shop'] = 'pdm', + }, + ['sentinel'] = { + ['name'] = 'Sentinel', + ['brand'] = 'Übermacht', + ['model'] = 'sentinel', + ['price'] = 30000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `sentinel`, + ['shop'] = 'pdm', + }, + ['sentinel2'] = { + ['name'] = 'Sentinel XS', + ['brand'] = 'Übermacht', + ['model'] = 'sentinel2', + ['price'] = 33000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `sentinel2`, + ['shop'] = 'pdm', + }, + ['windsor'] = { + ['name'] = 'Windsor', + ['brand'] = 'Enus', + ['model'] = 'windsor', + ['price'] = 27000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `windsor`, + ['shop'] = 'pdm', + }, + ['windsor2'] = { + ['name'] = 'Windsor Drop', + ['brand'] = 'Enus', + ['model'] = 'windsor2', + ['price'] = 34000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `windsor2`, + ['shop'] = 'pdm', + }, + ['zion'] = { + ['name'] = 'Zion', + ['brand'] = 'Übermacht', + ['model'] = 'zion', + ['price'] = 22000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `zion`, + ['shop'] = 'pdm', + }, + ['zion2'] = { + ['name'] = 'Zion Cabrio', + ['brand'] = 'Übermacht', + ['model'] = 'zion2', + ['price'] = 28000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `zion2`, + ['shop'] = 'pdm', + }, + ['previon'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Previon', + ['brand'] = 'Karin', + ['model'] = 'previon', + ['price'] = 149000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `previon`, + ['shop'] = 'pdm', + }, + ['champion'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Champion', + ['brand'] = 'Dewbauchee', + ['model'] = 'champion', + ['price'] = 205000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `champion`, + ['shop'] = 'pdm', + }, + ['driftfr36'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'FR36 (Drift)', + ['brand'] = 'Fathom', + ['model'] = 'driftfr36', + ['price'] = 29000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `driftfr36`, + ['shop'] = 'pdm', + }, + ['futo'] = { + ['name'] = 'Futo', + ['brand'] = 'Karin', + ['model'] = 'futo', + ['price'] = 17500, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `futo`, + ['shop'] = 'pdm', + }, + ['sentinel3'] = { + ['name'] = 'Sentinel Classic', + ['brand'] = 'Übermacht', + ['model'] = 'sentinel3', + ['price'] = 70000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `sentinel3`, + ['shop'] = 'pdm', + }, + ['kanjosj'] = { + ['name'] = 'Kanjo SJ', + ['brand'] = 'Dinka', + ['model'] = 'kanjosj', + ['price'] = 143000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `kanjosj`, + ['shop'] = 'pdm', + }, + ['postlude'] = { + ['name'] = 'Postlude', + ['brand'] = 'Dinka', + ['model'] = 'postlude', + ['price'] = 90000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `postlude`, + ['shop'] = 'pdm', + }, + ['tahoma'] = { + ['name'] = 'Tahoma Coupe', + ['brand'] = 'Declasse', + ['model'] = 'tahoma', + ['price'] = 12000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `tahoma`, + ['shop'] = 'pdm', + }, + ['broadway'] = { + ['name'] = 'Broadway', + ['brand'] = 'Classique', + ['model'] = 'broadway', + ['price'] = 20000, + ['category'] = 'Coupes', + ['categoryLabel'] = 'Coupes', + ['hash'] = `broadway`, + ['shop'] = 'pdm', + }, + + --- Cycles + ['bmx'] = { + ['name'] = 'BMX', + ['brand'] = 'Bike', + ['model'] = 'bmx', + ['price'] = 160, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `bmx`, + ['shop'] = 'pdm', + }, + ['cruiser'] = { + ['name'] = 'Cruiser', + ['brand'] = 'Bike', + ['model'] = 'cruiser', + ['price'] = 510, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `cruiser`, + ['shop'] = 'pdm', + }, + ['fixter'] = { + ['name'] = 'Fixter', + ['brand'] = 'Bike', + ['model'] = 'fixter', + ['price'] = 225, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `fixter`, + ['shop'] = 'pdm', + }, + ['scorcher'] = { + ['name'] = 'Scorcher', + ['brand'] = 'Bike', + ['model'] = 'scorcher', + ['price'] = 280, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `scorcher`, + ['shop'] = 'pdm', + }, + ['tribike'] = { + ['name'] = 'Whippet Race Bike', + ['brand'] = 'Bike', + ['model'] = 'tribike', + ['price'] = 500, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `tribike`, + ['shop'] = 'pdm', + }, + ['tribike2'] = { + ['name'] = 'Endurex Race Bike', + ['brand'] = 'Bike', + ['model'] = 'tribike2', + ['price'] = 700, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `tribike2`, + ['shop'] = 'pdm', + }, + ['tribike3'] = { + ['name'] = 'Tri-Cycles Race Bike', + ['brand'] = 'Bike', + ['model'] = 'tribike3', + ['price'] = 520, + ['category'] = 'Cycles', + ['categoryLabel'] = 'Cycles', + ['hash'] = `tribike3`, + ['shop'] = 'pdm', + }, + + --- Motorcycles + ['akuma'] = { + ['name'] = 'Akuma', + ['brand'] = 'Dinka', + ['model'] = 'akuma', + ['price'] = 55000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `akuma`, + ['shop'] = 'pdm', + }, + ['avarus'] = { + ['name'] = 'Avarus', + ['brand'] = 'LCC', + ['model'] = 'avarus', + ['price'] = 20000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `avarus`, + ['shop'] = 'pdm', + }, + ['bagger'] = { + ['name'] = 'Bagger', + ['brand'] = 'WMC', + ['model'] = 'bagger', + ['price'] = 13500, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `bagger`, + ['shop'] = 'pdm', + }, + ['bati'] = { + ['name'] = 'Bati 801', + ['brand'] = 'Pegassi', + ['model'] = 'bati', + ['price'] = 24000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `bati`, + ['shop'] = 'pdm', + }, + ['bati2'] = { + ['name'] = 'Bati 801RR', + ['brand'] = 'Pegassi', + ['model'] = 'bati2', + ['price'] = 19000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `bati2`, + ['shop'] = 'pdm', + }, + ['bf400'] = { + ['name'] = 'BF400', + ['brand'] = 'Nagasaki', + ['model'] = 'bf400', + ['price'] = 22000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `bf400`, + ['shop'] = 'pdm', + }, + ['carbonrs'] = { + ['name'] = 'Carbon RS', + ['brand'] = 'Nagasaki', + ['model'] = 'carbonrs', + ['price'] = 22000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `carbonrs`, + ['shop'] = 'pdm', + }, + ['chimera'] = { + ['name'] = 'Chimera', + ['brand'] = 'Nagasaki', + ['model'] = 'chimera', + ['price'] = 21000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `chimera`, + ['shop'] = 'pdm', + }, + ['cliffhanger'] = { + ['name'] = 'Cliffhanger', + ['brand'] = 'Western', + ['model'] = 'cliffhanger', + ['price'] = 28500, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `cliffhanger`, + ['shop'] = 'pdm', + }, + ['daemon'] = { + ['name'] = 'Daemon', + ['brand'] = 'WMC', + ['model'] = 'daemon', + ['price'] = 14000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `daemon`, + ['shop'] = 'pdm', + }, + ['daemon2'] = { + ['name'] = 'Daemon Custom', + ['brand'] = 'Western', + ['model'] = 'daemon2', + ['price'] = 23000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `daemon2`, + ['shop'] = 'pdm', + }, + ['defiler'] = { + ['name'] = 'Defiler', + ['brand'] = 'Shitzu', + ['model'] = 'defiler', + ['price'] = 30000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `defiler`, + ['shop'] = 'pdm', + }, + ['deathbike'] = { --DLC + ['name'] = 'Deathbike Apocalypse', + ['brand'] = 'Deathbike', + ['model'] = 'deathbike', + ['price'] = 30000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `deathbike`, + ['shop'] = 'pdm', + }, + ['deathbike2'] = { --DLC + ['name'] = 'Deathbike Future Shock', + ['brand'] = 'Deathbike', + ['model'] = 'deathbike2', + ['price'] = 30000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `deathbike2`, + ['shop'] = 'pdm', + }, + ['deathbike3'] = { --DLC + ['name'] = 'Deathbike Nightmare', + ['brand'] = 'Deathbike', + ['model'] = 'deathbike3', + ['price'] = 30000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `deathbike3`, + ['shop'] = 'pdm', + }, + ['diablous'] = { + ['name'] = 'Diablous', + ['brand'] = 'Principe', + ['model'] = 'diablous', + ['price'] = 30000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `diablous`, + ['shop'] = 'pdm', + }, + ['diablous2'] = { + ['name'] = 'Diablous Custom', + ['brand'] = 'Principe', + ['model'] = 'diablous2', + ['price'] = 38000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `diablous2`, + ['shop'] = 'pdm', + }, + ['double'] = { + ['name'] = 'Double-T', + ['brand'] = 'Dinka', + ['model'] = 'double', + ['price'] = 28000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `double`, + ['shop'] = 'pdm', + }, + ['enduro'] = { + ['name'] = 'Enduro', + ['brand'] = 'Dinka', + ['model'] = 'enduro', + ['price'] = 5500, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `enduro`, + ['shop'] = 'pdm', + }, + ['esskey'] = { + ['name'] = 'Esskey', + ['brand'] = 'Pegassi', + ['model'] = 'esskey', + ['price'] = 12000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `esskey`, + ['shop'] = 'pdm', + }, + ['faggio'] = { + ['name'] = 'Faggio Sport', + ['brand'] = 'Pegassi', + ['model'] = 'faggio', + ['price'] = 2000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `faggio`, + ['shop'] = 'pdm', + }, + ['faggio2'] = { + ['name'] = 'Faggio', + ['brand'] = 'Pegassi', + ['model'] = 'faggio2', + ['price'] = 1900, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `faggio2`, + ['shop'] = 'pdm', + }, + ['faggio3'] = { + ['name'] = 'Faggio Mod', + ['brand'] = 'Pegassi', + ['model'] = 'faggio3', + ['price'] = 2500, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `faggio3`, + ['shop'] = 'pdm', + }, + ['fcr'] = { + ['name'] = 'FCR 1000', + ['brand'] = 'Pegassi', + ['model'] = 'fcr', + ['price'] = 5000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `fcr`, + ['shop'] = 'pdm', + }, + ['fcr2'] = { + ['name'] = 'FCR 1000 Custom', + ['brand'] = 'Pegassi', + ['model'] = 'fcr2', + ['price'] = 19000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `fcr2`, + ['shop'] = 'pdm', + }, + ['gargoyle'] = { + ['name'] = 'Gargoyle', + ['brand'] = 'Western', + ['model'] = 'gargoyle', + ['price'] = 32000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `gargoyle`, + ['shop'] = 'pdm', + }, + ['hakuchou'] = { + ['name'] = 'Hakuchou', + ['brand'] = 'Shitzu', + ['model'] = 'hakuchou', + ['price'] = 17000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `hakuchou`, + ['shop'] = 'pdm', + }, + ['hakuchou2'] = { + ['name'] = 'Hakuchou Drag', + ['brand'] = 'Shitzu', + ['model'] = 'hakuchou2', + ['price'] = 45000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `hakuchou2`, + ['shop'] = 'pdm', + }, + ['hexer'] = { + ['name'] = 'Hexer', + ['brand'] = 'LCC', + ['model'] = 'hexer', + ['price'] = 16000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `hexer`, + ['shop'] = 'pdm', + }, + ['innovation'] = { + ['name'] = 'Innovation', + ['brand'] = 'LLC', + ['model'] = 'innovation', + ['price'] = 33500, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `innovation`, + ['shop'] = 'pdm', + }, + ['lectro'] = { + ['name'] = 'Lectro', + ['brand'] = 'Principe', + ['model'] = 'lectro', + ['price'] = 28000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `lectro`, + ['shop'] = 'pdm', + }, + ['manchez'] = { + ['name'] = 'Manchez', + ['brand'] = 'Maibatsu', + ['model'] = 'manchez', + ['price'] = 8300, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `manchez`, + ['shop'] = 'pdm', + }, + ['nemesis'] = { + ['name'] = 'Nemesis', + ['brand'] = 'Principe', + ['model'] = 'nemesis', + ['price'] = 20000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `nemesis`, + ['shop'] = 'pdm', + }, + ['nightblade'] = { + ['name'] = 'Nightblade', + ['brand'] = 'WMC', + ['model'] = 'nightblade', + ['price'] = 23000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `nightblade`, + ['shop'] = 'pdm', + }, + ['pcj'] = { + ['name'] = 'PCJ-600', + ['brand'] = 'Shitzu', + ['model'] = 'pcj', + ['price'] = 15000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `pcj`, + ['shop'] = 'pdm', + }, + ['ratbike'] = { + ['name'] = 'Rat Bike', + ['brand'] = 'Western', + ['model'] = 'ratbike', + ['price'] = 3000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `ratbike`, + ['shop'] = 'pdm', + }, + ['ruffian'] = { + ['name'] = 'Ruffian', + ['brand'] = 'Pegassi', + ['model'] = 'ruffian', + ['price'] = 25000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `ruffian`, + ['shop'] = 'pdm', + }, + ['sanchez'] = { + ['name'] = 'Sanchez Livery', + ['brand'] = 'Maibatsu', + ['model'] = 'sanchez', + ['price'] = 5300, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `sanchez`, + ['shop'] = 'pdm', + }, + ['sanchez2'] = { + ['name'] = 'Sanchez', + ['brand'] = 'Maibatsu', + ['model'] = 'sanchez2', + ['price'] = 5300, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `sanchez2`, + ['shop'] = 'pdm', + }, + ['sanctus'] = { + ['name'] = 'Sanctus', + ['brand'] = 'LCC', + ['model'] = 'sanctus', + ['price'] = 35000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `sanctus`, + ['shop'] = 'pdm', + }, + ['shotaro'] = { + ['name'] = 'Shotaro', + ['brand'] = 'Nagasaki', + ['model'] = 'shotaro', + ['price'] = 320000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `shotaro`, + ['shop'] = 'pdm', + }, + ['sovereign'] = { + ['name'] = 'Sovereign', + ['brand'] = 'WMC', + ['model'] = 'sovereign', + ['price'] = 8000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `sovereign`, + ['shop'] = 'pdm', + }, + ['stryder'] = { + ['name'] = 'Stryder', + ['brand'] = 'Nagasaki', + ['model'] = 'stryder', + ['price'] = 50000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `stryder`, + ['shop'] = 'pdm', + }, + ['thrust'] = { + ['name'] = 'Thrust', + ['brand'] = 'Dinka', + ['model'] = 'thrust', + ['price'] = 22000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `thrust`, + ['shop'] = 'pdm', + }, + ['vader'] = { + ['name'] = 'Vader', + ['brand'] = 'Shitzu', + ['model'] = 'vader', + ['price'] = 7200, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `vader`, + ['shop'] = 'pdm', + }, + ['vindicator'] = { + ['name'] = 'Vindicator', + ['brand'] = 'Dinka', + ['model'] = 'vindicator', + ['price'] = 19000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `vindicator`, + ['shop'] = 'pdm', + }, + ['vortex'] = { + ['name'] = 'Vortex', + ['brand'] = 'Pegassi', + ['model'] = 'vortex', + ['price'] = 31000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `vortex`, + ['shop'] = 'pdm', + }, + ['wolfsbane'] = { + ['name'] = 'Wolfsbane', + ['brand'] = 'Western', + ['model'] = 'wolfsbane', + ['price'] = 14000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `wolfsbane`, + ['shop'] = 'pdm', + }, + ['zombiea'] = { + ['name'] = 'Zombie Bobber', + ['brand'] = 'Western', + ['model'] = 'zombiea', + ['price'] = 28000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `zombiea`, + ['shop'] = 'pdm', + }, + ['zombieb'] = { + ['name'] = 'Zombie Chopper', + ['brand'] = 'Western', + ['model'] = 'zombieb', + ['price'] = 27000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `zombieb`, + ['shop'] = 'pdm', + }, + ['manchez2'] = { + ['name'] = 'Manchez Scout', + ['brand'] = 'Maibatsu', + ['model'] = 'manchez2', + ['price'] = 14000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `manchez2`, + ['shop'] = 'pdm', + }, + ['shinobi'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Shinobi', + ['brand'] = 'Nagasaki', + ['model'] = 'shinobi', + ['price'] = 25000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `shinobi`, + ['shop'] = 'pdm', + }, + ['reever'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Reever', + ['brand'] = 'Western', + ['model'] = 'reever', + ['price'] = 25000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `reever`, + ['shop'] = 'pdm', + }, + ['manchez3'] = { + ['name'] = 'Manchez Scout Classic', + ['brand'] = 'Maibatsu', + ['model'] = 'manchez3', + ['price'] = 15000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `manchez3`, + ['shop'] = 'pdm', + }, + ['powersurge'] = { + ['name'] = 'Powersurge', + ['brand'] = 'Western', + ['model'] = 'powersurge', + ['price'] = 7000, + ['category'] = 'Motorcycles', + ['categoryLabel'] = 'Motorcycles', + ['hash'] = `powersurge`, + ['shop'] = 'pdm', + }, + + --- Muscle + ['blade'] = { + ['name'] = 'Blade', + ['brand'] = 'Vapid', + ['model'] = 'blade', + ['price'] = 23500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `blade`, + ['shop'] = 'pdm', + }, + ['buccaneer'] = { + ['name'] = 'Buccaneer', + ['brand'] = 'Albany', + ['model'] = 'buccaneer', + ['price'] = 22500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `buccaneer`, + ['shop'] = 'pdm', + }, + ['buccaneer2'] = { + ['name'] = 'Buccaneer Rider', + ['brand'] = 'Albany', + ['model'] = 'buccaneer2', + ['price'] = 24500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `buccaneer2`, + ['shop'] = 'pdm', + }, + ['chino'] = { + ['name'] = 'Chino', + ['brand'] = 'Vapid', + ['model'] = 'chino', + ['price'] = 5000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `chino`, + ['shop'] = 'pdm', + }, + ['chino2'] = { + ['name'] = 'Chino Luxe', + ['brand'] = 'Vapid', + ['model'] = 'chino2', + ['price'] = 8000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `chino2`, + ['shop'] = 'pdm', + }, + ['clique'] = { --DLC + ['name'] = 'Clique', + ['brand'] = 'Vapid', + ['model'] = 'clique', + ['price'] = 20000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `clique`, + ['shop'] = 'pdm', + }, + ['coquette3'] = { + ['name'] = 'Coquette BlackFin', + ['brand'] = 'Invetero', + ['model'] = 'coquette3', + ['price'] = 180000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `coquette3`, + ['shop'] = 'pdm', + }, + ['deviant'] = { --DLC + ['name'] = 'Deviant', + ['brand'] = 'Schyster', + ['model'] = 'deviant', + ['price'] = 70000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `deviant`, + ['shop'] = 'pdm', + }, + ['dominator'] = { + ['name'] = 'Dominator', + ['brand'] = 'Vapid', + ['model'] = 'dominator', + ['price'] = 62500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator`, + ['shop'] = 'pdm', + }, + ['dominator2'] = { + ['name'] = 'Pißwasser Dominator', + ['brand'] = 'Vapid', + ['model'] = 'dominator2', + ['price'] = 50000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator2`, + ['shop'] = 'pdm', + }, + ['dominator3'] = { + ['name'] = 'Dominator GTX', + ['brand'] = 'Vapid', + ['model'] = 'dominator3', + ['price'] = 70000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator3`, + ['shop'] = 'pdm', + }, + ['dominator4'] = { --DLC + ['name'] = 'Dominator Arena', + ['brand'] = 'Vapid', + ['model'] = 'dominator4', + ['price'] = 200000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator4`, + ['shop'] = 'pdm', + }, + ['dominator7'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Dominator ASP', + ['brand'] = 'Vapid', + ['model'] = 'dominator7', + ['price'] = 110000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator7`, + ['shop'] = 'pdm', + }, + ['dominator8'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Dominator GTT', + ['brand'] = 'Vapid', + ['model'] = 'dominator8', + ['price'] = 80000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dominator8`, + ['shop'] = 'pdm', + }, + ['dukes'] = { + ['name'] = 'Dukes', + ['brand'] = 'Imponte', + ['model'] = 'dukes', + ['price'] = 23500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dukes`, + ['shop'] = 'pdm', + }, + ['dukes2'] = { + ['name'] = 'Duke O\'Death', + ['brand'] = 'Imponte', + ['model'] = 'dukes2', + ['price'] = 60000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dukes2`, + ['shop'] = 'pdm', + }, + ['dukes3'] = { + ['name'] = 'Beater Dukes', + ['brand'] = 'Imponte', + ['model'] = 'dukes3', + ['price'] = 45000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `dukes3`, + ['shop'] = 'pdm', + }, + ['faction'] = { + ['name'] = 'Faction', + ['brand'] = 'Willard', + ['model'] = 'faction', + ['price'] = 17000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `faction`, + ['shop'] = 'pdm', + }, + ['faction2'] = { + ['name'] = 'Faction Rider', + ['brand'] = 'Willard', + ['model'] = 'faction2', + ['price'] = 19000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `faction2`, + ['shop'] = 'pdm', + }, + ['faction3'] = { + ['name'] = 'Faction Custom Donk', + ['brand'] = 'Willard', + ['model'] = 'faction3', + ['price'] = 35000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `faction3`, + ['shop'] = 'pdm', + }, + ['ellie'] = { + ['name'] = 'Ellie', + ['brand'] = 'Vapid', + ['model'] = 'ellie', + ['price'] = 42250, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `ellie`, + ['shop'] = 'pdm', + }, + ['gauntlet'] = { + ['name'] = 'Gauntlet', + ['brand'] = 'Bravado', + ['model'] = 'gauntlet', + ['price'] = 28500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `gauntlet`, + ['shop'] = 'pdm', + }, + ['gauntlet2'] = { + ['name'] = 'Redwood Gauntlet', + ['brand'] = 'Bravado', + ['model'] = 'gauntlet2', + ['price'] = 70000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `gauntlet2`, + ['shop'] = 'pdm', + }, + ['gauntlet3'] = { --DLC + ['name'] = 'Classic Gauntlet', + ['brand'] = 'Bravado', + ['model'] = 'gauntlet3', + ['price'] = 75000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `gauntlet3`, + ['shop'] = 'pdm', + }, + ['gauntlet4'] = { --DLC + ['name'] = 'Gauntlet Hellfire', + ['brand'] = 'Bravado', + ['model'] = 'gauntlet4', + ['price'] = 80000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `gauntlet4`, + ['shop'] = 'pdm', + }, + ['gauntlet5'] = { + ['name'] = 'Gauntlet Classic Custom', + ['brand'] = 'Bravado', + ['model'] = 'gauntlet5', + ['price'] = 120000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `gauntlet5`, + ['shop'] = 'pdm', + }, + ['hermes'] = { + ['name'] = 'Hermes', + ['brand'] = 'Albany', + ['model'] = 'hermes', + ['price'] = 535000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `hermes`, + ['shop'] = 'pdm', + }, + ['hotknife'] = { + ['name'] = 'Hotknife', + ['brand'] = 'Vapid', + ['model'] = 'hotknife', + ['price'] = 90000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `hotknife`, + ['shop'] = 'pdm', + }, + ['hustler'] = { + ['name'] = 'Hustler', + ['brand'] = 'Vapid', + ['model'] = 'hustler', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `hustler`, + ['shop'] = 'pdm', + }, + ['impaler'] = { --DLC + ['name'] = 'Impaler', + ['brand'] = 'Vapid', + ['model'] = 'impaler', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `impaler`, + ['shop'] = 'pdm', + }, + ['impaler2'] = { --DLC + ['name'] = 'Impaler Arena', + ['brand'] = 'Vapid', + ['model'] = 'impaler2', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `impaler2`, + ['shop'] = 'pdm', + }, + ['impaler3'] = { --DLC + ['name'] = 'Impaler Future Shock', + ['brand'] = 'Vapid', + ['model'] = 'impaler3', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `impaler3`, + ['shop'] = 'pdm', + }, + ['impaler4'] = { --DLC + ['name'] = 'Impaler Nightmare', + ['brand'] = 'Vapid', + ['model'] = 'impaler4', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `impaler4`, + ['shop'] = 'pdm', + }, + ['imperator'] = { --DLC + ['name'] = 'Imperator Arena', + ['brand'] = 'Vapid', + ['model'] = 'imperator', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `imperator`, + ['shop'] = 'pdm', + }, + ['imperator2'] = { --DLC + ['name'] = 'imperator Future Shock', + ['brand'] = 'Vapid', + ['model'] = 'imperator2', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `imperator2`, + ['shop'] = 'pdm', + }, + ['imperator3'] = { --DLC + ['name'] = 'Imperator Nightmare', + ['brand'] = 'Vapid', + ['model'] = 'imperator3', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `imperator3`, + ['shop'] = 'pdm', + }, + ['lurcher'] = { + ['name'] = 'Lurcher', + ['brand'] = 'Bravado', + ['model'] = 'lurcher', + ['price'] = 21000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `lurcher`, + ['shop'] = 'pdm', + }, + ['nightshade'] = { + ['name'] = 'Nightshade', + ['brand'] = 'Imponte', + ['model'] = 'nightshade', + ['price'] = 70000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `nightshade`, + ['shop'] = 'pdm', + }, + ['phoenix'] = { + ['name'] = 'Phoenix', + ['brand'] = 'Imponte', + ['model'] = 'phoenix', + ['price'] = 65000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `phoenix`, + ['shop'] = 'pdm', + }, + ['picador'] = { + ['name'] = 'Picador', + ['brand'] = 'Cheval', + ['model'] = 'picador', + ['price'] = 20000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `picador`, + ['shop'] = 'pdm', + }, + ['ratloader2'] = { + ['name'] = 'Ratloader', + ['brand'] = 'Ratloader2', + ['model'] = 'ratloader2', + ['price'] = 20000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `ratloader2`, + ['shop'] = 'pdm', + }, + ['ruiner'] = { + ['name'] = 'Ruiner', + ['brand'] = 'Imponte', + ['model'] = 'ruiner', + ['price'] = 29000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `ruiner`, + ['shop'] = 'pdm', + }, + ['ruiner2'] = { + ['name'] = 'Ruiner 2000', + ['brand'] = 'Imponte', + ['model'] = 'ruiner2', + ['price'] = 50000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `ruiner2`, + ['shop'] = 'pdm', + }, + ['sabregt'] = { + ['name'] = 'Sabre GT Turbo', + ['brand'] = 'Declasse', + ['model'] = 'sabregt', + ['price'] = 23000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `sabregt`, + ['shop'] = 'pdm', + }, + ['sabregt2'] = { + ['name'] = 'Sabre GT Turbo Custom', + ['brand'] = 'Declasse', + ['model'] = 'sabregt2', + ['price'] = 26500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `sabregt2`, + ['shop'] = 'pdm', + }, + ['slamvan'] = { + ['name'] = 'Slam Van', + ['brand'] = 'Vapid', + ['model'] = 'slamvan', + ['price'] = 30000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `slamvan`, + ['shop'] = 'pdm', + }, + ['slamvan2'] = { + ['name'] = 'Lost Slam Van', + ['brand'] = 'Vapid', + ['model'] = 'slamvan2', + ['price'] = 90000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `slamvan2`, + ['shop'] = 'pdm', + }, + ['slamvan3'] = { + ['name'] = 'Slam Van Custom', + ['brand'] = 'Vapid', + ['model'] = 'slamvan3', + ['price'] = 17000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `slamvan3`, + ['shop'] = 'pdm', + }, + ['stalion'] = { + ['name'] = 'Stallion', + ['brand'] = 'Declasse', + ['model'] = 'stalion', + ['price'] = 33000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `stalion`, + ['shop'] = 'pdm', + }, + ['stalion2'] = { + ['name'] = 'Stallion Burgershot', + ['brand'] = 'Declasse', + ['model'] = 'stalion2', + ['price'] = 40000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `stalion2`, + ['shop'] = 'pdm', + }, + ['tampa'] = { + ['name'] = 'Tampa', + ['brand'] = 'Declasse', + ['model'] = 'tampa', + ['price'] = 24500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `tampa`, + ['shop'] = 'pdm', + }, + ['tulip'] = { --DLC + ['name'] = 'Tulip', + ['brand'] = 'Declasse', + ['model'] = 'tulip', + ['price'] = 80000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `tulip`, + ['shop'] = 'pdm', + }, + ['vamos'] = { --DLC + ['name'] = 'Vamos', + ['brand'] = 'Declasse', + ['model'] = 'vamos', + ['price'] = 30000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `vamos`, + ['shop'] = 'pdm', + }, + ['vigero'] = { + ['name'] = 'Vigero', + ['brand'] = 'Declasse', + ['model'] = 'vigero', + ['price'] = 39500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `vigero`, + ['shop'] = 'pdm', + }, + ['virgo'] = { + ['name'] = 'Virgo', + ['brand'] = 'Albany', + ['model'] = 'virgo', + ['price'] = 22000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `virgo`, + ['shop'] = 'pdm', + }, + ['virgo2'] = { + ['name'] = 'Virgo Custom Classic', + ['brand'] = 'Dundreary', + ['model'] = 'virgo2', + ['price'] = 21000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `virgo2`, + ['shop'] = 'pdm', + }, + ['virgo3'] = { + ['name'] = 'Virgo Classic', + ['brand'] = 'Dundreary', + ['model'] = 'virgo3', + ['price'] = 21000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `virgo3`, + ['shop'] = 'pdm', + }, + ['voodoo'] = { + ['name'] = 'Voodoo', + ['brand'] = 'Declasse', + ['model'] = 'voodoo', + ['price'] = 13000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `voodoo`, + ['shop'] = 'pdm', + }, + ['yosemite'] = { + ['name'] = 'Yosemite', + ['brand'] = 'Declasse', + ['model'] = 'yosemite', + ['price'] = 19500, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `yosemite`, + ['shop'] = 'pdm', + }, + ['yosemite2'] = { + ['name'] = 'Yosemite Drift', + ['brand'] = 'Declasse', + ['model'] = 'yosemite2', + ['price'] = 55000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `yosemite2`, + ['shop'] = 'pdm', + }, + ['buffalo4'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Buffalo STX', + ['brand'] = 'Bravado', + ['model'] = 'buffalo4', + ['price'] = 345000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `buffalo4`, + ['shop'] = 'pdm', + }, + ['tampa2'] = { + ['name'] = 'Drift Tampa', + ['brand'] = 'Declasse', + ['model'] = 'tampa2', + ['price'] = 80000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `tampa2`, + ['shop'] = 'pdm', + }, + ['manana'] = { + ['name'] = 'Manana', + ['brand'] = 'Albany', + ['model'] = 'manana', + ['price'] = 12800, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `manana`, + ['shop'] = 'pdm', + }, + ['manana2'] = { + ['name'] = 'Manana Custom', + ['brand'] = 'Albany', + ['model'] = 'manana2', + ['price'] = 24000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `manana2`, + ['shop'] = 'pdm', + }, + ['slamtruck'] = { + ['name'] = 'Slam Truck', + ['brand'] = 'Vapid', + ['model'] = 'slamtruck', + ['price'] = 100000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `slamtruck`, + ['shop'] = 'pdm', + }, + ['greenwood'] = { + ['name'] = 'Greenwood', + ['brand'] = 'Bravado', + ['model'] = 'greenwood', + ['price'] = 105000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `greenwood`, + ['shop'] = 'pdm', + }, + ['ruiner4'] = { + ['name'] = 'Ruiner ZZ-8', + ['brand'] = 'Imponte', + ['model'] = 'ruiner4', + ['price'] = 85000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `ruiner4`, + ['shop'] = 'pdm', + }, + ['vigero2'] = { + ['name'] = 'Vigero ZX', + ['brand'] = 'Declasse', + ['model'] = 'vigero2', + ['price'] = 105000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `vigero2`, + ['shop'] = 'pdm', + }, + ['weevil2'] = { + ['name'] = 'Weevil Custom', + ['brand'] = 'BF', + ['model'] = 'weevil2', + ['price'] = 95000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `weevil2`, + ['shop'] = 'pdm', + }, + ['tulip2'] = { + ['name'] = 'Tulip M-100', + ['brand'] = 'Declasse', + ['model'] = 'tulip2', + ['price'] = 80000, + ['category'] = 'Muscle', + ['categoryLabel'] = 'Muscle', + ['hash'] = `tulip2`, + ['shop'] = 'pdm', + }, + + --- Off-Road + ['yosemite3'] = { + ['name'] = 'Yosemite Rancher', + ['brand'] = 'Declasse', + ['price'] = 425000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'yosemite3', + ['hash'] = `yosemite3`, + ['shop'] = 'pdm', + }, + ['bfinjection'] = { + ['name'] = 'Bf Injection', + ['brand'] = 'Annis', + ['price'] = 9000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'bfinjection', + ['hash'] = `bfinjection`, + ['shop'] = 'pdm', + }, + ['bifta'] = { + ['name'] = 'Bifta', + ['brand'] = 'Annis', + ['price'] = 15500, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'bifta', + ['hash'] = `bifta`, + ['shop'] = 'pdm', + }, + ['blazer'] = { + ['name'] = 'Blazer', + ['brand'] = 'Annis', + ['price'] = 7500, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'blazer', + ['hash'] = `blazer`, + ['shop'] = 'pdm', + }, + ['blazer2'] = { + ['name'] = 'Blazer Lifeguard', + ['brand'] = 'Nagasaki', + ['model'] = 'blazer2', + ['price'] = 7000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `blazer2`, + ['shop'] = 'pdm', + }, + ['blazer3'] = { + ['name'] = 'Blazer Hot Rod', + ['brand'] = 'Nagasaki', + ['model'] = 'blazer3', + ['price'] = 7000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `blazer3`, + ['shop'] = 'pdm', + }, + ['blazer4'] = { + ['name'] = 'Blazer Sport', + ['brand'] = 'Annis', + ['price'] = 9250, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'blazer4', + ['hash'] = `blazer4`, + ['shop'] = 'pdm', + }, + ['blazer5'] = { + ['name'] = 'Blazer Aqua', + ['brand'] = 'Nagasaki', + ['model'] = 'blazer5', + ['price'] = 40000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `blazer5`, + ['shop'] = 'pdm', + }, + ['brawler'] = { + ['name'] = 'Brawler', + ['brand'] = 'Annis', + ['price'] = 40000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'brawler', + ['hash'] = `brawler`, + ['shop'] = 'pdm', + }, + ['caracara'] = { + ['name'] = 'Caracara', + ['brand'] = 'Vapid', + ['model'] = 'caracara', + ['price'] = 60000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `caracara`, + ['shop'] = 'pdm', + }, + ['caracara2'] = { --DLC + ['name'] = 'Caracara 4x4', + ['brand'] = 'Vapid', + ['model'] = 'caracara2', + ['price'] = 80000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `caracara2`, + ['shop'] = 'pdm', + }, + ['dubsta3'] = { + ['name'] = 'Dubsta 6x6', + ['brand'] = 'Annis', + ['price'] = 34000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'dubsta3', + ['hash'] = `dubsta3`, + ['shop'] = 'pdm', + }, + ['dune'] = { + ['name'] = 'Dune Buggy', + ['brand'] = 'Annis', + ['price'] = 14000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'dune', + ['hash'] = `dune`, + ['shop'] = 'pdm', + }, + ['everon'] = { + ['name'] = 'Everon', + ['brand'] = 'Karin', + ['model'] = 'everon', + ['price'] = 60000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `everon`, + ['shop'] = 'pdm', + }, + ['freecrawler'] = { --DLC + ['name'] = 'Freecrawler', + ['brand'] = 'Canis', + ['model'] = 'freecrawler', + ['price'] = 24000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `freecrawler`, + ['shop'] = 'pdm', + }, + ['hellion'] = { --DLC + ['name'] = 'Hellion', + ['brand'] = 'Annis', + ['model'] = 'hellion', + ['price'] = 38000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `hellion`, + ['shop'] = 'pdm', + }, + ['kalahari'] = { + ['name'] = 'Kalahari', + ['brand'] = 'Canis', + ['model'] = 'kalahari', + ['price'] = 14000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `kalahari`, + ['shop'] = 'pdm', + }, + ['kamacho'] = { + ['name'] = 'Kamacho', + ['brand'] = 'Canis', + ['model'] = 'kamacho', + ['price'] = 50000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `kamacho`, + ['shop'] = 'pdm', + }, + ['mesa3'] = { + ['name'] = 'Mesa Merryweather', + ['brand'] = 'Canis', + ['model'] = 'mesa3', + ['price'] = 400000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `mesa3`, + ['shop'] = 'pdm', + }, + ['outlaw'] = { + ['name'] = 'Outlaw', + ['brand'] = 'Nagasaki', + ['model'] = 'outlaw', + ['price'] = 15000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `outlaw`, + ['shop'] = 'pdm', + }, + ['rancherxl'] = { + ['name'] = 'Rancher XL', + ['brand'] = 'Declasse', + ['model'] = 'rancherxl', + ['price'] = 24000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `rancherxl`, + ['shop'] = 'pdm', + }, + ['rebel2'] = { + ['name'] = 'Rebel', + ['brand'] = 'Vapid', + ['model'] = 'rebel2', + ['price'] = 20000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `rebel2`, + ['shop'] = 'pdm', + }, + ['riata'] = { + ['name'] = 'Riata', + ['brand'] = 'Vapid', + ['model'] = 'riata', + ['price'] = 380000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `riata`, + ['shop'] = 'pdm', + }, + ['sandking'] = { + ['name'] = 'Sandking XL', + ['brand'] = 'Vapid', + ['price'] = 25000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'sandking', + ['hash'] = `sandking`, + ['shop'] = 'pdm', + }, + ['sandking2'] = { + ['name'] = 'Sandking SWB', + ['brand'] = 'Vapid', + ['price'] = 38000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'sandking2', + ['hash'] = `sandking2`, + ['shop'] = 'pdm', + }, + ['trophytruck'] = { + ['name'] = 'Trophy Truck', + ['brand'] = 'Vapid', + ['price'] = 60000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'trophytruck', + ['hash'] = `trophytruck`, + ['shop'] = 'pdm', + }, + ['trophytruck2'] = { + ['name'] = 'Desert Raid', + ['brand'] = 'Vapid', + ['price'] = 80000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'trophytruck2', + ['hash'] = `trophytruck2`, + ['shop'] = 'pdm', + }, + ['vagrant'] = { + ['name'] = 'Vagrant', + ['brand'] = 'Maxwell', + ['price'] = 50000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'vagrant', + ['hash'] = `vagrant`, + ['shop'] = 'pdm', + }, + ['verus'] = { + ['name'] = 'Verus', + ['brand'] = 'Dinka', + ['price'] = 20000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'verus', + ['hash'] = `verus`, + ['shop'] = 'pdm', + }, + ['winky'] = { + ['name'] = 'Winky', + ['brand'] = 'Vapid', + ['price'] = 10000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['model'] = 'winky', + ['hash'] = `winky`, + ['shop'] = 'pdm', + }, + ['mesa'] = { + ['name'] = 'Mesa', + ['brand'] = 'Canis', + ['model'] = 'mesa', + ['price'] = 12000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `mesa`, + ['shop'] = 'pdm', + }, + ['draugur'] = { + ['name'] = 'Draugur', + ['brand'] = 'Declasse', + ['model'] = 'draugur', + ['price'] = 99000, + ['category'] = 'Off Road', + ['categoryLabel'] = 'Off Road', + ['hash'] = `draugur`, + ['shop'] = 'pdm', + }, + + --- SUVs + ['baller'] = { + ['name'] = 'Baller', + ['brand'] = 'Gallivanter', + ['model'] = 'baller', + ['price'] = 22000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller`, + ['shop'] = 'pdm', + }, + ['baller2'] = { + ['name'] = 'Baller II', + ['brand'] = 'Gallivanter', + ['model'] = 'baller2', + ['price'] = 15000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller2`, + ['shop'] = 'pdm', + }, + ['baller3'] = { + ['name'] = 'Baller LE', + ['brand'] = 'Gallivanter', + ['model'] = 'baller3', + ['price'] = 15000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller3`, + ['shop'] = 'pdm', + }, + ['baller4'] = { + ['name'] = 'Baller LE LWB', + ['brand'] = 'Gallivanter', + ['model'] = 'baller4', + ['price'] = 29000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller4`, + ['shop'] = 'pdm', + }, + ['baller5'] = { + ['name'] = 'Baller LE (Armored)', + ['brand'] = 'Gallivanter', + ['model'] = 'baller5', + ['price'] = 78000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller5`, + ['shop'] = 'pdm', + }, + ['baller6'] = { + ['name'] = 'Baller LE LWB (Armored)', + ['brand'] = 'Gallivanter', + ['model'] = 'baller6', + ['price'] = 82000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `baller6`, + ['shop'] = 'pdm', + }, + ['bjxl'] = { + ['name'] = 'BeeJay XL', + ['brand'] = 'Karin', + ['model'] = 'bjxl', + ['price'] = 19000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `bjxl`, + ['shop'] = 'pdm', + }, + ['cavalcade'] = { + ['name'] = 'Cavalcade', + ['brand'] = 'Albany', + ['model'] = 'cavalcade', + ['price'] = 14000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `cavalcade`, + ['shop'] = 'pdm', + }, + ['cavalcade2'] = { + ['name'] = 'Cavalcade II', + ['brand'] = 'Albany', + ['model'] = 'cavalcade2', + ['price'] = 16500, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `cavalcade2`, + ['shop'] = 'pdm', + }, + ['contender'] = { + ['name'] = 'Contender', + ['brand'] = 'Vapid', + ['model'] = 'contender', + ['price'] = 35000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `contender`, + ['shop'] = 'pdm', + }, + ['dubsta'] = { + ['name'] = 'Dubsta', + ['brand'] = 'Benefactor', + ['model'] = 'dubsta', + ['price'] = 19000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `dubsta`, + ['shop'] = 'pdm', + }, + ['dubsta2'] = { + ['name'] = 'Dubsta Luxury', + ['brand'] = 'Benefactor', + ['model'] = 'dubsta2', + ['price'] = 19500, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `dubsta2`, + ['shop'] = 'pdm', + }, + ['fq2'] = { + ['name'] = 'FQ2', + ['brand'] = 'Fathom', + ['model'] = 'fq2', + ['price'] = 18500, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `fq2`, + ['shop'] = 'pdm', + }, + ['granger'] = { + ['name'] = 'Granger', + ['brand'] = 'Declasse', + ['model'] = 'granger', + ['price'] = 22000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `granger`, + ['shop'] = 'pdm', + }, + ['gresley'] = { + ['name'] = 'Gresley', + ['brand'] = 'Bravado', + ['model'] = 'gresley', + ['price'] = 25000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `gresley`, + ['shop'] = 'pdm', + }, + ['habanero'] = { + ['name'] = 'Habanero', + ['brand'] = 'Emperor', + ['model'] = 'habanero', + ['price'] = 20000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `habanero`, + ['shop'] = 'pdm', + }, + ['huntley'] = { + ['name'] = 'Huntley S', + ['brand'] = 'Enus', + ['model'] = 'huntley', + ['price'] = 24500, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `huntley`, + ['shop'] = 'pdm', + }, + ['landstalker'] = { + ['name'] = 'Landstalker', + ['brand'] = 'Dundreary', + ['model'] = 'landstalker', + ['price'] = 12000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `landstalker`, + ['shop'] = 'pdm', + }, + ['landstalker2'] = { + ['name'] = 'Landstalker XL', + ['brand'] = 'Dundreary', + ['model'] = 'landstalker2', + ['price'] = 26000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `landstalker2`, + ['shop'] = 'pdm', + }, + ['novak'] = { --DLC + ['name'] = 'Novak', + ['brand'] = 'Lampadati', + ['model'] = 'novak', + ['price'] = 70000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `novak`, + ['shop'] = 'pdm', + }, + ['patriot'] = { + ['name'] = 'Patriot', + ['brand'] = 'Mammoth', + ['model'] = 'patriot', + ['price'] = 21000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `patriot`, + ['shop'] = 'pdm', + }, + ['patriot2'] = { + ['name'] = 'Patriot Stretch', + ['brand'] = 'Mammoth', + ['model'] = 'patriot2', + ['price'] = 21000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `patriot2`, + ['shop'] = 'pdm', + }, + ['radi'] = { + ['name'] = 'Radius', + ['brand'] = 'Vapid', + ['model'] = 'radi', + ['price'] = 18000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `radi`, + ['shop'] = 'pdm', + }, + ['rebla'] = { + ['name'] = 'Rebla GTS', + ['brand'] = 'Übermacht', + ['model'] = 'rebla', + ['price'] = 21000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `rebla`, + ['shop'] = 'pdm', + }, + ['rocoto'] = { + ['name'] = 'Rocoto', + ['brand'] = 'Obey', + ['model'] = 'rocoto', + ['price'] = 13000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `rocoto`, + ['shop'] = 'pdm', + }, + ['seminole'] = { + ['name'] = 'Seminole', + ['brand'] = 'Canis', + ['model'] = 'seminole', + ['price'] = 20000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `seminole`, + ['shop'] = 'pdm', + }, + ['seminole2'] = { + ['name'] = 'Seminole Frontier', + ['brand'] = 'Canis', + ['model'] = 'seminole2', + ['price'] = 13000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `seminole2`, + ['shop'] = 'pdm', + }, + ['serrano'] = { + ['name'] = 'Serrano', + ['brand'] = 'Benefactor', + ['model'] = 'serrano', + ['price'] = 48000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `serrano`, + ['shop'] = 'pdm', + }, + ['toros'] = { --DLC + ['name'] = 'Toros', + ['brand'] = 'Pegassi', + ['model'] = 'toros', + ['price'] = 65000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `toros`, + ['shop'] = 'pdm', + }, + ['xls'] = { + ['name'] = 'XLS', + ['brand'] = 'Benefactor', + ['model'] = 'xls', + ['price'] = 17000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `xls`, + ['shop'] = 'pdm', + }, + ['granger2'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Granger 3600LX', + ['brand'] = 'Declasse', + ['model'] = 'granger2', + ['price'] = 221000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `granger2`, + ['shop'] = 'pdm', + }, + ['patriot3'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Patriot Military', + ['brand'] = 'Mil-Spec', + ['model'] = 'patriot3', + ['price'] = 270000, + ['category'] = 'SUVs', + ['categoryLabel'] = 'SUVs', + ['hash'] = `patriot3`, + ['shop'] = 'pdm', + }, + + --- Sedans + ['oracle'] = { + ['name'] = 'Oracle', + ['brand'] = 'Übermacht', + ['model'] = 'oracle', + ['price'] = 22000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `oracle`, + ['shop'] = 'pdm', + }, + ['asea'] = { + ['name'] = 'Asea', + ['brand'] = 'Declasse', + ['model'] = 'asea', + ['price'] = 2500, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `asea`, + ['shop'] = 'pdm', + }, + ['asterope'] = { + ['name'] = 'Asterope', + ['brand'] = 'Karin', + ['model'] = 'asterope', + ['price'] = 11000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `asterope`, + ['shop'] = 'pdm', + }, + ['cog55'] = { + ['name'] = 'Cognoscenti 55', + ['brand'] = 'Enus', + ['model'] = 'cog55', + ['price'] = 22000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `cog55`, + ['shop'] = 'pdm', + }, + ['cognoscenti'] = { + ['name'] = 'Cognoscenti', + ['brand'] = 'Enus', + ['model'] = 'cognoscenti', + ['price'] = 22500, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `cognoscenti`, + ['shop'] = 'pdm', + }, + ['emperor'] = { + ['name'] = 'Emperor', + ['brand'] = 'Albany', + ['model'] = 'emperor', + ['price'] = 4250, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `emperor`, + ['shop'] = 'pdm', + }, + ['fugitive'] = { + ['name'] = 'Fugitive', + ['brand'] = 'Cheval', + ['model'] = 'fugitive', + ['price'] = 20000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `fugitive`, + ['shop'] = 'pdm', + }, + ['glendale'] = { + ['name'] = 'Glendale', + ['brand'] = 'Benefactor', + ['model'] = 'glendale', + ['price'] = 3400, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `glendale`, + ['shop'] = 'pdm', + }, + ['glendale2'] = { + ['name'] = 'Glendale Custom', + ['brand'] = 'Benefactor', + ['model'] = 'glendale2', + ['price'] = 12000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `glendale2`, + ['shop'] = 'pdm', + }, + ['ingot'] = { + ['name'] = 'Ingot', + ['brand'] = 'Vulcar', + ['model'] = 'ingot', + ['price'] = 4999, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `ingot`, + ['shop'] = 'pdm', + }, + ['intruder'] = { + ['name'] = 'Intruder', + ['brand'] = 'Karin', + ['model'] = 'intruder', + ['price'] = 11250, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `intruder`, + ['shop'] = 'pdm', + }, + ['premier'] = { + ['name'] = 'Premier', + ['brand'] = 'Declasse', + ['model'] = 'premier', + ['price'] = 12000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `premier`, + ['shop'] = 'pdm', + }, + ['primo'] = { + ['name'] = 'Primo', + ['brand'] = 'Albany', + ['model'] = 'primo', + ['price'] = 5000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `primo`, + ['shop'] = 'pdm', + }, + ['primo2'] = { + ['name'] = 'Primo Custom', + ['brand'] = 'Albany', + ['model'] = 'primo2', + ['price'] = 14500, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `primo2`, + ['shop'] = 'pdm', + }, + ['regina'] = { + ['name'] = 'Regina', + ['brand'] = 'Dundreary', + ['model'] = 'regina', + ['price'] = 7000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `regina`, + ['shop'] = 'pdm', + }, + ['stafford'] = { --DLC + ['name'] = 'Stafford', + ['brand'] = 'Enus', + ['model'] = 'stafford', + ['price'] = 30000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `stafford`, + ['shop'] = 'pdm', + }, + ['stanier'] = { + ['name'] = 'Stanier', + ['brand'] = 'Vapid', + ['model'] = 'stanier', + ['price'] = 19000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `stanier`, + ['shop'] = 'pdm', + }, + ['stratum'] = { + ['name'] = 'Stratum', + ['brand'] = 'Zirconium', + ['model'] = 'stratum', + ['price'] = 15000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `stratum`, + ['shop'] = 'pdm', + }, + ['stretch'] = { + ['name'] = 'Stretch', + ['brand'] = 'Dundreary', + ['model'] = 'stretch', + ['price'] = 19000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `stretch`, + ['shop'] = 'pdm', + }, + ['superd'] = { + ['name'] = 'Super Diamond', + ['brand'] = 'Enus', + ['model'] = 'superd', + ['price'] = 17000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `superd`, + ['shop'] = 'pdm', + }, + ['surge'] = { + ['name'] = 'Surge', + ['brand'] = 'Cheval', + ['model'] = 'surge', + ['price'] = 20000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `surge`, + ['shop'] = 'pdm', + }, + ['tailgater'] = { + ['name'] = 'Tailgater', + ['brand'] = 'Obey', + ['model'] = 'tailgater', + ['price'] = 22000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `tailgater`, + ['shop'] = 'pdm', + }, + ['warrener'] = { + ['name'] = 'Warrener', + ['brand'] = 'Vulcar', + ['model'] = 'warrener', + ['price'] = 4000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `warrener`, + ['shop'] = 'pdm', + }, + ['washington'] = { + ['name'] = 'Washington', + ['brand'] = 'Albany', + ['model'] = 'washington', + ['price'] = 7000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `washington`, + ['shop'] = 'pdm', + }, + ['tailgater2'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Tailgater S', + ['brand'] = 'Obey', + ['model'] = 'tailgater2', + ['price'] = 51000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `tailgater2`, + ['shop'] = 'pdm', + }, + ['cinquemila'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Lampadati', + ['brand'] = 'Cinquemila', + ['model'] = 'cinquemila', + ['price'] = 125000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `cinquemila`, + ['shop'] = 'pdm', + }, + ['iwagen'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Obey', + ['brand'] = 'I-Wagen', + ['model'] = 'iwagen', + ['price'] = 225000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `iwagen`, + ['shop'] = 'pdm', + }, + ['astron'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Astron', + ['brand'] = 'Pfister', + ['model'] = 'astron', + ['price'] = 150000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `astron`, + ['shop'] = 'pdm', + }, + ['baller7'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Baller ST', + ['brand'] = 'Gallivanter', + ['model'] = 'baller7', + ['price'] = 145000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `baller7`, + ['shop'] = 'pdm', + }, + ['comet7'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Comet', + ['brand'] = 'S2 Cabrio', + ['model'] = 'comet7', + ['price'] = 25000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `comet7`, + ['shop'] = 'pdm', + }, + ['deity'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Deity', + ['brand'] = 'Enus', + ['model'] = 'deity', + ['price'] = 505000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `deity`, + ['shop'] = 'pdm', + }, + ['jubilee'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Jubilee', + ['brand'] = 'Enus', + ['model'] = 'jubilee', + ['price'] = 485000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `jubilee`, + ['shop'] = 'pdm', + }, + ['schafter2'] = { + ['name'] = 'Schafter', + ['brand'] = 'Benefactor', + ['model'] = 'schafter2', + ['price'] = 16000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `schafter2`, + ['shop'] = 'pdm', + }, + ['warrener2'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Warrener HKR', + ['brand'] = 'Vulcar', + ['model'] = 'warrener2', + ['price'] = 30000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `warrener2`, + ['shop'] = 'pdm', + }, + ['rhinehart'] = { + ['name'] = 'Rhinehart', + ['brand'] = 'Übermacht', + ['model'] = 'rhinehart ', + ['price'] = 105000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `rhinehart`, + ['shop'] = 'pdm', + }, + ['eudora'] = { + ['name'] = 'Eudora', + ['brand'] = 'Willard', + ['model'] = 'eudora', + ['price'] = 17000, + ['category'] = 'Sedans', + ['categoryLabel'] = 'Sedans', + ['hash'] = `eudora`, + ['shop'] = 'pdm', + }, + + --- Sports + ['alpha'] = { + ['name'] = 'Alpha', + ['brand'] = 'Albany', + ['model'] = 'alpha', + ['price'] = 53000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `alpha`, + ['shop'] = 'luxury', + }, + ['banshee'] = { + ['name'] = 'Banshee', + ['brand'] = 'Bravado', + ['model'] = 'banshee', + ['price'] = 56000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `banshee`, + ['shop'] = 'luxury', + }, + ['bestiagts'] = { + ['name'] = 'Bestia GTS', + ['brand'] = 'Grotti', + ['model'] = 'bestiagts', + ['price'] = 37000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `bestiagts`, + ['shop'] = 'luxury', + }, + ['buffalo'] = { + ['name'] = 'Buffalo', + ['brand'] = 'Bravado', + ['model'] = 'buffalo', + ['price'] = 18750, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `buffalo`, + ['shop'] = 'luxury', + }, + ['buffalo2'] = { + ['name'] = 'Buffalo S', + ['brand'] = 'Bravado', + ['model'] = 'buffalo2', + ['price'] = 24500, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `buffalo2`, + ['shop'] = 'luxury', + }, + ['carbonizzare'] = { + ['name'] = 'Carbonizzare', + ['brand'] = 'Grotti', + ['model'] = 'carbonizzare', + ['price'] = 155000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `carbonizzare`, + ['shop'] = 'luxury', + }, + ['comet2'] = { + ['name'] = 'Comet', + ['brand'] = 'Pfister', + ['model'] = 'comet2', + ['price'] = 130000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `comet2`, + ['shop'] = 'luxury', + }, + ['comet3'] = { + ['name'] = 'Comet Retro Custom', + ['brand'] = 'Pfister', + ['model'] = 'comet3', + ['price'] = 175000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `comet3`, + ['shop'] = 'luxury', + }, + ['comet4'] = { + ['name'] = 'Comet Safari', + ['brand'] = 'Pfister', + ['model'] = 'comet4', + ['price'] = 110000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `comet4`, + ['shop'] = 'luxury', + }, + ['comet5'] = { + ['name'] = 'Comet SR', + ['brand'] = 'Pfister', + ['model'] = 'comet5', + ['price'] = 155000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `comet5`, + ['shop'] = 'luxury', + }, + ['coquette'] = { + ['name'] = 'Coquette', + ['brand'] = 'Invetero', + ['model'] = 'coquette', + ['price'] = 145000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `coquette`, + ['shop'] = 'luxury', + }, + ['coquette4'] = { + ['name'] = 'Coquette D10', + ['brand'] = 'Invetero', + ['model'] = 'coquette4', + ['price'] = 220000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `coquette4`, + ['shop'] = 'luxury', + }, + ['drafter'] = { --DLC + ['name'] = '8F Drafter', + ['brand'] = 'Obey', + ['model'] = 'drafter', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `drafter`, + ['shop'] = 'luxury', + }, + ['elegy'] = { --DLC + ['name'] = 'Elegy Retro Custom', + ['brand'] = 'Annis', + ['model'] = 'elegy', + ['price'] = 145000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `elegy`, + ['shop'] = 'luxury', + }, + ['elegy2'] = { + ['name'] = 'Elegy RH8', + ['brand'] = 'Annis', + ['model'] = 'elegy2', + ['price'] = 150000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `elegy2`, + ['shop'] = 'luxury', + }, + ['feltzer2'] = { + ['name'] = 'Feltzer', + ['brand'] = 'Benefactor', + ['model'] = 'feltzer2', + ['price'] = 97000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `feltzer2`, + ['shop'] = 'luxury', + }, + ['flashgt'] = { + ['name'] = 'Flash GT', + ['brand'] = 'Vapid', + ['model'] = 'flashgt', + ['price'] = 48000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `flashgt`, + ['shop'] = 'luxury', + }, + ['furoregt'] = { + ['name'] = 'Furore GT', + ['brand'] = 'Lampadati', + ['model'] = 'furoregt', + ['price'] = 78000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `furoregt`, + ['shop'] = 'luxury', + }, + ['gb200'] = { + ['name'] = 'GB 200', + ['brand'] = 'Vapid', + ['model'] = 'gb200', + ['price'] = 140000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `gb200`, + ['shop'] = 'luxury', + }, + ['komoda'] = { + ['name'] = 'Komoda', + ['brand'] = 'Lampadati', + ['model'] = 'komoda', + ['price'] = 55000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `komoda`, + ['shop'] = 'luxury', + }, + ['imorgon'] = { + ['name'] = 'Imorgon', + ['brand'] = 'Överflöd', + ['model'] = 'imorgon', + ['price'] = 120000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `imorgon`, + ['shop'] = 'luxury', + }, + ['italigto'] = { --DLC + ['name'] = 'Itali GTO', + ['brand'] = 'Progen', + ['model'] = 'italigto', + ['price'] = 260000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `italigto`, + ['shop'] = 'luxury', + }, + ['jugular'] = { --DLC + ['name'] = 'Jugular', + ['brand'] = 'Ocelot', + ['model'] = 'jugular', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `jugular`, + ['shop'] = 'luxury', + }, + ['jester'] = { + ['name'] = 'Jester', + ['brand'] = 'Dinka', + ['model'] = 'jester', + ['price'] = 132250, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `jester`, + ['shop'] = 'luxury', + }, + ['jester2'] = { + ['name'] = 'Jester Racecar', + ['brand'] = 'Dinka', + ['model'] = 'jester2', + ['price'] = 210000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `jester2`, + ['shop'] = 'luxury', + }, + ['jester3'] = { + ['name'] = 'Jester Classic', + ['brand'] = 'Dinka', + ['model'] = 'jester3', + ['price'] = 85000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `jester3`, + ['shop'] = 'luxury', + }, + ['khamelion'] = { + ['name'] = 'Khamelion', + ['brand'] = 'Hijak', + ['model'] = 'khamelion', + ['price'] = 90000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `khamelion`, + ['shop'] = 'luxury', + }, + ['kuruma'] = { + ['name'] = 'Kuruma', + ['brand'] = 'Karin', + ['model'] = 'kuruma', + ['price'] = 72000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `kuruma`, + ['shop'] = 'luxury', + }, + ['kuruma2'] = { + ['name'] = 'kuruma2', + ['brand'] = 'Karin2', + ['model'] = 'kuruma2', + ['price'] = 72000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `kuruma2`, + ['shop'] = 'luxury', + }, + ['locust'] = { --DLC + ['name'] = 'Locust', + ['brand'] = 'Ocelot', + ['model'] = 'locust', + ['price'] = 200000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `locust`, + ['shop'] = 'luxury', + }, + ['lynx'] = { + ['name'] = 'Lynx', + ['brand'] = 'Ocelot', + ['model'] = 'lynx', + ['price'] = 150000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `lynx`, + ['shop'] = 'luxury', + }, + ['massacro'] = { + ['name'] = 'Massacro', + ['brand'] = 'Dewbauchee', + ['model'] = 'massacro', + ['price'] = 110000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `massacro`, + ['shop'] = 'luxury', + }, + ['massacro2'] = { + ['name'] = 'Massacro Racecar', + ['brand'] = 'Dewbauchee', + ['model'] = 'massacro2', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `massacro2`, + ['shop'] = 'luxury', + }, + ['neo'] = { --DLC + ['name'] = 'Neo', + ['brand'] = 'Vysser', + ['model'] = 'neo', + ['price'] = 230000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `neo`, + ['shop'] = 'luxury', + }, + ['neon'] = { --DLC + ['name'] = 'Neon', + ['brand'] = 'Pfister', + ['model'] = 'neon', + ['price'] = 220000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `neon`, + ['shop'] = 'luxury', + }, + ['ninef'] = { + ['name'] = '9F', + ['brand'] = 'Obey', + ['model'] = 'ninef', + ['price'] = 95000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `ninef`, + ['shop'] = 'luxury', + }, + ['ninef2'] = { + ['name'] = '9F Cabrio', + ['brand'] = 'Obey', + ['model'] = 'ninef2', + ['price'] = 105000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `ninef2`, + ['shop'] = 'luxury', + }, + ['omnis'] = { + ['name'] = 'Omnis', + ['brand'] = 'Wow', + ['model'] = 'omnis', + ['price'] = 90000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `omnis`, + ['shop'] = 'luxury', + }, + ['paragon'] = { --DLC + ['name'] = 'Paragon', + ['brand'] = 'Enus', + ['model'] = 'paragon', + ['price'] = 60000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `paragon`, + ['shop'] = 'luxury', + }, + ['pariah'] = { + ['name'] = 'Pariah', + ['brand'] = 'Ocelot', + ['model'] = 'pariah', + ['price'] = 90000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `pariah`, + ['shop'] = 'luxury', + }, + ['penumbra'] = { + ['name'] = 'Penumbra', + ['brand'] = 'Maibatsu', + ['model'] = 'penumbra', + ['price'] = 22000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `penumbra`, + ['shop'] = 'luxury', + }, + ['penumbra2'] = { + ['name'] = 'Penumbra FF', + ['brand'] = 'Maibatsu', + ['model'] = 'penumbra2', + ['price'] = 30000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `penumbra2`, + ['shop'] = 'luxury', + }, + ['rapidgt'] = { + ['name'] = 'Rapid GT', + ['brand'] = 'Dewbauchee', + ['model'] = 'rapidgt', + ['price'] = 86000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `rapidgt`, + ['shop'] = 'luxury', + }, + ['rapidgt2'] = { + ['name'] = 'Rapid GT Convertible', + ['brand'] = 'Dewbauchee', + ['model'] = 'rapidgt2', + ['price'] = 92000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `rapidgt2`, + ['shop'] = 'luxury', + }, + ['raptor'] = { + ['name'] = 'Raptor', + ['brand'] = 'BF', + ['model'] = 'raptor', + ['price'] = 90000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `raptor`, + ['shop'] = 'luxury', + }, + ['revolter'] = { + ['name'] = 'Revolter', + ['brand'] = 'Übermacht', + ['model'] = 'revolter', + ['price'] = 95000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `revolter`, + ['shop'] = 'luxury', + }, + ['ruston'] = { + ['name'] = 'Ruston', + ['brand'] = 'Hijak', + ['model'] = 'ruston', + ['price'] = 130000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `ruston`, + ['shop'] = 'luxury', + }, + ['schafter3'] = { + ['name'] = 'Schafter V12', + ['brand'] = 'Benefactor', + ['model'] = 'schafter3', + ['price'] = 35000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `schafter3`, + ['shop'] = 'luxury', + }, + ['schafter4'] = { + ['name'] = 'Schafter LWB', + ['brand'] = 'Benefactor', + ['model'] = 'schafter4', + ['price'] = 21000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `schafter4`, + ['shop'] = 'luxury', + }, + ['schlagen'] = { --DLC + ['name'] = 'Schlagen GT', + ['brand'] = 'Benefactor', + ['model'] = 'schlagen', + ['price'] = 160000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `schlagen`, + ['shop'] = 'luxury', + }, + ['schwarzer'] = { + ['name'] = 'Schwartzer', + ['brand'] = 'Benefactor', + ['model'] = 'schwarzer', + ['price'] = 47000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `schwarzer`, + ['shop'] = 'luxury', + }, + ['seven70'] = { + ['name'] = 'Seven-70', + ['brand'] = 'Dewbauchee', + ['model'] = 'seven70', + ['price'] = 140000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `seven70`, + ['shop'] = 'luxury', + }, + ['specter'] = { + ['name'] = 'Specter', + ['brand'] = 'Dewbauchee', + ['model'] = 'specter', + ['price'] = 160000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `specter`, + ['shop'] = 'luxury', + }, + ['streiter'] = { + ['name'] = 'Streiter', + ['brand'] = 'Benefactor', + ['model'] = 'streiter', + ['price'] = 40000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `streiter`, + ['shop'] = 'luxury', + }, + ['sugoi'] = { + ['name'] = 'Sugoi', + ['brand'] = 'Dinka', + ['model'] = 'sugoi', + ['price'] = 85000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sugoi`, + ['shop'] = 'luxury', + }, + ['sultan'] = { + ['name'] = 'Sultan', + ['brand'] = 'Karin', + ['model'] = 'sultan', + ['price'] = 50000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sultan`, + ['shop'] = 'luxury', + }, + ['sultan2'] = { + ['name'] = 'Sultan Custom', + ['brand'] = 'Karin', + ['model'] = 'sultan2', + ['price'] = 55000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sultan2`, + ['shop'] = 'luxury', + }, + ['surano'] = { + ['name'] = 'Surano', + ['brand'] = 'Benefactor', + ['model'] = 'surano', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `surano`, + ['shop'] = 'luxury', + }, + ['tropos'] = { + ['name'] = 'Tropos Rallye', + ['brand'] = 'Lampadati', + ['model'] = 'tropos', + ['price'] = 65000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `tropos`, + ['shop'] = 'luxury', + }, + ['verlierer2'] = { + ['name'] = 'Verlierer', + ['brand'] = 'Bravado', + ['model'] = 'verlierer2', + ['price'] = 90500, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `verlierer2`, + ['shop'] = 'luxury', + }, + ['vstr'] = { + ['name'] = 'V-STR', + ['brand'] = 'Albany', + ['model'] = 'vstr', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `vstr`, + ['shop'] = 'luxury', + }, + ['italirsx'] = { + ['name'] = 'Itali RSX', + ['brand'] = 'Progen', + ['model'] = 'italirsx', + ['price'] = 260000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `italirsx`, + ['shop'] = 'luxury', + }, + ['zr350'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'ZR350', + ['brand'] = 'Annis', + ['model'] = 'zr350', + ['price'] = 38000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `zr350`, + ['shop'] = 'luxury', + }, + ['calico'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Calico GTF', + ['brand'] = 'Karin', + ['model'] = 'calico', + ['price'] = 39000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `calico`, + ['shop'] = 'luxury', + }, + ['futo2'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Futo GTX', + ['brand'] = 'Karin', + ['model'] = 'futo2', + ['price'] = 39000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `futo2`, + ['shop'] = 'luxury', + }, + ['euros'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Euros', + ['brand'] = 'Annis', + ['model'] = 'euros', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `euros`, + ['shop'] = 'luxury', + }, + ['jester4'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Jester RR', + ['brand'] = 'Dinka', + ['model'] = 'jester4', + ['price'] = 240000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `jester4`, + ['shop'] = 'luxury', + }, + ['remus'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Remus', + ['brand'] = 'Annis', + ['model'] = 'remus', + ['price'] = 48000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `remus`, + ['shop'] = 'luxury', + }, + ['comet6'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Comet S2', + ['brand'] = 'Pfister', + ['model'] = 'comet6', + ['price'] = 230000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `comet6`, + ['shop'] = 'luxury', + }, + ['growler'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Growler', + ['brand'] = 'Pfister', + ['model'] = 'growler', + ['price'] = 205000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `growler`, + ['shop'] = 'luxury', + }, + ['vectre'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Vectre', + ['brand'] = 'Emperor', + ['model'] = 'vectre', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `vectre`, + ['shop'] = 'luxury', + }, + ['cypher'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Cypher', + ['brand'] = 'Übermacht', + ['model'] = 'cypher', + ['price'] = 155000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `cypher`, + ['shop'] = 'luxury', + }, + ['sultan3'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'Sultan Classic Custom', + ['brand'] = 'Karin', + ['model'] = 'sultan3', + ['price'] = 56000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sultan3`, + ['shop'] = 'luxury', + }, + ['rt3000'] = { --DLC +set sv_enforceGameBuild 2372 + ['name'] = 'RT3000', + ['brand'] = 'Dinka', + ['model'] = 'rt3000', + ['price'] = 65000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `rt3000`, + ['shop'] = 'luxury', + }, + ['cheetah2'] = { + ['name'] = 'Cheetah Classic', + ['brand'] = 'Grotti', + ['model'] = 'cheetah2', + ['price'] = 195000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `cheetah2`, + ['shop'] = 'luxury', + }, + ['sultanrs'] = { + ['name'] = 'Sultan RS', + ['brand'] = 'Karin', + ['model'] = 'sultanrs', + ['price'] = 76500, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sultanrs`, + ['shop'] = 'luxury', + }, + ['visione'] = { + ['name'] = 'Visione', + ['brand'] = 'Grotti', + ['model'] = 'visione', + ['price'] = 750000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `visione`, + ['shop'] = 'luxury', + }, + ['corsita'] = { + ['name'] = 'Corsita', + ['brand'] = 'Lampadati', + ['model'] = 'corsita', + ['price'] = 90000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `corsita`, + ['shop'] = 'luxury', + }, + ['omnisegt'] = { + ['name'] = 'Omnis e-GT', + ['brand'] = 'Obey', + ['model'] = 'omnisegt', + ['price'] = 185000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `omnisegt`, + ['shop'] = 'luxury', + }, + ['sentinel4'] = { + ['name'] = 'Sentinel Classic Widebody', + ['brand'] = 'Übermacht', + ['model'] = 'sentinel4', + ['price'] = 140000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sentinel4`, + ['shop'] = 'luxury', + }, + ['sm722'] = { + ['name'] = 'SM722', + ['brand'] = 'Benefactor', + ['model'] = 'sm722', + ['price'] = 125000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `sm722`, + ['shop'] = 'luxury', + }, + ['tenf'] = { + ['name'] = '10F', + ['brand'] = 'Obey', + ['model'] = 'tenf', + ['price'] = 185000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `tenf`, + ['shop'] = 'luxury', + }, + ['tenf2'] = { + ['name'] = '10F Widebody', + ['brand'] = 'Obey', + ['model'] = 'tenf2', + ['price'] = 215000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `tenf2`, + ['shop'] = 'luxury', + }, + ['everon2'] = { + ['name'] = 'Everon Hotring', + ['brand'] = 'Karin', + ['model'] = 'everon2', + ['price'] = 80000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `everon`, + ['shop'] = 'pdm', + }, + ['issi8'] = { + ['name'] = 'Issi Rally', + ['brand'] = 'Weeny', + ['model'] = 'issi8', + ['price'] = 10000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `issi8`, + ['shop'] = 'pdm', + }, + ['r300'] = { + ['name'] = '300R', + ['brand'] = 'Annis', + ['model'] = 'r300', + ['price'] = 56000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `r300`, + ['shop'] = 'pdm', + }, + ['panthere'] = { + ['name'] = 'Panthere', + ['brand'] = 'Toundra', + ['model'] = 'panthere', + ['price'] = 55000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `panthere`, + ['shop'] = 'pdm', + }, + ['drifteuros'] = { + ['name'] = 'Euros (Drift)', + ['brand'] = 'Annis', + ['model'] = 'drifteuros', + ['price'] = 27000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `drifteuros`, + ['shop'] = 'pdm', + }, + ['driftfuto'] = { + ['name'] = 'Futo GTX (Drift)', + ['brand'] = 'Karin', + ['model'] = 'driftfuto', + ['price'] = 25000, + ['category'] = 'Sports', + ['categoryLabel'] = 'Sports', + ['hash'] = `driftfuto`, + ['shop'] = 'pdm', + }, + + + --- Sports Classic + ['coquette2'] = { + ['name'] = 'Coquette Classic', + ['brand'] = 'Invetero', + ['model'] = 'coquette2', + ['price'] = 165000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `coquette2`, + ['shop'] = 'pdm', + }, + ['peyote2'] = { --DLC + ['name'] = 'Peyote Gasser', + ['brand'] = 'Vapid', + ['model'] = 'peyote2', + ['price'] = 40000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `peyote2`, + ['shop'] = 'pdm', + }, + ['ardent'] = { + ['name'] = 'Ardent', + ['brand'] = 'Ocelot', + ['model'] = 'ardent', + ['price'] = 30000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `ardent`, + ['shop'] = 'pdm', + }, + ['btype'] = { --meme car that goes pretty fast + ['name'] = 'Roosevelt', + ['brand'] = 'Albany', + ['model'] = 'btype', + ['price'] = 75000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `btype`, + ['shop'] = 'pdm', + }, + ['btype2'] = { + ['name'] = 'Franken Stange', + ['brand'] = 'Albany', + ['model'] = 'btype2', + ['price'] = 87000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `btype2`, + ['shop'] = 'pdm', + }, + ['btype3'] = { + ['name'] = 'Roosevelt Valor', + ['brand'] = 'Albany', + ['model'] = 'btype3', + ['price'] = 63000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `btype3`, + ['shop'] = 'pdm', + }, + ['casco'] = { + ['name'] = 'Casco', + ['brand'] = 'Lampadati', + ['model'] = 'casco', + ['price'] = 100000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `casco`, + ['shop'] = 'pdm', + }, + ['deluxo'] = { + ['name'] = 'Deluxo', + ['brand'] = 'Imponte', + ['model'] = 'deluxo', + ['price'] = 55000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `deluxo`, + ['shop'] = 'pdm', + }, + ['dynasty'] = { --DLC + ['name'] = 'Dynasty', + ['brand'] = 'Weeny', + ['model'] = 'dynasty', + ['price'] = 25000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `dynasty`, + ['shop'] = 'pdm', + }, + ['fagaloa'] = { + ['name'] = 'Fagaloa', + ['brand'] = 'Vulcar', + ['model'] = 'fagaloa', + ['price'] = 13000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `fagaloa`, + ['shop'] = 'pdm', + }, + ['feltzer3'] = { --DLC + ['name'] = 'Stirling GT', + ['brand'] = 'Benefactor', + ['model'] = 'feltzer3', + ['price'] = 115000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `feltzer3`, + ['shop'] = 'pdm', + }, + ['gt500'] = { + ['name'] = 'GT500', + ['brand'] = 'Grotti', + ['model'] = 'gt500', + ['price'] = 130000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `gt500`, + ['shop'] = 'pdm', + }, + ['infernus2'] = { + ['name'] = 'Infernus Classic', + ['brand'] = 'Pegassi', + ['model'] = 'infernus2', + ['price'] = 245000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `infernus2`, + ['shop'] = 'pdm', + }, + ['jb700'] = { + ['name'] = 'JB 700', + ['brand'] = 'Dewbauchee', + ['model'] = 'jb700', + ['price'] = 240000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `jb700`, + ['shop'] = 'pdm', + }, + ['jb7002'] = { + ['name'] = 'JB 700W', + ['brand'] = 'Dewbauchee', + ['model'] = 'jb7002', + ['price'] = 40000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `jb7002`, + ['shop'] = 'pdm', + }, + ['mamba'] = { + ['name'] = 'Mamba', + ['brand'] = 'Declasse', + ['model'] = 'mamba', + ['price'] = 140000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `mamba`, + ['shop'] = 'pdm', + }, + ['michelli'] = { + ['name'] = 'Michelli GT', + ['brand'] = 'Lampadati', + ['model'] = 'michelli', + ['price'] = 30000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `michelli`, + ['shop'] = 'pdm', + }, + ['monroe'] = { + ['name'] = 'Monroe', + ['brand'] = 'Pegassi', + ['model'] = 'monroe', + ['price'] = 115000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `monroe`, + ['shop'] = 'pdm', + }, + ['nebula'] = { --DLC + ['name'] = 'Nebula', + ['brand'] = 'Vulcar', + ['model'] = 'nebula', + ['price'] = 22000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `nebula`, + ['shop'] = 'pdm', + }, + ['peyote'] = { + ['name'] = 'Peyote', + ['brand'] = 'Vapid', + ['model'] = 'peyote', + ['price'] = 23500, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `peyote`, + ['shop'] = 'pdm', + }, + ['peyote3'] = { + ['name'] = 'Peyote Custom', + ['brand'] = 'Vapid', + ['model'] = 'peyote3', + ['price'] = 48000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `peyote3`, + ['shop'] = 'pdm', + }, + ['pigalle'] = { + ['name'] = 'Pigalle', + ['brand'] = 'Lampadati', + ['model'] = 'pigalle', + ['price'] = 92000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `pigalle`, + ['shop'] = 'pdm', + }, + ['rapidgt3'] = { + ['name'] = 'Rapid GT Classic', + ['brand'] = 'Dewbauchee', + ['model'] = 'rapidgt3', + ['price'] = 90000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `rapidgt3`, + ['shop'] = 'pdm', + }, + ['retinue'] = { + ['name'] = 'Retinue', + ['brand'] = 'Vapid', + ['model'] = 'retinue', + ['price'] = 32000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `retinue`, + ['shop'] = 'pdm', + }, + ['retinue2'] = { + ['name'] = 'Retinue MKII', + ['brand'] = 'Vapid', + ['model'] = 'retinue2', + ['price'] = 38000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `retinue2`, + ['shop'] = 'pdm', + }, + ['savestra'] = { + ['name'] = 'Savestra', + ['brand'] = 'Annis', + ['model'] = 'savestra', + ['price'] = 67000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `savestra`, + ['shop'] = 'pdm', + }, + ['stinger'] = { + ['name'] = 'Stinger', + ['brand'] = 'Grotti', + ['model'] = 'stinger', + ['price'] = 39500, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `stinger`, + ['shop'] = 'pdm', + }, + ['stingergt'] = { + ['name'] = 'Stinger GT', + ['brand'] = 'Grotti', + ['model'] = 'stingergt', + ['price'] = 70000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `stingergt`, + ['shop'] = 'pdm', + }, + ['stromberg'] = { + ['name'] = 'Stromberg', + ['brand'] = 'Ocelot', + ['model'] = 'stromberg', + ['price'] = 80000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `stromberg`, + ['shop'] = 'pdm', + }, + ['swinger'] = { --DLC + ['name'] = 'Swinger', + ['brand'] = 'Ocelot', + ['model'] = 'swinger', + ['price'] = 221000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `swinger`, + ['shop'] = 'pdm', + }, + ['torero'] = { + ['name'] = 'Torero', + ['brand'] = 'Pegassi', + ['model'] = 'torero', + ['price'] = 84000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `torero`, + ['shop'] = 'pdm', + }, + ['tornado'] = { + ['name'] = 'Tornado', + ['brand'] = 'Declasse', + ['model'] = 'tornado', + ['price'] = 21000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `tornado`, + ['shop'] = 'pdm', + }, + ['tornado2'] = { + ['name'] = 'Tornado Convertible', + ['brand'] = 'Declasse', + ['model'] = 'tornado2', + ['price'] = 22000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `tornado2`, + ['shop'] = 'pdm', + }, + ['tornado5'] = { + ['name'] = 'Tornado Custom', + ['brand'] = 'Declasse', + ['model'] = 'tornado5', + ['price'] = 22000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `tornado5`, + ['shop'] = 'pdm', + }, + ['turismo2'] = { + ['name'] = 'Turismo Classic', + ['brand'] = 'Grotti', + ['model'] = 'turismo2', + ['price'] = 170000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `turismo2`, + ['shop'] = 'pdm', + }, + ['viseris'] = { + ['name'] = 'Viseris', + ['brand'] = 'Lampadati', + ['model'] = 'viseris', + ['price'] = 210000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `viseris`, + ['shop'] = 'pdm', + }, + ['z190'] = { + ['name'] = '190Z', + ['brand'] = 'Karin', + ['model'] = 'z190', + ['price'] = 78000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `z190`, + ['shop'] = 'pdm', + }, + ['ztype'] = { + ['name'] = 'Z-Type', + ['brand'] = 'Truffade', + ['model'] = 'ztype', + ['price'] = 270000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `ztype`, + ['shop'] = 'pdm', + }, + ['zion3'] = { --DLC + ['name'] = 'Zion Classic', + ['brand'] = 'Übermacht', + ['model'] = 'zion3', + ['price'] = 45000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `zion3`, + ['shop'] = 'pdm', + }, + ['cheburek'] = { + ['name'] = 'Cheburek', + ['brand'] = 'Rune', + ['model'] = 'cheburek', + ['price'] = 7000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `cheburek`, + ['shop'] = 'pdm', + }, + ['toreador'] = { + ['name'] = 'Toreador', + ['brand'] = 'Pegassi', + ['model'] = 'toreador', + ['price'] = 50000, + ['category'] = 'Sports Classics', + ['categoryLabel'] = 'Sports Classics', + ['hash'] = `toreador`, + ['shop'] = 'pdm', + }, + + --- Super + ['adder'] = { + ['name'] = 'Adder', + ['brand'] = 'Truffade', + ['model'] = 'adder', + ['price'] = 280000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `adder`, + ['shop'] = 'luxury', + }, + ['autarch'] = { + ['name'] = 'Autarch', + ['brand'] = 'Överflöd', + ['model'] = 'autarch', + ['price'] = 224000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `autarch`, + ['shop'] = 'luxury', + }, + ['banshee2'] = { + ['name'] = 'Banshee 900R', + ['brand'] = 'Bravado', + ['model'] = 'banshee2', + ['price'] = 120000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `banshee2`, + ['shop'] = 'luxury', + }, + ['bullet'] = { + ['name'] = 'Bullet', + ['brand'] = 'Vapid', + ['model'] = 'bullet', + ['price'] = 120000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `bullet`, + ['shop'] = 'luxury', + }, + ['cheetah'] = { + ['name'] = 'Cheetah', + ['brand'] = 'Grotti', + ['model'] = 'cheetah', + ['price'] = 214000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `cheetah`, + ['shop'] = 'luxury', + }, + ['cyclone'] = { --might be too overpowered + ['name'] = 'Cyclone', + ['brand'] = 'Coil', + ['model'] = 'cyclone', + ['price'] = 300000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `cyclone`, + ['shop'] = 'luxury', + }, + ['entity2'] = { + ['name'] = 'Entity XXR', + ['brand'] = 'Överflöd', + ['model'] = 'entity2', + ['price'] = 164000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `entity2`, + ['shop'] = 'luxury', + }, + ['entityxf'] = { + ['name'] = 'Entity XF', + ['brand'] = 'Överflöd', + ['model'] = 'entityxf', + ['price'] = 180000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `entityxf`, + ['shop'] = 'luxury', + }, + ['emerus'] = { --DLC + ['name'] = 'Emerus', + ['brand'] = 'Progen', + ['model'] = 'emerus', + ['price'] = 220000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `emerus`, + ['shop'] = 'luxury', + }, + ['fmj'] = { + ['name'] = 'FMJ', + ['brand'] = 'Vapid', + ['model'] = 'fmj', + ['price'] = 125000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `fmj`, + ['shop'] = 'luxury', + }, + ['furia'] = { + ['name'] = 'Furia', + ['brand'] = 'Grotti', + ['model'] = 'furia', + ['price'] = 230000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `furia`, + ['shop'] = 'luxury', + }, + ['gp1'] = { + ['name'] = 'GP1', + ['brand'] = 'Progen', + ['model'] = 'gp1', + ['price'] = 110000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `gp1`, + ['shop'] = 'luxury', + }, + ['infernus'] = { + ['name'] = 'Infernus', + ['brand'] = 'Pegassi', + ['model'] = 'infernus', + ['price'] = 235000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `infernus`, + ['shop'] = 'luxury', + }, + ['italigtb'] = { + ['name'] = 'Itali GTB', + ['brand'] = 'Progen', + ['model'] = 'italigtb', + ['price'] = 170000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `italigtb`, + ['shop'] = 'luxury', + }, + ['italigtb2'] = { + ['name'] = 'Itali GTB Custom', + ['brand'] = 'Progen', + ['model'] = 'italigtb2', + ['price'] = 250000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `italigtb2`, + ['shop'] = 'luxury', + }, + ['krieger'] = { --DLC + ['name'] = 'Krieger', + ['brand'] = 'Benefactor', + ['model'] = 'krieger', + ['price'] = 222000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `krieger`, + ['shop'] = 'luxury', + }, + ['le7b'] = { + ['name'] = 'RE-7B', + ['brand'] = 'Annis', + ['model'] = 'le7b', + ['price'] = 260000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `le7b`, + ['shop'] = 'luxury', + }, + ['nero'] = { + ['name'] = 'Nero', + ['brand'] = 'Truffade', + ['model'] = 'nero', + ['price'] = 200000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `nero`, + ['shop'] = 'luxury', + }, + ['nero2'] = { + ['name'] = 'Nero Custom', + ['brand'] = 'Truffade', + ['model'] = 'nero2', + ['price'] = 260000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `nero2`, + ['shop'] = 'luxury', + }, + ['osiris'] = { + ['name'] = 'Osiris', + ['brand'] = 'Pegassi', + ['model'] = 'osiris', + ['price'] = 220000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `osiris`, + ['shop'] = 'luxury', + }, + ['penetrator'] = { + ['name'] = 'Penetrator', + ['brand'] = 'Ocelot', + ['model'] = 'penetrator', + ['price'] = 130000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `penetrator`, + ['shop'] = 'luxury', + }, + ['pfister811'] = { + ['name'] = '811', + ['brand'] = 'Pfister', + ['model'] = 'pfister811', + ['price'] = 220000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `pfister811`, + ['shop'] = 'luxury', + }, + ['prototipo'] = { + ['name'] = 'X80 Proto', + ['brand'] = 'Grotti', + ['model'] = 'prototipo', + ['price'] = 235000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `prototipo`, + ['shop'] = 'luxury', + }, + ['reaper'] = { + ['name'] = 'Reaper', + ['brand'] = 'Pegassi', + ['model'] = 'reaper', + ['price'] = 100000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `reaper`, + ['shop'] = 'luxury', + }, + ['s80'] = { --DLC + ['name'] = 'S80RR', + ['brand'] = 'Annis', + ['model'] = 's80', + ['price'] = 205000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `s80`, + ['shop'] = 'luxury', + }, + ['sc1'] = { + ['name'] = 'SC1', + ['brand'] = 'Übermacht', + ['model'] = 'sc1', + ['price'] = 90000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `sc1`, + ['shop'] = 'luxury', + }, + ['sheava'] = { --DLC + ['name'] = 'ETR1', + ['brand'] = 'Emperor', + ['model'] = 'sheava', + ['price'] = 220000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `sheava`, + ['shop'] = 'luxury', + }, + ['t20'] = { + ['name'] = 'T20', + ['brand'] = 'Progen', + ['model'] = 't20', + ['price'] = 1650000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `t20`, + ['shop'] = 'luxury', + }, + ['taipan'] = { + ['name'] = 'Taipan', + ['brand'] = 'Cheval', + ['model'] = 'taipan', + ['price'] = 1850000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `taipan`, + ['shop'] = 'luxury', + }, + ['tempesta'] = { + ['name'] = 'Tempesta', + ['brand'] = 'Pegassi', + ['model'] = 'tempesta', + ['price'] = 120000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `tempesta`, + ['shop'] = 'luxury', + }, + ['tezeract'] = { + ['name'] = 'Tezeract', + ['brand'] = 'Pegassi', + ['model'] = 'tezeract', + ['price'] = 220000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `tezeract`, + ['shop'] = 'luxury', + }, + ['thrax'] = { --DLC + ['name'] = 'Thrax', + ['brand'] = 'Truffade', + ['model'] = 'thrax', + ['price'] = 180000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `thrax`, + ['shop'] = 'luxury', + }, + ['tigon'] = { + ['name'] = 'Tigon', + ['brand'] = 'Lampadati', + ['model'] = 'tigon', + ['price'] = 240000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `tigon`, + ['shop'] = 'luxury', + }, + ['turismor'] = { + ['name'] = 'Turismo R', + ['brand'] = 'Grotti', + ['model'] = 'turismor', + ['price'] = 140000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `turismor`, + ['shop'] = 'luxury', + }, + ['tyrant'] = { + ['name'] = 'Tyrant', + ['brand'] = 'Överflöd', + ['model'] = 'tyrant', + ['price'] = 2100000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `tyrant`, + ['shop'] = 'luxury', + }, + ['tyrus'] = { + ['name'] = 'Tyrus', + ['brand'] = 'Progen', + ['model'] = 'tyrus', + ['price'] = 230000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `tyrus`, + ['shop'] = 'luxury', + }, + ['vacca'] = { + ['name'] = 'Vacca', + ['brand'] = 'Pegassi', + ['model'] = 'vacca', + ['price'] = 105000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `vacca`, + ['shop'] = 'luxury', + }, + ['vagner'] = { + ['name'] = 'Vagner', + ['brand'] = 'Dewbauchee', + ['model'] = 'vagner', + ['price'] = 1660000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `vagner`, + ['shop'] = 'luxury', + }, + ['voltic'] = { + ['name'] = 'Voltic', + ['brand'] = 'Coil', + ['model'] = 'voltic', + ['price'] = 120000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `voltic`, + ['shop'] = 'luxury', + }, + ['voltic2'] = { + ['name'] = 'Rocket Voltic', + ['brand'] = 'Coil', + ['model'] = 'voltic2', + ['price'] = 9830400, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `voltic2`, + ['shop'] = 'luxury', + }, + ['xa21'] = { + ['name'] = 'XA-21', + ['brand'] = 'Ocelot', + ['model'] = 'xa21', + ['price'] = 180000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `xa21`, + ['shop'] = 'luxury', + }, + ['zentorno'] = { + ['name'] = 'Zentorno', + ['brand'] = 'Pegassi', + ['model'] = 'zentorno', + ['price'] = 340000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `zentorno`, + ['shop'] = 'luxury', + }, + ['zorrusso'] = { --DLC + ['name'] = 'Zorrusso', + ['brand'] = 'Pegassi', + ['model'] = 'zorrusso', + ['price'] = 277000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `zorrusso`, + ['shop'] = 'luxury', + }, + ['deveste'] = { --DLC + ['name'] = 'Deveste', + ['brand'] = 'Principe', + ['model'] = 'deveste', + ['price'] = 234000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `deveste`, + ['shop'] = 'luxury', + }, + ['oppressor'] = { + ['name'] = 'Oppressor', + ['brand'] = 'Pegassi', + ['model'] = 'oppressor', + ['price'] = 9999999, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `oppressor`, + ['shop'] = 'luxury', + }, + ['ignus'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Ignus', + ['brand'] = 'Pegassi', + ['model'] = 'ignus', + ['price'] = 1120000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `ignus`, + ['shop'] = 'luxury', + }, + ['zeno'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Zeno', + ['brand'] = 'Överflöd', + ['model'] = 'zeno', + ['price'] = 1350000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `zeno`, + ['shop'] = 'luxury', + }, + ['virtue'] = { + ['name'] = 'Virtue', + ['brand'] = 'Ocelot', + ['model'] = 'virtue', + ['price'] = 72000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `virtue`, + ['shop'] = 'luxury', + }, + ['entity3'] = { --DLC +set sv_enforceGameBuild 2802 + ['name'] = 'Entity MT', + ['brand'] = 'Overflod', + ['model'] = 'entity3', + ['price'] = 200000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `entity3`, + ['shop'] = 'luxury', + }, + ['torero2'] = { + ['name'] = 'Torero XO', + ['brand'] = 'Pegassi', + ['model'] = 'torero2', + ['price'] = 245000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `torero2`, + ['shop'] = 'luxury', + }, + ['lm87'] = { + ['name'] = 'LM87', + ['brand'] = 'Benefactor', + ['model'] = 'lm87', + ['price'] = 155000, + ['category'] = 'Super', + ['categoryLabel'] = 'Super', + ['hash'] = `lm87`, + ['shop'] = 'luxury', + }, + + -- Vans + ['moonbeam'] = { + ['name'] = 'Moonbeam', + ['brand'] = 'Declasse', + ['model'] = 'moonbeam', + ['price'] = 13000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `moonbeam`, + ['shop'] = 'pdm', + }, + ['moonbeam2'] = { + ['name'] = 'Moonbeam Custom', + ['brand'] = 'Declasse', + ['model'] = 'moonbeam2', + ['price'] = 15000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `moonbeam2`, + ['shop'] = 'pdm', + }, + ['bison'] = { + ['name'] = 'Bison', + ['brand'] = 'Bravado', + ['model'] = 'bison', + ['price'] = 18000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `bison`, + ['shop'] = 'pdm', + }, + ['bobcatxl'] = { + ['name'] = 'Bobcat XL Open', + ['brand'] = 'Vapid', + ['model'] = 'bobcatxl', + ['price'] = 13500, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `bobcatxl`, + ['shop'] = 'pdm', + }, + ['burrito3'] = { + ['name'] = 'Burrito', + ['brand'] = 'Declasse', + ['model'] = 'burrito3', + ['price'] = 4000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `burrito3`, + ['shop'] = 'pdm', + }, + ['gburrito2'] = { + ['name'] = 'Burrito Custom', + ['brand'] = 'Declasse', + ['model'] = 'gburrito2', + ['price'] = 11500, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `gburrito2`, + ['shop'] = 'pdm', + }, + ['rumpo'] = { + ['name'] = 'Rumpo', + ['brand'] = 'Bravado', + ['model'] = 'rumpo', + ['price'] = 9000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `rumpo`, + ['shop'] = 'pdm', + }, + ['journey'] = { + ['name'] = 'Journey', + ['brand'] = 'Zirconium', + ['model'] = 'journey', + ['price'] = 6500, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `journey`, + ['shop'] = 'pdm', + }, + ['minivan'] = { + ['name'] = 'Minivan', + ['brand'] = 'Vapid', + ['model'] = 'minivan', + ['price'] = 7000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `minivan`, + ['shop'] = 'pdm', + }, + ['minivan2'] = { + ['name'] = 'Minivan Custom', + ['brand'] = 'Vapid', + ['model'] = 'minivan2', + ['price'] = 10000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `minivan2`, + ['shop'] = 'pdm', + }, + ['paradise'] = { + ['name'] = 'Paradise', + ['brand'] = 'Bravado', + ['model'] = 'paradise', + ['price'] = 9000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `paradise`, + ['shop'] = 'pdm', + }, + ['rumpo3'] = { + ['name'] = 'Rumpo Custom', + ['brand'] = 'Bravado', + ['model'] = 'rumpo3', + ['price'] = 19500, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `rumpo3`, + ['shop'] = 'pdm', + }, + ['speedo'] = { + ['name'] = 'Speedo', + ['brand'] = 'Vapid', + ['model'] = 'speedo', + ['price'] = 10000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `speedo`, + ['shop'] = 'pdm', + }, + ['speedo4'] = { + ['name'] = 'Speedo Custom', + ['brand'] = 'Vapid', + ['model'] = 'speedo4', + ['price'] = 15000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `speedo4`, + ['shop'] = 'pdm', + }, + ['surfer'] = { + ['name'] = 'Surfer', + ['brand'] = 'BF', + ['model'] = 'surfer', + ['price'] = 9000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `surfer`, + ['shop'] = 'pdm', + }, + ['youga3'] = { + ['name'] = 'Youga Classic 4x4', + ['brand'] = 'Bravado', + ['model'] = 'youga3', + ['price'] = 15000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `youga3`, + ['shop'] = 'pdm', + }, + ['youga'] = { + ['name'] = 'Youga', + ['brand'] = 'Bravado', + ['model'] = 'youga', + ['price'] = 8000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `youga`, + ['shop'] = 'pdm', + }, + ['youga2'] = { + ['name'] = 'Youga Classic', + ['brand'] = 'Bravado', + ['model'] = 'youga2', + ['price'] = 14500, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `youga2`, + ['shop'] = 'pdm', + }, + ['youga4'] = { --DLC +set sv_enforceGameBuild 2545 + ['name'] = 'Youga Custom', + ['brand'] = 'Bravado', + ['model'] = 'youga4', + ['price'] = 85000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `youga4`, + ['shop'] = 'pdm', + }, + ['boxville'] = { + ['name'] = 'Boxville LSDWP', + ['brand'] = 'Brute', + ['model'] = 'boxville', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `boxville`, + ['shop'] = 'truck', + }, + ['boxville2'] = { + ['name'] = 'Boxville Go Postal', + ['brand'] = 'Brute', + ['model'] = 'boxville2', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `boxville2`, + ['shop'] = 'truck', + }, + ['boxville3'] = { + ['name'] = 'Boxville Humane Labs', + ['brand'] = 'Brute', + ['model'] = 'boxville3', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `boxville3`, + ['shop'] = 'truck', + }, + ['boxville4'] = { + ['name'] = 'Boxville Post OP', + ['brand'] = 'Brute', + ['model'] = 'boxville4', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `boxville4`, + ['shop'] = 'truck', + }, + ['boxville5'] = { + ['name'] = 'Armored Boxville', + ['brand'] = 'Brute', + ['model'] = 'boxville5', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `boxville5`, + ['shop'] = 'truck', + }, + ['pony'] = { + ['name'] = 'Pony', + ['brand'] = 'Brute', + ['model'] = 'pony', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `pony`, + ['shop'] = 'truck', + }, + ['pony2'] = { + ['name'] = 'Pony (Smoke on the water)', + ['brand'] = 'Brute', + ['model'] = 'pony2', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Vans', + ['hash'] = `pony2`, + ['shop'] = 'truck', + }, + ['taco'] = { + ['name'] = 'Taco Truck', + ['brand'] = 'Brute', + ['model'] = 'taco', + ['price'] = 45000, + ['category'] = 'Vans', + ["categoryLabel"] = 'Food Truck', + ['hash'] = `taco`, + ['shop'] = 'truck', + }, + ['journey2'] = { + ['name'] = 'Journey II', + ['brand'] = 'Zirconium', + ['model'] = 'journey2', + ['price'] = 7000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `journey2`, + ['shop'] = 'pdm', + }, + ['surfer3'] = { + ['name'] = 'Surfer Custom', + ['brand'] = 'BF', + ['model'] = 'surfer3', + ['price'] = 15000, + ['category'] = 'Vans', + ['categoryLabel'] = 'Vans', + ['hash'] = `surfer3`, + ['shop'] = 'pdm', + }, + + -- Utility + + -- ['tractor2'] = { + -- ['name'] = 'Fieldmaster', + -- ['brand'] = 'Stanley', + -- ['model'] = 'tractor2', + -- ['price'] = 40000, + -- ['category'] = 'utility', + -- ['categoryLabel'] = 'Utility', + -- ['hash'] = `tractor2`, + -- ['shop'] = 'utility', + -- }, + ['sadler'] = { + ['name'] = 'Sadler', + ['brand'] = 'Vapid', + ['model'] = 'sadler', + ['price'] = 40000, + ['category'] = 'Utility', + ['categoryLabel'] = 'Utility', + ['hash'] = `sadler`, + ['shop'] = 'pdm', + }, + ['utillitruck3'] = { + ['name'] = 'Utility Truck', + ['brand'] = 'Vapid', + ['model'] = 'utillitruck3', + ['price'] = 40000, + ['category'] = 'Utility', + ['categoryLabel'] = 'Utility', + ['hash'] = `utillitruck3`, + ['shop'] = 'pdm', + }, + -- Boats + ['squalo'] = { + ['name'] = 'Squalo', + ['brand'] = 'Shitzu', + ['model'] = 'squalo', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `squalo`, + ['shop'] = 'boats', + }, + ['marquis'] = { + ['name'] = 'Marquis', + ['brand'] = 'Dinka', + ['model'] = 'marquis', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `marquis`, + ['shop'] = 'boats', + }, + ['seashark'] = { + ['name'] = 'Seashark', + ['brand'] = 'Speedophile', + ['model'] = 'seashark', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `seashark`, + ['shop'] = 'boats', + }, + ['seashark2'] = { + ['name'] = 'Seashark Lifeguard', + ['brand'] = 'Speedophile', + ['model'] = 'seashark2', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `seashark2`, + ['shop'] = 'boats', + }, + ['seashark3'] = { + ['name'] = 'Seashark Yacht', + ['brand'] = 'Speedophile', + ['model'] = 'seashark3', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `seashark3`, + ['shop'] = 'boats', + }, + ['jetmax'] = { + ['name'] = 'Jetmax', + ['brand'] = 'Shitzu', + ['model'] = 'jetmax', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `jetmax`, + ['shop'] = 'boats', + }, + ['tropic'] = { + ['name'] = 'Tropic', + ['brand'] = 'Shitzu', + ['model'] = 'tropic', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `tropic`, + ['shop'] = 'boats', + }, + ['tropic2'] = { + ['name'] = 'Tropic Yacht', + ['brand'] = 'Shitzu', + ['model'] = 'tropic2', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `tropic2`, + ['shop'] = 'boats', + }, + ['dinghy'] = { + ['name'] = 'Dinghy 2-Seater', + ['brand'] = 'Nagasaki', + ['model'] = 'dinghy', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `dinghy`, + ['shop'] = 'boats', + }, + ['dinghy2'] = { + ['name'] = 'Dinghy 4-Seater', + ['brand'] = 'Nagasaki', + ['model'] = 'dinghy2', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `dinghy2`, + ['shop'] = 'boats', + }, + ['dinghy3'] = { + ['name'] = 'Dinghy (Heist)', + ['brand'] = 'Nagasaki', + ['model'] = 'dinghy3', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `dinghy3`, + ['shop'] = 'boats', + }, + ['dinghy4'] = { + ['name'] = 'Dinghy Yacht', + ['brand'] = 'Nagasaki', + ['model'] = 'dinghy4', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `dinghy4`, + ['shop'] = 'boats', + }, + ['suntrap'] = { + ['name'] = 'Suntrap', + ['brand'] = 'Shitzu', + ['model'] = 'suntrap', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `suntrap`, + ['shop'] = 'boats', + }, + ['speeder'] = { + ['name'] = 'Speeder', + ['brand'] = 'Pegassi', + ['model'] = 'speeder', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `speeder`, + ['shop'] = 'boats', + }, + ['speeder2'] = { + ['name'] = 'Speeder Yacht', + ['brand'] = 'Pegassi', + ['model'] = 'speeder2', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `speeder2`, + ['shop'] = 'boats', + }, + ['longfin'] = { + ['name'] = 'Longfin', + ['brand'] = 'Shitzu', + ['model'] = 'longfin', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `longfin`, + ['shop'] = 'boats', + }, + ['toro'] = { + ['name'] = 'Toro', + ['brand'] = 'Lampadati', + ['model'] = 'toro', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `toro`, + ['shop'] = 'boats', + }, + ['toro2'] = { + ['name'] = 'Toro Yacht', + ['brand'] = 'Lampadati', + ['model'] = 'toro2', + ['price'] = 40000, + ['category'] = 'Boats', + ['categoryLabel'] = 'Boats', + ['hash'] = `toro2`, + ['shop'] = 'boats', + }, + + -- helicopters + ['buzzard2'] = { + ['name'] = 'Buzzard', + ['brand'] = 'Unknown', + ['model'] = 'buzzard2', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `buzzard2`, + ['shop'] = 'air', + }, + ['frogger'] = { + ['name'] = 'Frogger', + ['brand'] = 'Unknown', + ['model'] = 'frogger', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `frogger`, + ['shop'] = 'air', + }, + ['frogger2'] = { + ['name'] = 'Frogger (Trevor Philips Enterprises)', + ['brand'] = 'Unknown', + ['model'] = 'frogger2', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `frogger2`, + ['shop'] = 'air', + }, + ['maverick'] = { + ['name'] = 'Maverick', + ['brand'] = 'Unknown', + ['model'] = 'maverick', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `maverick`, + ['shop'] = 'air', + }, + ['swift'] = { + ['name'] = 'Swift', + ['brand'] = 'Buckingham', + ['model'] = 'swift', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `swift`, + ['shop'] = 'air', + }, + ['swift2'] = { + ['name'] = 'Swift Deluxe', + ['brand'] = 'Buckingham', + ['model'] = 'swift2', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `swift2`, + ['shop'] = 'air', + }, + ['seasparrow'] = { + ['name'] = 'Sea Sparrow', + ['brand'] = 'Unknown', + ['model'] = 'seasparrow', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `seasparrow`, + ['shop'] = 'air', + }, + ['seasparrow2'] = { + ['name'] = 'Sparrow', + ['brand'] = 'Unknown', + ['model'] = 'seasparrow2', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `seasparrow2`, + ['shop'] = 'air', + }, + ['seasparrow3'] = { + ['name'] = 'Sparrow (Prop)', + ['brand'] = 'Unknown', + ['model'] = 'seasparrow3', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `seasparrow3`, + ['shop'] = 'air', + }, + ['supervolito'] = { + ['name'] = 'SuperVolito', + ['brand'] = 'Buckingham', + ['model'] = 'supervolito', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `supervolito`, + ['shop'] = 'air', + }, + ['supervolito2'] = { + ['name'] = 'SuperVolito Carbon', + ['brand'] = 'Buckingham', + ['model'] = 'supervolito2', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `supervolito2`, + ['shop'] = 'air', + }, + ['volatus'] = { + ['name'] = 'Volatus', + ['brand'] = 'Buckingham', + ['model'] = 'volatus', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `volatus`, + ['shop'] = 'air', + }, + ['havok'] = { + ['name'] = 'Havok', + ['brand'] = 'Nagasaki', + ['model'] = 'havok', + ['price'] = 52000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `havok`, + ['shop'] = 'air', + }, + ['conada'] = { + ['name'] = 'Conada', + ['brand'] = 'Buckingham', + ['model'] = 'conada', + ['price'] = 115000, + ['category'] = 'Helicopters', + ['categoryLabel'] = 'Helicopters', + ['hash'] = `conada`, + ['shop'] = 'air', + }, + + -- Planes + ['duster'] = { + ['name'] = 'Duster', + ['brand'] = 'Unknown', + ['model'] = 'duster', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `duster`, + ['shop'] = 'air', + }, + ['luxor'] = { + ['name'] = 'Luxor', + ['brand'] = 'Buckingham', + ['model'] = 'luxor', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `luxor`, + ['shop'] = 'air', + }, + ['luxor2'] = { + ['name'] = 'Luxor Deluxe', + ['brand'] = 'Buckingham', + ['model'] = 'luxor2', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `luxor2`, + ['shop'] = 'air', + }, + ['stunt'] = { + ['name'] = 'Mallard', + ['brand'] = 'Unknown', + ['model'] = 'stunt', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `stunt`, + ['shop'] = 'air', + }, + ['mammatus'] = { + ['name'] = 'Mammatus', + ['brand'] = 'Unknown', + ['model'] = 'mammatus', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `mammatus`, + ['shop'] = 'air', + }, + ['velum'] = { + ['name'] = 'Velum', + ['brand'] = 'Unknown', + ['model'] = 'velum', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `velum`, + ['shop'] = 'air', + }, + ['velum2'] = { + ['name'] = 'Velum 5-Seater', + ['brand'] = 'Unknown', + ['model'] = 'velum2', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `velum2`, + ['shop'] = 'air', + }, + ['shamal'] = { + ['name'] = 'Shamal', + ['brand'] = 'Buckingham', + ['model'] = 'shamal', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `shamal`, + ['shop'] = 'air', + }, + ['vestra'] = { + ['name'] = 'Vestra', + ['brand'] = 'Buckingham', + ['model'] = 'vestra', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `vestra`, + ['shop'] = 'air', + }, + ['dodo'] = { + ['name'] = 'Dodo', + ['brand'] = 'Mammoth', + ['model'] = 'dodo', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `dodo`, + ['shop'] = 'air', + }, + ['howard'] = { + ['name'] = 'Howard NX-25', + ['brand'] = 'Buckingham', + ['model'] = 'howard', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `howard`, + ['shop'] = 'air', + }, + ['alphaz1'] = { + ['name'] = 'Alpha-Z1', + ['brand'] = 'Buckingham', + ['model'] = 'alphaz1', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `alphaz1`, + ['shop'] = 'air', + }, + ['nimbus'] = { + ['name'] = 'Nimbus', + ['brand'] = 'Buckingham', + ['model'] = 'nimbus', + ['price'] = 45000, + ['category'] = 'Planes', + ['categoryLabel'] = 'Planes', + ['hash'] = `nimbus`, + ['shop'] = 'air', + }, + + -- Commercial + ['hauler'] = { + ['name'] = 'Hauler', + ['brand'] = 'Jobuilt', + ['model'] = 'hauler', + ['price'] = 100000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `hauler`, + ['shop'] = 'truck', + }, + ['packer'] = { + ['name'] = 'Packer', + ['brand'] = 'MTL', + ['model'] = 'packer', + ['price'] = 100000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `packer`, + ['shop'] = 'truck', + }, + ['stockade'] = { + ['name'] = 'Stockade', + ['brand'] = 'Brute', + ['model'] = 'stockade', + ['price'] = 100000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `stockade`, + ['shop'] = 'truck', + }, + ['biff'] = { + ['name'] = 'Biff', + ['brand'] = 'Brute', + ['model'] = 'biff', + ['price'] = 100000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `biff`, + ['shop'] = 'truck', + }, + ['phantom'] = { + ['name'] = 'Phantom', + ['brand'] = 'Jobuilt', + ['model'] = 'phantom', + ['price'] = 100000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `phantom`, + ['shop'] = 'truck', + }, + ['phantom3'] = { + ['name'] = 'Phantom Custom', + ['brand'] = 'Jobuilt', + ['model'] = 'phantom3', + ['price'] = 110000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `phantom3`, + ['shop'] = 'truck', + }, + ['benson'] = { + ['name'] = 'Benson', + ['brand'] = 'Vapid', + ['model'] = 'benson', + ['price'] = 55000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `benson`, + ['shop'] = 'truck', + }, + ['mule'] = { + ['name'] = 'Mule', + ['brand'] = 'Maibatsu', + ['model'] = 'mule', + ['price'] = 40000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `mule`, + ['shop'] = 'truck', + }, + ['mule2'] = { + ['name'] = 'Mule with Drop Door', + ['brand'] = 'Maibatsu', + ['model'] = 'mule2', + ['price'] = 40000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `mule2`, + ['shop'] = 'truck', + }, + ['mule3'] = { + ['name'] = 'Mule with Swinging Doors', + ['brand'] = 'Maibatsu', + ['model'] = 'mule3', + ['price'] = 40000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `mule3`, + ['shop'] = 'truck', + }, + ['mule4'] = { + ['name'] = 'Mule with Swinging Doors & Side Step', + ['brand'] = 'Maibatsu', + ['model'] = 'mule4', + ['price'] = 40000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `mule4`, + ['shop'] = 'truck', + }, + ['mule5'] = { + ['name'] = 'Mule with Swinging Doors & Step Bumper', + ['brand'] = 'Maibatsu', + ['model'] = 'mule5', + ['price'] = 40000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `mule5`, + ['shop'] = 'truck', + }, + ['pounder'] = { + ['name'] = 'Pounder', + ['brand'] = 'MTL', + ['model'] = 'pounder', + ['price'] = 55000, + ['category'] = 'Commercial', + ["categoryLabel"] = 'Commercial', + ['hash'] = `pounder`, + ['shop'] = 'truck', + }, + + --Industrial + ['bulldozer'] = { + ['name'] = 'Bulldozer', + ['brand'] = 'HVY', + ['model'] = 'bulldozer', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `bulldozer`, + ['shop'] = 'truck', + }, + ['flatbed'] = { + ['name'] = 'Flatbed Truck', + ['brand'] = 'MTL', + ['model'] = 'flatbed', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `flatbed`, + ['shop'] = 'truck', + }, + ['guardian'] = { + ['name'] = 'Guardian', + ['brand'] = 'Vapid', + ['model'] = 'guardian', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `guardian`, + ['shop'] = 'truck', + }, + ['mixer'] = { + ['name'] = 'Cement Mixer', + ['brand'] = 'HVY', + ['model'] = 'mixer', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `mixer`, + ['shop'] = 'truck', + }, + ['mixer2'] = { + ['name'] = 'Cement Mixer 2', + ['brand'] = 'HVY', + ['model'] = 'mixer2', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `mixer2`, + ['shop'] = 'truck', + }, + ['tiptruck'] = { + ['name'] = 'Dump Truck (Street Legal)', + ['brand'] = 'Brute', + ['model'] = 'tiptruck', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `tiptruck`, + ['shop'] = 'truck', + }, + ['tiptruck2'] = { + ['name'] = 'Dump Truck (Street Legal)', + ['brand'] = 'MTL', + ['model'] = 'tiptruck2', + ['price'] = 30000, + ['category'] = 'Industrial', + ["categoryLabel"] = 'Industrial', + ['hash'] = `tiptruck2`, + ['shop'] = 'truck', + }, +} + +for _, v in pairs(QBShared.Vehicles) do + QBShared.VehicleHashes[v.hash] = v +end diff --git a/resources/[qb]/qb-core/shared/weapons.lua b/resources/[qb]/qb-core/shared/weapons.lua new file mode 100644 index 0000000..d8a67ea --- /dev/null +++ b/resources/[qb]/qb-core/shared/weapons.lua @@ -0,0 +1,157 @@ +QBShared = QBShared or {} +QBShared.Weapons = { + -- // WEAPONS + -- Melee + [`weapon_unarmed`] = {['name'] = 'weapon_unarmed', ['label'] = 'Fists', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_dagger`] = {['name'] = 'weapon_dagger', ['label'] = 'Dagger', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_bat`] = {['name'] = 'weapon_bat', ['label'] = 'Bat', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_bottle`] = {['name'] = 'weapon_bottle', ['label'] = 'Broken Bottle', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_crowbar`] = {['name'] = 'weapon_crowbar', ['label'] = 'Crowbar', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_flashlight`] = {['name'] = 'weapon_flashlight', ['label'] = 'Flashlight', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_golfclub`] = {['name'] = 'weapon_golfclub', ['label'] = 'Golfclub', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_hammer`] = {['name'] = 'weapon_hammer', ['label'] = 'Hammer', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_hatchet`] = {['name'] = 'weapon_hatchet', ['label'] = 'Hatchet', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_knuckle`] = {['name'] = 'weapon_knuckle', ['label'] = 'Knuckle', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_knife`] = {['name'] = 'weapon_knife', ['label'] = 'Knife', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_machete`] = {['name'] = 'weapon_machete', ['label'] = 'Machete', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_switchblade`] = {['name'] = 'weapon_switchblade', ['label'] = 'Switchblade', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_nightstick`] = {['name'] = 'weapon_nightstick', ['label'] = 'Nightstick', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_wrench`] = {['name'] = 'weapon_wrench', ['label'] = 'Wrench', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_battleaxe`] = {['name'] = 'weapon_battleaxe', ['label'] = 'Battle Axe', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + [`weapon_poolcue`] = {['name'] = 'weapon_poolcue', ['label'] = 'Poolcue', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_briefcase`] = {['name'] = 'weapon_briefcase', ['label'] = 'Briefcase', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_briefcase_02`] = {['name'] = 'weapon_briefcase_02', ['label'] = 'Briefcase', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_garbagebag`] = {['name'] = 'weapon_garbagebag', ['label'] = 'Garbage Bag', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_handcuffs`] = {['name'] = 'weapon_handcuffs', ['label'] = 'Handcuffs', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_bread`] = {['name'] = 'weapon_bread', ['label'] = 'Baquette', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered'}, + [`weapon_stone_hatchet`] = {['name'] = 'weapon_stone_hatchet', ['label'] = 'Stone Hatchet', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Knifed / Stabbed / Eviscerated'}, + + -- Melee + [`weapon_candycane`] = {['name'] = 'weapon_candycane', ['label'] = 'Candy Cane', ['weapontype'] = 'Melee', ['ammotype'] = nil, ['damagereason'] = 'Canned with Candy'}, + -- Pistol + [`weapon_pistolxm3`] = {['name'] = 'weapon_pistolxm3', ['label'] = 'Pistol XM3', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plaugged / Bust a cap in'}, + -- Heavy Weapons + [`weapon_railgunxm3`] = {['name'] = 'weapon_railgunxm3', ['label'] = 'Railgun XM3', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = nil, ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + + -- Handguns + [`weapon_pistol`] = {['name'] = 'weapon_pistol', ['label'] = 'Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_pistol_mk2`] = {['name'] = 'weapon_pistol_mk2', ['label'] = 'Pistol Mk2', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_combatpistol`] = {['name'] = 'weapon_combatpistol', ['label'] = 'Combat Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_appistol`] = {['name'] = 'weapon_appistol', ['label'] = 'AP Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_stungun`] = {['name'] = 'weapon_stungun', ['label'] = 'Taser', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_STUNGUN', ['damagereason'] = 'Died'}, + [`weapon_pistol50`] = {['name'] = 'weapon_pistol50', ['label'] = 'Pistol .50 Cal', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_snspistol`] = {['name'] = 'weapon_snspistol', ['label'] = 'SNS Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_snspistol_mk2`] = {['name'] = 'weapon_snspistol_mk2', ['label'] = 'SNS Pistol MK2', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_heavypistol`] = {['name'] = 'weapon_heavypistol', ['label'] = 'Heavy Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_vintagepistol`] = {['name'] = 'weapon_vintagepistol', ['label'] = 'Vintage Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_flaregun`] = {['name'] = 'weapon_flaregun', ['label'] = 'Flare Gun', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_FLARE', ['damagereason'] = 'Died'}, + [`weapon_marksmanpistol`] = {['name'] = 'weapon_marksmanpistol', ['label'] = 'Marksman Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_revolver`] = {['name'] = 'weapon_revolver', ['label'] = 'Revolver', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_revolver_mk2`] = {['name'] = 'weapon_revolver_mk2', ['label'] = 'Revolver MK2', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_doubleaction`] = {['name'] = 'weapon_doubleaction', ['label'] = 'Double Action Revolver', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_raypistol`] = {['name'] = 'weapon_raypistol', ['label'] = 'Ray Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_ceramicpistol`] = {['name'] = 'weapon_ceramicpistol', ['label'] = 'Ceramic Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_navyrevolver`] = {['name'] = 'weapon_navyrevolver', ['label'] = 'Navy Revolver', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_gadgetpistol`] = {['name'] = 'weapon_gadgetpistol', ['label'] = 'Gadget Pistol', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Pistoled / Blasted / Plugged / Bust a cap in'}, + [`weapon_stungun_mp`] = {['name'] = 'weapon_stungun_mp', ['label'] = 'Taser', ['weapontype'] = 'Pistol', ['ammotype'] = 'AMMO_STUNGUN', ['damagereason'] = 'Died'}, + + -- Submachine Guns + [`weapon_microsmg`] = {['name'] = 'weapon_microsmg', ['label'] = 'Micro SMG', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_smg`] = {['name'] = 'weapon_smg', ['label'] = 'SMG', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_smg_mk2`] = {['name'] = 'weapon_smg_mk2', ['label'] = 'SMG MK2', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_assaultsmg`] = {['name'] = 'weapon_assaultsmg', ['label'] = 'Assault SMG', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_combatpdw`] = {['name'] = 'weapon_combatpdw', ['label'] = 'Combat PDW', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_machinepistol`] = {['name'] = 'weapon_machinepistol', ['label'] = 'Tec-9', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_PISTOL', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_minismg`] = {['name'] = 'weapon_minismg', ['label'] = 'Mini SMG', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + [`weapon_raycarbine`] = {['name'] = 'weapon_raycarbine', ['label'] = 'Raycarbine', ['weapontype'] = 'Submachine Gun', ['ammotype'] = 'AMMO_SMG', ['damagereason'] = 'Riddled / Drilled / Finished / Submachine Gunned'}, + + -- Shotguns + [`weapon_pumpshotgun`] = {['name'] = 'weapon_pumpshotgun', ['label'] = 'Pump Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_pumpshotgun_mk2`] = {['name'] = 'weapon_pumpshotgun_mk2', ['label'] = 'Pump Shotgun MK2', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_sawnoffshotgun`] = {['name'] = 'weapon_sawnoffshotgun', ['label'] = 'Sawn-off Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_assaultshotgun`] = {['name'] = 'weapon_assaultshotgun', ['label'] = 'Assault Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_bullpupshotgun`] = {['name'] = 'weapon_bullpupshotgun', ['label'] = 'Bullpup Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_musket`] = {['name'] = 'weapon_musket', ['label'] = 'Musket', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_heavyshotgun`] = {['name'] = 'weapon_heavyshotgun', ['label'] = 'Heavy Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_dbshotgun`] = {['name'] = 'weapon_dbshotgun', ['label'] = 'Double-barrel Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_autoshotgun`] = {['name'] = 'weapon_autoshotgun', ['label'] = 'Auto Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + [`weapon_combatshotgun`] = {['name'] = 'weapon_combatshotgun', ['label'] = 'Combat Shotgun', ['weapontype'] = 'Shotgun', ['ammotype'] = 'AMMO_SHOTGUN', ['damagereason'] = 'Devastated / Pulverized / Shotgunned'}, + + -- Assault Rifles + [`weapon_assaultrifle`] = {['name'] = 'weapon_assaultrifle', ['label'] = 'Assault Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_tacticalrifle`] = {['name'] = 'weapon_tacticalrifle', ['label'] = 'Service Carbine', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_assaultrifle_mk2`] = {['name'] = 'weapon_assaultrifle_mk2', ['label'] = 'Assault Rifle MK2', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_carbinerifle`] = {['name'] = 'weapon_carbinerifle', ['label'] = 'Carbine Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_carbinerifle_mk2`] = {['name'] = 'weapon_carbinerifle_mk2', ['label'] = 'Carbine Rifle MK2', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_advancedrifle`] = {['name'] = 'weapon_advancedrifle', ['label'] = 'Advanced Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_specialcarbine`] = {['name'] = 'weapon_specialcarbine', ['label'] = 'Special Carbine', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_specialcarbine_mk2`] = {['name'] = 'weapon_specialcarbine_mk2', ['label'] = 'Specialcarbine MK2', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_bullpuprifle`] = {['name'] = 'weapon_bullpuprifle', ['label'] = 'Bullpup Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_bullpuprifle_mk2`] = {['name'] = 'weapon_bullpuprifle_mk2', ['label'] = 'Bull Puprifle MK2', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_compactrifle`] = {['name'] = 'weapon_compactrifle', ['label'] = 'Compact Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_militaryrifle`] = {['name'] = 'weapon_militaryrifle', ['label'] = 'Military Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + [`weapon_heavyrifle`] = {['name'] = 'weapon_heavyrifle', ['label'] = 'Heavy Rifle', ['weapontype'] = 'Assault Rifle', ['ammotype'] = 'AMMO_RIFLE', ['damagereason'] = 'Ended / Rifled / Shot down / Floored'}, + + -- Light Machine Guns + [`weapon_mg`] = {['name'] = 'weapon_mg', ['label'] = 'Machinegun', ['weapontype'] = 'Light Machine Gun', ['ammotype'] = 'AMMO_MG', ['damagereason'] = 'Machine gunned / Sprayed / Ruined'}, + [`weapon_combatmg`] = {['name'] = 'weapon_combatmg', ['label'] = 'Combat MG', ['weapontype'] = 'Light Machine Gun', ['ammotype'] = 'AMMO_MG', ['damagereason'] = 'Machine gunned / Sprayed / Ruined'}, + [`weapon_combatmg_mk2`] = {['name'] = 'weapon_combatmg_mk2', ['label'] = 'Combat MG MK2', ['weapontype'] = 'Light Machine Gun', ['ammotype'] = 'AMMO_MG', ['damagereason'] = 'Machine gunned / Sprayed / Ruined'}, + [`weapon_gusenberg`] = {['name'] = 'weapon_gusenberg', ['label'] = 'Thompson SMG', ['weapontype'] = 'Light Machine Gun', ['ammotype'] = 'AMMO_MG', ['damagereason'] = 'Machine gunned / Sprayed / Ruined'}, + + -- Sniper Rifles + [`weapon_sniperrifle`] = {['name'] = 'weapon_sniperrifle', ['label'] = 'Sniper Rifle', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + [`weapon_heavysniper`] = {['name'] = 'weapon_heavysniper', ['label'] = 'Heavy Sniper', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + [`weapon_heavysniper_mk2`] = {['name'] = 'weapon_heavysniper_mk2', ['label'] = 'Heavysniper MK2', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + [`weapon_marksmanrifle`] = {['name'] = 'weapon_marksmanrifle', ['label'] = 'Marksman Rifle', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + [`weapon_marksmanrifle_mk2`] = {['name'] = 'weapon_marksmanrifle_mk2', ['label'] = 'Marksman Rifle MK2', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + [`weapon_remotesniper`] = {['name'] = 'weapon_remotesniper', ['label'] = 'Remote Sniper', ['weapontype'] = 'Sniper Rifle', ['ammotype'] = 'AMMO_SNIPER_REMOTE', ['damagereason'] = 'Sniped / Picked off / Scoped'}, + + -- Heavy Weapons + [`weapon_rpg`] = {['name'] = 'weapon_rpg', ['label'] = 'RPG', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_RPG', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_grenadelauncher`] = {['name'] = 'weapon_grenadelauncher', ['label'] = 'Grenade Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_GRENADELAUNCHER', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_grenadelauncher_smoke`] = {['name'] = 'weapon_grenadelauncher_smoke', ['label'] = 'Smoke Grenade Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_GRENADELAUNCHER', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_minigun`] = {['name'] = 'weapon_minigun', ['label'] = 'Minigun', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_MINIGUN', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_firework`] = {['name'] = 'weapon_firework', ['label'] = 'Firework Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = nil, ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_railgun`] = {['name'] = 'weapon_railgun', ['label'] = 'Railgun', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = nil, ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_hominglauncher`] = {['name'] = 'weapon_hominglauncher', ['label'] = 'Homing Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_STINGER', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_compactlauncher`] = {['name'] = 'weapon_compactlauncher', ['label'] = 'Compact Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = nil, ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_rayminigun`] = {['name'] = 'weapon_rayminigun', ['label'] = 'Ray Minigun', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_MINIGUN', ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_emplauncher`] = {['name'] = 'weapon_emplauncher', ['label'] = 'EMP Launcher', ['weapontype'] = 'Heavy Weapons', ['ammotype'] = 'AMMO_EMPLAUNCHER', ['damagereason'] = 'Died'}, + + -- Throwables + [`weapon_grenade`] = {['name'] = 'weapon_grenade', ['label'] = 'Grenade', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Bombed / Exploded / Detonated / Blew up'}, + [`weapon_bzgas`] = {['name'] = 'weapon_bzgas', ['label'] = 'BZ Gas', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_molotov`] = {['name'] = 'weapon_molotov', ['label'] = 'Molotov', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Torched / Flambeed / Barbecued'}, + [`weapon_stickybomb`] = {['name'] = 'weapon_stickybomb', ['label'] = 'C4', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Bombed / Exploded / Detonated / Blew up'}, + [`weapon_proxmine`] = {['name'] = 'weapon_proxmine', ['label'] = 'Proxmine Grenade', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Bombed / Exploded / Detonated / Blew up'}, + [`weapon_snowball`] = {['name'] = 'weapon_snowball', ['label'] = 'Snowball', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_pipebomb`] = {['name'] = 'weapon_pipebomb', ['label'] = 'Pipe Bomb', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Bombed / Exploded / Detonated / Blew up'}, + [`weapon_ball`] = {['name'] = 'weapon_ball', ['label'] = 'Ball', ['weapontype'] = 'Throwable', ['ammotype'] = 'AMMO_BALL', ['damagereason'] = 'Died'}, + [`weapon_smokegrenade`] = {['name'] = 'weapon_smokegrenade', ['label'] = 'Smoke Grenade', ['weapontype'] = 'Throwable', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_flare`] = {['name'] = 'weapon_flare', ['label'] = 'Flare pistol', ['weapontype'] = 'Throwable', ['ammotype'] = 'AMMO_FLARE', ['damagereason'] = 'Died'}, + + -- Miscellaneous + [`weapon_petrolcan`] = {['name'] = 'weapon_petrolcan', ['label'] = 'Petrol Can', ['weapontype'] = 'Miscellaneous', ['ammotype'] = 'AMMO_PETROLCAN', ['damagereason'] = 'Died'}, + [`gadget_parachute`] = {['name'] = 'gadget_parachute', ['label'] = 'Parachute', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_fireextinguisher`] = {['name'] = 'weapon_fireextinguisher', ['label'] = 'Fire Extinguisher', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_hazardcan`] = {['name'] = 'weapon_hazardcan', ['label'] = 'Hazardcan', ['weapontype'] = 'Miscellaneous', ['ammotype'] = 'AMMO_PETROLCAN', ['damagereason'] = 'Died'}, + [`weapon_fertilizercan`] = {['name'] = 'weapon_fertilizercan', ['label'] = 'Fertilizer Can', ['weapontype'] = 'Miscellaneous', ['ammotype'] = 'AMMO_FERTILIZERCAN', ['damagereason'] = 'Died'}, + [`weapon_barbed_wire`] = {['name'] = 'weapon_barbed_wire', ['label'] = 'Barbed Wire', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Prodded'}, + [`weapon_drowning`] = {['name'] = 'weapon_drowning', ['label'] = 'Drowning', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_drowning_in_vehicle`] = {['name'] = 'weapon_drowning_in_vehicle', ['label'] = 'Drowning in a Vehicle', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_bleeding`] = {['name'] = 'weapon_bleeding', ['label'] = 'Bleeding', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Bled out'}, + [`weapon_electric_fence`] = {['name'] = 'weapon_electric_fence', ['label'] = 'Electric Fence', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Fried'}, + [`weapon_explosion`] = {['name'] = 'weapon_explosion', ['label'] = 'Explosion', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Killed / Exploded / Obliterated / Destroyed / Erased / Annihilated'}, + [`weapon_fall`] = {['name'] = 'weapon_fall', ['label'] = 'Fall', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Committed suicide'}, + [`weapon_exhaustion`] = {['name'] = 'weapon_exhaustion', ['label'] = 'Exhaustion', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_hit_by_water_cannon`] = {['name'] = 'weapon_hit_by_water_cannon', ['label'] = 'Water Cannon', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Died'}, + [`weapon_rammed_by_car`] = {['name'] = 'weapon_rammed_by_car', ['label'] = 'Rammed - Vehicle', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Flattened / Ran over / Ran down'}, + [`weapon_run_over_by_car`] = {['name'] = 'weapon_run_over_by_car', ['label'] = 'Run Over - Vehicle', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Flattened / Ran over / Ran down'}, + [`weapon_heli_crash`] = {['name'] = 'weapon_heli_crash', ['label'] = 'Heli Crash', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Helicopter Crash'}, + [`weapon_fire`] = {['name'] = 'weapon_fire', ['label'] = 'Fire', ['weapontype'] = 'Miscellaneous', ['ammotype'] = nil, ['damagereason'] = 'Torched / Flambeed / Barbecued'}, + + -- Animals + [`weapon_animal`] = {['name'] = 'weapon_animal', ['label'] = 'Animal', ['weapontype'] = 'Animals', ['ammotype'] = nil, ['damagereason'] = 'Mauled'}, + [`weapon_cougar`] = {['name'] = 'weapon_cougar', ['label'] = 'Cougar', ['weapontype'] = 'Animals', ['ammotype'] = nil, ['damagereason'] = 'Mauled'}, + [`weapon_shoe`] = {['name'] = 'weapon_shoe', ['label'] = 'Shoe', ['ammotype'] = nil, ['damagereason'] = 'Died'}, +}