Part 4
51
resources/[sna]/sna-alpr/client/client.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// integrations/alpr/client/client.ts
|
||||||
|
onNet("sn:cadBoloResults" /* ALPRCadBoloResults */, (plate, body) => {
|
||||||
|
if (!body || body === "failed")
|
||||||
|
return;
|
||||||
|
if (body.bolos.length > 0) {
|
||||||
|
emit("sna-sync:create-notification" /* CreateNotification */, {
|
||||||
|
title: "Active Bolo Notice",
|
||||||
|
message: `${plate} has an active BOLO. Open SnailyCAD for more details.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onNet("sn:cadPlateResults" /* ALPRCadPlateResults */, (plate, body) => {
|
||||||
|
var _a, _b, _c, _d;
|
||||||
|
if (!body || body === "failed") {
|
||||||
|
return emit("sna-sync:create-notification" /* CreateNotification */, {
|
||||||
|
message: "Unable to fetch plate search results: failed to fetch.",
|
||||||
|
title: "Plate Search Results"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const [vehicle] = body;
|
||||||
|
if (!vehicle) {
|
||||||
|
return emit("sna-sync:create-notification" /* CreateNotification */, {
|
||||||
|
message: `Plate is not registered: ${plate}`,
|
||||||
|
title: "Plate Search Results"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const owner = vehicle.citizen ? `${vehicle.citizen.name} ${vehicle.citizen.surname}` : "Unknown";
|
||||||
|
const message = [
|
||||||
|
`<li><b>Plate:</b> ${plate}</li>`,
|
||||||
|
`<li><b>Model:</b> ${vehicle.model.value.value}</li>`,
|
||||||
|
`<li><b>Color:</b> ${vehicle.color}</li>`,
|
||||||
|
`<li><b>VIN Number:</b> ${vehicle.vinNumber}</li>`,
|
||||||
|
`<li><b>Owner:</b> ${owner}</li>`
|
||||||
|
];
|
||||||
|
emit("sna-sync:create-notification" /* CreateNotification */, {
|
||||||
|
message: message.join("\n"),
|
||||||
|
title: "Plate Search Results",
|
||||||
|
timeout: 17e3
|
||||||
|
});
|
||||||
|
const warrants = ((_b = (_a = vehicle.citizen) == null ? void 0 : _a.warrants) == null ? void 0 : _b.filter((v) => v.status === "ACTIVE")) ?? [];
|
||||||
|
const hasWarrants = warrants.length > 0;
|
||||||
|
if (hasWarrants) {
|
||||||
|
const citizenFullName = `${(_c = vehicle.citizen) == null ? void 0 : _c.name} ${(_d = vehicle.citizen) == null ? void 0 : _d.surname}`;
|
||||||
|
emit("sna-sync:create-notification" /* CreateNotification */, {
|
||||||
|
title: "Active Warrants Notice",
|
||||||
|
message: `This vehicle - ${citizenFullName} - owner has active warrants.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
2
resources/[sna]/sna-alpr/documentation.url
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[InternetShortcut]
|
||||||
|
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-alpr
|
9
resources/[sna]/sna-alpr/fxmanifest.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fx_version "cerulean"
|
||||||
|
game "gta5"
|
||||||
|
|
||||||
|
author "Casper Iversen"
|
||||||
|
description "ALPR integration with support for Wraith ARS 2X"
|
||||||
|
version "0.13.1"
|
||||||
|
|
||||||
|
server_scripts {"server/server.js"}
|
||||||
|
client_scripts {"client/client.js"}
|
15880
resources/[sna]/sna-alpr/server/server.js
Normal file
53
resources/[sna]/sna-call911/client/client.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// src/utils/notification.ts
|
||||||
|
function createNotification(options) {
|
||||||
|
SetNotificationTextEntry("STRING");
|
||||||
|
AddTextComponentString(options.message);
|
||||||
|
SetNotificationMessage(
|
||||||
|
options.picture,
|
||||||
|
options.picture,
|
||||||
|
true,
|
||||||
|
options.icon ?? 0 /* None */,
|
||||||
|
options.title,
|
||||||
|
options.subject ?? ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// integrations/call911/client/client.ts
|
||||||
|
emit("chat:addSuggestion", `/${"sn-call911" /* Call911 */}`, "Contact the emergency services.", [
|
||||||
|
{ name: "description", help: "The description of the call" }
|
||||||
|
]);
|
||||||
|
onNet("sn:911Call" /* Call911ToClient */, ({ source, name, description }) => {
|
||||||
|
const playerPed = GetPlayerPed(-1);
|
||||||
|
const [x, y, z] = GetEntityCoords(playerPed, true);
|
||||||
|
const [lastStreet] = GetStreetNameAtCoord(x, y, z);
|
||||||
|
const lastStreetName = GetStreetNameFromHashKey(lastStreet);
|
||||||
|
const heading = GetEntityHeading(PlayerPedId());
|
||||||
|
setImmediate(() => {
|
||||||
|
emitNet("sn:911CallUpdate" /* Call911ToServer */, {
|
||||||
|
street: lastStreetName,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
position: { x, y, z, heading },
|
||||||
|
source
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
onNet("sn:911CallResponse" /* Call911ToClientResponse */, (state) => {
|
||||||
|
if (state === "success") {
|
||||||
|
createNotification({
|
||||||
|
picture: "CHAR_CALL911" /* CHAR_CALL911 */,
|
||||||
|
icon: 1 /* ChatBox */,
|
||||||
|
message: "Your call has been reported to the emergency services",
|
||||||
|
title: "Emergency Services"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createNotification({
|
||||||
|
picture: "CHAR_CALL911" /* CHAR_CALL911 */,
|
||||||
|
icon: 1 /* ChatBox */,
|
||||||
|
message: "We were unable to process your 911 call at this time.",
|
||||||
|
title: "Failed to report call"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
2
resources/[sna]/sna-call911/documentation.url
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[InternetShortcut]
|
||||||
|
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-call911
|
9
resources/[sna]/sna-call911/fxmanifest.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fx_version "cerulean"
|
||||||
|
game "gta5"
|
||||||
|
|
||||||
|
author "Casper Iversen"
|
||||||
|
description "/call911 command that connects to SnailyCADv4"
|
||||||
|
version "0.13.1"
|
||||||
|
|
||||||
|
server_scripts {"server/server.js"}
|
||||||
|
client_scripts {"client/client.js"}
|
24355
resources/[sna]/sna-call911/server/server.js
Normal file
305
resources/[sna]/sna-live-map/client/client.js
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// src/utils/getWeaponNameFromHash.ts
|
||||||
|
var WEAPON_HASHES = {
|
||||||
|
"100416529": "Sniper Rifle",
|
||||||
|
"101631238": "Fire Extinguisher",
|
||||||
|
"125959754": "Compact Grenade Launcher",
|
||||||
|
"126349499": "Snowball",
|
||||||
|
"137902532": "Vintage Pistol",
|
||||||
|
"171789620": "Combat PDW",
|
||||||
|
"177293209": "Heavy Sniper Mk II",
|
||||||
|
"205991906": "Heavy Sniper",
|
||||||
|
"317205821": "Sweeper Shotgun",
|
||||||
|
"324215364": "Micro SMG",
|
||||||
|
"419712736": "Pipe Wrench",
|
||||||
|
"453432689": "Pistol",
|
||||||
|
"487013001": "Pump Shotgun",
|
||||||
|
"584646201": "AP Pistol",
|
||||||
|
"600439132": "Ball",
|
||||||
|
"615608432": "Molotov",
|
||||||
|
"736523883": "SMG",
|
||||||
|
"741814745": "Sticky Bomb",
|
||||||
|
"883325847": "Jerry Can",
|
||||||
|
"911657153": "Stun Gun",
|
||||||
|
"940833800": "Stone Hatchet",
|
||||||
|
"961495388": "Assault Rifle Mk II",
|
||||||
|
"984333226": "Heavy Shotgun",
|
||||||
|
"1119849093": "Minigun",
|
||||||
|
"1141786504": "Golf Club",
|
||||||
|
"1198256469": "Unholy Hellbringer",
|
||||||
|
"1198879012": "Flare Gun",
|
||||||
|
"1233104067": "Flare",
|
||||||
|
"1317494643": "Hammer",
|
||||||
|
"1432025498": "Pump Shotgun Mk II",
|
||||||
|
"1593441988": "Combat Pistol",
|
||||||
|
"1627465347": "Gusenberg Sweeper",
|
||||||
|
"1649403952": "Compact Rifle",
|
||||||
|
"1672152130": "Homing Launcher",
|
||||||
|
"1737195953": "Nightstick",
|
||||||
|
"1785463520": "Marksman Rifle Mk II",
|
||||||
|
"1834241177": "Railgun",
|
||||||
|
"2017895192": "Sawed-Off Shotgun",
|
||||||
|
"2024373456": "SMG Mk II",
|
||||||
|
"2132975508": "Bullpup Rifle",
|
||||||
|
"2138347493": "Firework Launcher",
|
||||||
|
"2144741730": "Combat MG",
|
||||||
|
"2210333304": "Carbine Rifle",
|
||||||
|
"2227010557": "Crowbar",
|
||||||
|
"2228681469": "Bullpup Rifle Mk II",
|
||||||
|
"2285322324": "SNS Pistol Mk II",
|
||||||
|
"2343591895": "Flashlight",
|
||||||
|
"2460120199": "Antique Cavalry Dagger",
|
||||||
|
"2481070269": "Grenade",
|
||||||
|
"2484171525": "Pool Cue",
|
||||||
|
"2508868239": "Baseball Bat",
|
||||||
|
"2526821735": "Special Carbine Mk II",
|
||||||
|
"2548703416": "Double-Action Revolver",
|
||||||
|
"2578377531": "Pistol .50",
|
||||||
|
"2578778090": "Knife",
|
||||||
|
"2634544996": "MG",
|
||||||
|
"2640438543": "Bullpup Shotgun",
|
||||||
|
"2694266206": "BZ Gas",
|
||||||
|
"2726580491": "Grenade Launcher",
|
||||||
|
"2828843422": "Musket",
|
||||||
|
"2874559379": "Proximity Mine",
|
||||||
|
"2937143193": "Advanced Rifle",
|
||||||
|
"2939590305": "Up-n-Atomizer",
|
||||||
|
"2982836145": "RPG",
|
||||||
|
"3056410471": "Widowmaker",
|
||||||
|
"3125143736": "Pipe Bomb",
|
||||||
|
"3173288789": "Mini SMG",
|
||||||
|
"3218215474": "SNS Pistol",
|
||||||
|
"3219281620": "Pistol Mk II",
|
||||||
|
"3220176749": "Assault Rifle",
|
||||||
|
"3231910285": "Special Carbine",
|
||||||
|
"3520460075": "Service Rifle",
|
||||||
|
"3249783761": "Heavy Revolver",
|
||||||
|
"3342088282": "Marksman Rifle",
|
||||||
|
"3415619887": "Heavy Revolver Mk II",
|
||||||
|
"3441901897": "Battle Axe",
|
||||||
|
"3523564046": "Heavy Pistol",
|
||||||
|
"3638508604": "Knuckle Duster",
|
||||||
|
"3675956304": "Machine Pistol",
|
||||||
|
"3686625920": "Combat MG Mk II",
|
||||||
|
"3696079510": "Marksman Pistol",
|
||||||
|
"3713923289": "Machete",
|
||||||
|
"3756226112": "Switchblade",
|
||||||
|
"3800352039": "Assault Shotgun",
|
||||||
|
"4019527611": "Double Barrel Shotgun",
|
||||||
|
"4024951519": "Assault SMG",
|
||||||
|
"4191993645": "Hatchet",
|
||||||
|
"4192643659": "Bottle",
|
||||||
|
"4208062921": "Carbine Rifle Mk II",
|
||||||
|
"4256991824": "Tear Gas"
|
||||||
|
};
|
||||||
|
function getWeaponNameFromHash(hash) {
|
||||||
|
const name = WEAPON_HASHES[hash.toString(10)];
|
||||||
|
if (name) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getWeapon.ts
|
||||||
|
function getWeapon(pedId) {
|
||||||
|
const weaponHash = GetSelectedPedWeapon(pedId);
|
||||||
|
const hash = getWeaponNameFromHash(weaponHash);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getArea.ts
|
||||||
|
var areaHashes = {
|
||||||
|
"2072609373": "Blaine County",
|
||||||
|
"-289320599": "Los Santos"
|
||||||
|
};
|
||||||
|
function getArea(position) {
|
||||||
|
const areaHash = GetHashOfMapAreaAtCoords(...position);
|
||||||
|
return areaHashes[areaHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getZone.ts
|
||||||
|
var areaHashes2 = {
|
||||||
|
[GetHashKey("AIRP")]: "Los Santos International Airport",
|
||||||
|
[GetHashKey("ALAMO")]: "Alamo Sea",
|
||||||
|
[GetHashKey("ALTA")]: "Alta",
|
||||||
|
[GetHashKey("ARMYB")]: "Fort Zancudo",
|
||||||
|
[GetHashKey("BANHAMC")]: "Banham Canyon Dr",
|
||||||
|
[GetHashKey("BANNING")]: "Banning",
|
||||||
|
[GetHashKey("BEACH")]: "Vespucci Beach",
|
||||||
|
[GetHashKey("BHAMCA")]: "Banham Canyon",
|
||||||
|
[GetHashKey("BRADP")]: "Braddock Pass",
|
||||||
|
[GetHashKey("BRADT")]: "Braddock Tunnel",
|
||||||
|
[GetHashKey("BURTON")]: "Burton",
|
||||||
|
[GetHashKey("CALAFB")]: "Calafia Bridge",
|
||||||
|
[GetHashKey("CANNY")]: "Raton Canyon",
|
||||||
|
[GetHashKey("CCREAK")]: "Cassidy Creek",
|
||||||
|
[GetHashKey("CHAMH")]: "Chamberlain Hills",
|
||||||
|
[GetHashKey("CHIL")]: "Vinewood Hills",
|
||||||
|
[GetHashKey("CHU")]: "Chumash",
|
||||||
|
[GetHashKey("CMSW")]: "Chiliad Mountain State Wilderness",
|
||||||
|
[GetHashKey("CYPRE")]: "Cypress Flats",
|
||||||
|
[GetHashKey("DAVIS")]: "Davis",
|
||||||
|
[GetHashKey("DELBE")]: "Del Perro Beach",
|
||||||
|
[GetHashKey("DELPE")]: "Del Perro",
|
||||||
|
[GetHashKey("DELSOL")]: "La Puerta",
|
||||||
|
[GetHashKey("DESRT")]: "Grand Senora Desert",
|
||||||
|
[GetHashKey("DOWNT")]: "Downtown",
|
||||||
|
[GetHashKey("DTVINE")]: "Downtown Vinewood",
|
||||||
|
[GetHashKey("EAST_V")]: "East Vinewood",
|
||||||
|
[GetHashKey("EBURO")]: "El Burro Heights",
|
||||||
|
[GetHashKey("ELGORL")]: "El Gordo Lighthouse",
|
||||||
|
[GetHashKey("ELYSIAN")]: "Elysian Island",
|
||||||
|
[GetHashKey("GALFISH")]: "Galilee",
|
||||||
|
[GetHashKey("GOLF")]: "GWC and Golfing Society",
|
||||||
|
[GetHashKey("GRAPES")]: "Grapeseed",
|
||||||
|
[GetHashKey("GREATC")]: "Great Chaparral",
|
||||||
|
[GetHashKey("HARMO")]: "Harmony",
|
||||||
|
[GetHashKey("HAWICK")]: "Hawick",
|
||||||
|
[GetHashKey("HORS")]: "Vinewood Racetrack",
|
||||||
|
[GetHashKey("HUMLAB")]: "Humane Labs and Research",
|
||||||
|
[GetHashKey("JAIL")]: "Bolingbroke Penitentiary",
|
||||||
|
[GetHashKey("KOREAT")]: "Little Seoul",
|
||||||
|
[GetHashKey("LACT")]: "Land Act Reservoir",
|
||||||
|
[GetHashKey("LAGO")]: "Lago Zancudo",
|
||||||
|
[GetHashKey("LDAM")]: "Land Act Dam",
|
||||||
|
[GetHashKey("LEGSQU")]: "Legion Square",
|
||||||
|
[GetHashKey("LMESA")]: "La Mesa",
|
||||||
|
[GetHashKey("LOSPUER")]: "La Puerta",
|
||||||
|
[GetHashKey("MIRR")]: "Mirror Park",
|
||||||
|
[GetHashKey("MORN")]: "Morningwood",
|
||||||
|
[GetHashKey("MOVIE")]: "Richards Majestic",
|
||||||
|
[GetHashKey("MTCHIL")]: "Mount Chiliad",
|
||||||
|
[GetHashKey("MTGORDO")]: "Mount Gordo",
|
||||||
|
[GetHashKey("MTJOSE")]: "Mount Josiah",
|
||||||
|
[GetHashKey("MURRI")]: "Murrieta Heights",
|
||||||
|
[GetHashKey("NCHU")]: "North Chumash",
|
||||||
|
[GetHashKey("NOOSE")]: "N.O.O.S.E",
|
||||||
|
[GetHashKey("OCEANA")]: "Pacific Ocean",
|
||||||
|
[GetHashKey("PALCOV")]: "Paleto Cove",
|
||||||
|
[GetHashKey("PALETO")]: "Paleto Bay",
|
||||||
|
[GetHashKey("PALFOR")]: "Paleto Forest",
|
||||||
|
[GetHashKey("PALHIGH")]: "Palomino Highlands",
|
||||||
|
[GetHashKey("PALMPOW")]: "Palmer-Taylor Power Station",
|
||||||
|
[GetHashKey("PBLUFF")]: "Pacific Bluffs",
|
||||||
|
[GetHashKey("PBOX")]: "Pillbox Hill",
|
||||||
|
[GetHashKey("PROCOB")]: "Procopio Beach",
|
||||||
|
[GetHashKey("RANCHO")]: "Rancho",
|
||||||
|
[GetHashKey("RGLEN")]: "Richman Glen",
|
||||||
|
[GetHashKey("RICHM")]: "Richman",
|
||||||
|
[GetHashKey("ROCKF")]: "Rockford Hills",
|
||||||
|
[GetHashKey("RTRAK")]: "Redwood Lights Track",
|
||||||
|
[GetHashKey("SANAND")]: "San Andreas",
|
||||||
|
[GetHashKey("SANCHIA")]: "San Chianski Mountain Range",
|
||||||
|
[GetHashKey("SANDY")]: "Sandy Shores",
|
||||||
|
[GetHashKey("SKID")]: "Mission Row",
|
||||||
|
[GetHashKey("SLAB")]: "Stab City",
|
||||||
|
[GetHashKey("STAD")]: "Maze Bank Arena",
|
||||||
|
[GetHashKey("STRAW")]: "Strawberry",
|
||||||
|
[GetHashKey("TATAMO")]: "Tataviam Mountains",
|
||||||
|
[GetHashKey("TERMINA")]: "Terminal",
|
||||||
|
[GetHashKey("TEXTI")]: "Textile City",
|
||||||
|
[GetHashKey("TONGVAH")]: "Tongva Hills",
|
||||||
|
[GetHashKey("TONGVAV")]: "Tongva Valley",
|
||||||
|
[GetHashKey("VCANA")]: "Vespucci Canals",
|
||||||
|
[GetHashKey("VESP")]: "Vespucci",
|
||||||
|
[GetHashKey("VINE")]: "Vinewood",
|
||||||
|
[GetHashKey("WINDF")]: "Ron Alternates Wind Farm",
|
||||||
|
[GetHashKey("WVINE")]: "West Vinewood",
|
||||||
|
[GetHashKey("ZANCUDO")]: "Zancudo River",
|
||||||
|
[GetHashKey("ZP_ORT")]: "Port of South Los Santos",
|
||||||
|
[GetHashKey("ZQ_UAR")]: "Davis Quartz"
|
||||||
|
};
|
||||||
|
function getZone(position) {
|
||||||
|
const areaHash = GetHashKey(GetNameOfZone(...position));
|
||||||
|
return areaHashes2[areaHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getLocation.ts
|
||||||
|
function getLocation(pos) {
|
||||||
|
const [lastStreet] = GetStreetNameAtCoord(...pos);
|
||||||
|
const streetName = GetStreetNameFromHashKey(lastStreet);
|
||||||
|
const zone = getZone(pos);
|
||||||
|
const area = getArea(pos);
|
||||||
|
const location = `${streetName}, ${zone} (${area})`;
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getVehicle.ts
|
||||||
|
function getVehicle(pedId) {
|
||||||
|
const vehicle = GetVehiclePedIsIn(pedId, false);
|
||||||
|
if (vehicle === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const licensePlate = GetVehicleNumberPlateText(vehicle);
|
||||||
|
const hasSirenEnabled = isSirenEnabled(vehicle);
|
||||||
|
let vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)));
|
||||||
|
if (vehicleName === "NULL") {
|
||||||
|
vehicleName = GetDisplayNameFromVehicleModel(GetEntityModel(vehicle));
|
||||||
|
}
|
||||||
|
return { licensePlate, vehicle: vehicleName, hasSirenEnabled };
|
||||||
|
}
|
||||||
|
function isSirenEnabled(vehicle) {
|
||||||
|
const sirenEnabledValue = IsVehicleSirenOn(vehicle) || IsVehicleSirenAudioOn(vehicle) || IsVehicleSirenSoundOn(vehicle);
|
||||||
|
if (typeof sirenEnabledValue === "number") {
|
||||||
|
return sirenEnabledValue === 1;
|
||||||
|
}
|
||||||
|
return sirenEnabledValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/getIcon.ts
|
||||||
|
function getIcon(pedId) {
|
||||||
|
if (!IsPedInAnyVehicle(pedId, false))
|
||||||
|
return 6;
|
||||||
|
const vehicle = GetVehiclePedIsIn(pedId, false);
|
||||||
|
if (vehicle === 0) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
const vehicleModel = GetEntityModel(vehicle);
|
||||||
|
if (isPoliceVehicle(vehicle))
|
||||||
|
return 56;
|
||||||
|
if (isTowTruck(vehicleModel))
|
||||||
|
return 68;
|
||||||
|
if (IsThisModelAHeli(vehicleModel))
|
||||||
|
return 64;
|
||||||
|
return 225;
|
||||||
|
}
|
||||||
|
function isPoliceVehicle(vehicle) {
|
||||||
|
const vehicleClass = GetVehicleClass(vehicle);
|
||||||
|
return vehicleClass === 18;
|
||||||
|
}
|
||||||
|
function isTowTruck(vehicleModel) {
|
||||||
|
const hashes = [GetHashKey("towtruck"), GetHashKey("towtruck2")];
|
||||||
|
return hashes.includes(vehicleModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// integration/client/client.ts
|
||||||
|
var firstSpawn = true;
|
||||||
|
onNet("playerDropped" /* CFXPlayerDropped */, () => {
|
||||||
|
if (firstSpawn) {
|
||||||
|
emitPlayerData();
|
||||||
|
firstSpawn = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInterval(() => {
|
||||||
|
emitPlayerData();
|
||||||
|
}, 500);
|
||||||
|
function emitPlayerData() {
|
||||||
|
const [playerX, playerY, playerZ] = GetEntityCoords(PlayerPedId(), false);
|
||||||
|
const vehicle = getVehicle(PlayerPedId());
|
||||||
|
const weapon = getWeapon(PlayerPedId());
|
||||||
|
const location = getLocation([playerX, playerY, playerZ]);
|
||||||
|
const icon = getIcon(PlayerPedId());
|
||||||
|
emitNet("sna-live-map-player-spawned" /* PlayerSpawned */, {
|
||||||
|
playerId: PlayerPedId(),
|
||||||
|
name: GetPlayerName(PlayerId()),
|
||||||
|
location,
|
||||||
|
pos: { x: playerX, y: playerY, z: playerZ },
|
||||||
|
weapon,
|
||||||
|
icon,
|
||||||
|
...vehicle
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onNet("smartmotorways:syncSignsClient", (signId) => {
|
||||||
|
emitNet("sna-live-map-sign-smart-motorways" /* SyncSmartMotorwaysSigns */, signId);
|
||||||
|
});
|
9
resources/[sna]/sna-live-map/fxmanifest.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fx_version "cerulean"
|
||||||
|
game "gta5"
|
||||||
|
|
||||||
|
author "Dev-CasperTheGhost"
|
||||||
|
description "SnailyCAD Live Map integration for FiveM."
|
||||||
|
version "0.2.2"
|
||||||
|
|
||||||
|
client_scripts {"client/client.js"}
|
||||||
|
server_scripts {"server/server.js"}
|
21939
resources/[sna]/sna-live-map/server/server.js
Normal file
145
resources/[sna]/sna-sync/client/client.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// integrations/sync/client/flows/auth.ts
|
||||||
|
var API_URL = GetConvar("snailycad_url", "null");
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-whoami" /* WhoAmI */}`,
|
||||||
|
"Shows your current SnailyCAD account username and ID that is connected to the game."
|
||||||
|
);
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-auth" /* Auth */}`,
|
||||||
|
"Authenticate with your personal SnailyCAD API Token to interact with parts of it."
|
||||||
|
);
|
||||||
|
onNet("sna-sync:request-authentication-flow" /* RequestAuthFlow */, () => {
|
||||||
|
SendNuiMessage(
|
||||||
|
JSON.stringify({ action: "sna-sync:request-authentication-flow" /* RequestAuthFlow */, data: { url: API_URL, source } })
|
||||||
|
);
|
||||||
|
SetNuiFocus(true, true);
|
||||||
|
});
|
||||||
|
RegisterNuiCallbackType("sna-sync-nui:authentication-flow-success" /* OnAuthenticationFlowSuccess */);
|
||||||
|
on(`__cfx_nui:${"sna-sync-nui:authentication-flow-success" /* OnAuthenticationFlowSuccess */}`, (data, cb) => {
|
||||||
|
emitNet("sna-sync:on-user-save" /* OnUserSave */, data);
|
||||||
|
cb({ ok: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
// integrations/sync/client/flows/unit-status.ts
|
||||||
|
var API_URL2 = GetConvar("snailycad_url", "null");
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-active-unit" /* ActiveUnit */}`,
|
||||||
|
"This will show your active unit's name and status."
|
||||||
|
);
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-set-status" /* SetStatus */}`,
|
||||||
|
"This will open a menu and will allow you to select a status for your active unit.",
|
||||||
|
[{ name: "status-code", help: "The status code you want to set (Optional)." }]
|
||||||
|
);
|
||||||
|
onNet(
|
||||||
|
"sna-sync:request-set-status-flow" /* RequestSetStatusFlow */,
|
||||||
|
(unitId, source2, userApiToken, statusCodes) => {
|
||||||
|
SendNuiMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
action: "sna-sync:request-set-status-flow" /* RequestSetStatusFlow */,
|
||||||
|
data: { url: API_URL2, source: source2, unitId, userApiToken, statusCodes }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
SetNuiFocus(true, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// integrations/sync/client/flows/911-call-attach.ts
|
||||||
|
var API_URL3 = GetConvar("snailycad_url", "null");
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-attach" /* AttachTo911Call */}`,
|
||||||
|
"Attach your active unit to a 911 call.",
|
||||||
|
[{ name: "case-number", help: "The case number of the 911 call (Optional)." }]
|
||||||
|
);
|
||||||
|
onNet(
|
||||||
|
"sna-sync:request-call-911-attach-flow" /* RequestCall911AttachFlow */,
|
||||||
|
(unitId, source2, calls, userApiToken) => {
|
||||||
|
SendNuiMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
action: "sna-sync:request-call-911-attach-flow" /* RequestCall911AttachFlow */,
|
||||||
|
data: { url: API_URL3, userApiToken, source: source2, unitId, calls }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
SetNuiFocus(true, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// integrations/sync/client/flows/traffic-stop.ts
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-traffic-stop" /* TrafficStop */}`,
|
||||||
|
"Create a call with your current position and be assigned as primary unit.",
|
||||||
|
[{ name: "description", help: "The description of your traffic stop" }]
|
||||||
|
);
|
||||||
|
onNet(
|
||||||
|
"sna-sync:request-traffic-stop-flow" /* RequestTrafficStopFlow */,
|
||||||
|
(data) => {
|
||||||
|
const playerPed = GetPlayerPed(-1);
|
||||||
|
const [x, y, z] = GetEntityCoords(playerPed, true);
|
||||||
|
const [lastStreet] = GetStreetNameAtCoord(x, y, z);
|
||||||
|
const lastStreetName = GetStreetNameFromHashKey(lastStreet);
|
||||||
|
const heading = GetEntityHeading(PlayerPedId());
|
||||||
|
setImmediate(() => {
|
||||||
|
emitNet("sna-sync:on-traffic-stop-client-position" /* OnTrafficStopClientPosition */, {
|
||||||
|
...data,
|
||||||
|
streetName: lastStreetName,
|
||||||
|
position: { x, y, z, heading }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// integrations/sync/client/client.ts
|
||||||
|
var API_URL4 = GetConvar("snailycad_url", "null");
|
||||||
|
if (API_URL4 === "null") {
|
||||||
|
console.error(`
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
[${GetCurrentResourceName()}] Failed to find the "snailycad_url" convar in your server.cfg. Please make sure you are using \`setr\` and not \`set\`:
|
||||||
|
|
||||||
|
\`setr snailycad_url "<api-url-here>/v1" \`
|
||||||
|
|
||||||
|
---------------------------------------`);
|
||||||
|
}
|
||||||
|
emit(
|
||||||
|
"chat:addSuggestion",
|
||||||
|
`/${"sn-panic-button" /* PanicButton */}`,
|
||||||
|
"Toggle the panic button state for your active unit."
|
||||||
|
);
|
||||||
|
onNet("playerSpawned", () => {
|
||||||
|
SendNuiMessage(JSON.stringify({ action: "sn:initialize", data: { url: API_URL4 } }));
|
||||||
|
});
|
||||||
|
on(
|
||||||
|
"sna-sync:create-notification" /* CreateNotification */,
|
||||||
|
(options) => {
|
||||||
|
SendNuiMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
action: "sna-sync:create-notification" /* CreateNotification */,
|
||||||
|
data: { ...options, url: API_URL4 }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
RegisterNuiCallbackType("sna-sync-nui:connected" /* Connected */);
|
||||||
|
on(`__cfx_nui:${"sna-sync-nui:connected" /* Connected */}`, (_data, cb) => {
|
||||||
|
console.info("Connected to SnailyCAD!");
|
||||||
|
cb({ ok: true });
|
||||||
|
});
|
||||||
|
RegisterNuiCallbackType("sna-sync-nui:close-nui" /* CloseNui */);
|
||||||
|
on(`__cfx_nui:${"sna-sync-nui:close-nui" /* CloseNui */}`, (_data, cb) => {
|
||||||
|
SetNuiFocus(false, false);
|
||||||
|
cb({ ok: true });
|
||||||
|
});
|
||||||
|
RegisterNuiCallbackType("sna-sync-nui:connect_error" /* ConnectionError */);
|
||||||
|
on(`__cfx_nui:${"sna-sync-nui:connect_error" /* ConnectionError */}`, (data, cb) => {
|
||||||
|
console.info((data == null ? void 0 : data.message) ?? (data == null ? void 0 : data.name) ?? (String(data) || "Unknown error"));
|
||||||
|
console.info("Unable to connect to SnailyCAD. Error:", data);
|
||||||
|
cb({ ok: true });
|
||||||
|
});
|
2
resources/[sna]/sna-sync/documentation.url
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[InternetShortcut]
|
||||||
|
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-sync
|
15
resources/[sna]/sna-sync/fxmanifest.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
fx_version "bodacious"
|
||||||
|
game "gta5"
|
||||||
|
|
||||||
|
author "Casper Iversen"
|
||||||
|
description "Sync SnailyCAD with FiveM."
|
||||||
|
version "0.13.1"
|
||||||
|
|
||||||
|
ui_page "nui/index.html"
|
||||||
|
|
||||||
|
files {
|
||||||
|
"nui/**/*",
|
||||||
|
}
|
||||||
|
|
||||||
|
client_scripts {"client/client.js"}
|
||||||
|
server_scripts {"server/server.js"}
|
1
resources/[sna]/sna-sync/nui/alert-38484668.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
import{r as f,$ as o,j as i}from"./index-f45b8810.js";import{P as s,T as u}from"./fetch.client-5aab1c76.js";var d=["color","size","title"];function c(){return c=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var l=arguments[n];for(var t in l)Object.prototype.hasOwnProperty.call(l,t)&&(e[t]=l[t])}return e},c.apply(this,arguments)}function x(e,n){if(e==null)return{};var l=b(e,n),t,r;if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],!(n.indexOf(t)>=0)&&Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}function b(e,n){if(e==null)return{};var l={},t=Object.keys(e),r,a;for(a=0;a<t.length;a++)r=t[a],!(n.indexOf(r)>=0)&&(l[r]=e[r]);return l}var m=f.forwardRef(function(e,n){var l=e.color,t=e.size,r=e.title,a=x(e,d);return o.createElement("svg",c({ref:n,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 16 16",width:t,height:t,fill:l},a),r?o.createElement("title",null,r):null,o.createElement("path",{d:"M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"}))});m.propTypes={color:s.string,size:s.oneOfType([s.string,s.number]),title:s.string};m.defaultProps={color:"currentColor",size:"1em",title:null};const g=m,h=u("flex flex-col p-2 px-4 text-black rounded-md shadow border",{variants:{type:{warning:"bg-orange-400 border-orange-500/80",error:"bg-red-400 border-red-500/80",success:"bg-green-400 border-green-500/80"}}});function j(e){return i.jsxs("div",{role:"alert",className:h({className:e.className,type:e.type}),children:[e.title?i.jsxs("header",{className:"flex items-center gap-2 mb-2",children:[i.jsx(g,{}),i.jsx("h5",{className:"font-semibold text-lg",children:e.title})]}):null,e.message?i.jsxs("div",{className:"flex items-center gap-2",children:[e.title?null:i.jsx(g,{}),i.jsx("p",{children:e.message})]}):null,e.children]})}export{j as A};
|
1
resources/[sna]/sna-sync/nui/fetch.client-5aab1c76.js
Normal file
1
resources/[sna]/sna-sync/nui/index-093e64e9.css
Normal file
61
resources/[sna]/sna-sync/nui/index-f45b8810.js
Normal file
1
resources/[sna]/sna-sync/nui/index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Assistant:wght@200;300;400;500;600;700;800" rel="stylesheet"><script type="module" crossorigin src="./index-f45b8810.js"></script><link rel="stylesheet" href="./index-093e64e9.css"></head><body class="antialiased dark text-white"><div id="root" class="h-screen w-screen flex justify-center items-center overflow-hidden"></div><div id="notification-portal" class="fixed inset-5 gap-y-2 top-[56px] flex flex-col items-end pointer-events-none z-[999]"></div></body></html>
|
1
resources/[sna]/sna-sync/nui/label-979d47e9.js
Normal file
24852
resources/[sna]/sna-sync/server/server.js
Normal file
2
resources/[ss]/ss-garage/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
80
resources/[ss]/ss-garage/README.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<h1>About Us</h1>
|
||||||
|
We're a team with experience in FiveM and UI development, we've played FiveM for thousands of hours, and have a clear understanding of the players needs. That caused us to start Simplified Studios.
|
||||||
|
|
||||||
|
[Simplified Studios Discord](https://discord.gg/KucTZ2nvET) is where you can find all of our updates, new scripts and maybe some sneak peaks if you're lucky!
|
||||||
|
|
||||||
|
[Simplified Studios Tebex](https://simplified-studios.tebex.io/) is where you can buy our paid scripts!
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
This script is really just plug n play, unless you want to use the Renewed Phone, then you need to follow the instructions below.
|
||||||
|
If you want pictures on the garages, you need to take pictures rename them as they are called in the config and put them into the html/img folder.
|
||||||
|
|
||||||
|
# Use of Renewed Phone
|
||||||
|
|
||||||
|
if you're using the default qb-phone you dont need to do anything, just plug n play.
|
||||||
|
if you're using Renewed Phone, you need to navigate to server/garage.lua and replace the current Callback "qb-phone:server:GetGarageVehicles" with this:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
QBCore.Functions.CreateCallback('qb-phone:server:GetGarageVehicles', function(source, cb)
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local Vehicles = {}
|
||||||
|
local vehdata
|
||||||
|
local result = exports.oxmysql:executeSync('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid})
|
||||||
|
local garages = exports['ss-garage']:GetGarages()
|
||||||
|
if result[1] then
|
||||||
|
for _, v in pairs(result) do
|
||||||
|
local VehicleData = QBCore.Shared.Vehicles[v.vehicle]
|
||||||
|
local VehicleGarage = "None"
|
||||||
|
local enginePercent = round(v.engine / 10, 0)
|
||||||
|
local bodyPercent = round(v.body / 10, 0)
|
||||||
|
if v.garage then
|
||||||
|
if garages[v.garage] then
|
||||||
|
VehicleGarage = garages[v.garage]["label"]
|
||||||
|
else
|
||||||
|
VehicleGarage = v.garage
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local VehicleState = "In"
|
||||||
|
if v.state == 0 then
|
||||||
|
VehicleState = "Out"
|
||||||
|
elseif v.state == 2 then
|
||||||
|
VehicleState = "Impounded"
|
||||||
|
end
|
||||||
|
|
||||||
|
if VehicleData["brand"] then
|
||||||
|
vehdata = {
|
||||||
|
fullname = VehicleData["brand"] .. " " .. VehicleData["name"],
|
||||||
|
brand = VehicleData["brand"],
|
||||||
|
model = VehicleData["name"],
|
||||||
|
plate = v.plate,
|
||||||
|
garage = VehicleGarage,
|
||||||
|
state = VehicleState,
|
||||||
|
fuel = v.fuel,
|
||||||
|
engine = enginePercent,
|
||||||
|
body = bodyPercent,
|
||||||
|
paymentsleft = v.paymentsleft
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vehdata = {
|
||||||
|
fullname = VehicleData["name"],
|
||||||
|
brand = VehicleData["name"],
|
||||||
|
model = VehicleData["name"],
|
||||||
|
plate = v.plate,
|
||||||
|
garage = VehicleGarage,
|
||||||
|
state = VehicleState,
|
||||||
|
fuel = v.fuel,
|
||||||
|
engine = enginePercent,
|
||||||
|
body = bodyPercent,
|
||||||
|
paymentsleft = v.paymentsleft
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Vehicles[#Vehicles+1] = vehdata
|
||||||
|
end
|
||||||
|
cb(Vehicles)
|
||||||
|
else
|
||||||
|
cb(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
```
|
313
resources/[ss]/ss-garage/client/cl_functions.lua
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
local garageZones = {}
|
||||||
|
|
||||||
|
function GetSpawnPoint(garage)
|
||||||
|
local location = nil
|
||||||
|
for k,v in pairs(Config.Garages[garage].spawnPoint) do
|
||||||
|
local isOccupied = IsPositionOccupied( v.x, v.y, v.z, 5.0, false, true, false, false, false, 0, false )
|
||||||
|
if not isOccupied then
|
||||||
|
location = v
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not location then
|
||||||
|
QBCore.Functions.Notify(Lang:t('error.vehicle_occupied'), 'error')
|
||||||
|
end
|
||||||
|
return location
|
||||||
|
end
|
||||||
|
|
||||||
|
function doCarDamage(currentVehicle, stats, props)
|
||||||
|
local engine = stats.engine + 0.0
|
||||||
|
local body = stats.body + 0.0
|
||||||
|
SetVehicleEngineHealth(currentVehicle, engine)
|
||||||
|
SetVehicleBodyHealth(currentVehicle, body)
|
||||||
|
if not next(props) then return end
|
||||||
|
if props.doorStatus then
|
||||||
|
for k, v in pairs(props.doorStatus) do
|
||||||
|
if v then SetVehicleDoorBroken(currentVehicle, tonumber(k), true) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if props.tireBurstState then
|
||||||
|
for k, v in pairs(props.tireBurstState) do
|
||||||
|
if v then SetVehicleTyreBurst(currentVehicle, tonumber(k), true) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Buggy, så slået fra.
|
||||||
|
-- if props.windowStatus then
|
||||||
|
-- for k, v in pairs(props.windowStatus) do
|
||||||
|
-- if not v then SmashVehicleWindow(currentVehicle, tonumber(k)) end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function CreateBlips(setloc)
|
||||||
|
local Garage = AddBlipForCoord(setloc.takeVehicle.x, setloc.takeVehicle.y, setloc.takeVehicle.z)
|
||||||
|
SetBlipSprite(Garage, setloc.blipNumber)
|
||||||
|
SetBlipDisplay(Garage, 4)
|
||||||
|
SetBlipScale(Garage, 0.60)
|
||||||
|
SetBlipAsShortRange(Garage, true)
|
||||||
|
SetBlipColour(Garage, setloc.blipColor)
|
||||||
|
BeginTextCommandSetBlipName('STRING')
|
||||||
|
AddTextComponentSubstringPlayerName(setloc.blipName)
|
||||||
|
EndTextCommandSetBlipName(Garage)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckPlayers(vehicle)
|
||||||
|
for i = -1, 5, 1 do
|
||||||
|
local seat = GetPedInVehicleSeat(vehicle, i)
|
||||||
|
if seat then
|
||||||
|
TaskLeaveVehicle(seat, vehicle, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Wait(1500)
|
||||||
|
QBCore.Functions.DeleteVehicle(vehicle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IsVehicleAllowed(classList, vehicle)
|
||||||
|
for _, class in ipairs(classList) do
|
||||||
|
if GetVehicleClass(vehicle) == class then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function DepositVehicle(veh, data)
|
||||||
|
local plate = QBCore.Functions.GetPlate(veh)
|
||||||
|
QBCore.Functions.TriggerCallback('qb-garages:server:canDeposit', function(canDeposit)
|
||||||
|
if canDeposit then
|
||||||
|
local bodyDamage = math.ceil(GetVehicleBodyHealth(veh))
|
||||||
|
local engineDamage = math.ceil(GetVehicleEngineHealth(veh))
|
||||||
|
local totalFuel = exports[Config.FuelSystem]:GetFuel(veh)
|
||||||
|
TriggerServerEvent('qb-mechanicjob:server:SaveVehicleProps', QBCore.Functions.GetVehicleProperties(veh))
|
||||||
|
TriggerServerEvent('qb-garages:server:updateVehicleStats', plate, totalFuel, engineDamage, bodyDamage)
|
||||||
|
CheckPlayers(veh)
|
||||||
|
if plate then TriggerServerEvent('qb-garages:server:UpdateOutsideVehicle', plate, nil) end
|
||||||
|
QBCore.Functions.Notify(Lang:t('success.vehicle_parked'), 'success', 4500)
|
||||||
|
else
|
||||||
|
QBCore.Functions.Notify(Lang:t('error.not_owned'), 'error', 3500)
|
||||||
|
end
|
||||||
|
end, plate, data.type, data.indexgarage, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreateZone(index, garage, zoneType)
|
||||||
|
local zone = CircleZone:Create(garage.takeVehicle, 10.0, {
|
||||||
|
name = zoneType .. '_' .. index,
|
||||||
|
debugPoly = false,
|
||||||
|
data = {
|
||||||
|
indexgarage = index,
|
||||||
|
type = garage.type,
|
||||||
|
category = garage.category
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return zone
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreateBlipsZones()
|
||||||
|
PlayerData = QBCore.Functions.GetPlayerData()
|
||||||
|
PlayerGang = PlayerData.gang
|
||||||
|
PlayerJob = PlayerData.job
|
||||||
|
|
||||||
|
for index, garage in pairs(Config.Garages) do
|
||||||
|
local zone
|
||||||
|
if garage.showBlip then
|
||||||
|
CreateBlips(garage)
|
||||||
|
end
|
||||||
|
if garage.type == 'job' and (PlayerJob.name == garage.job or PlayerJob.type == garage.jobType) then
|
||||||
|
zone = CreateZone(index, garage, 'job')
|
||||||
|
elseif garage.type == 'gang' and PlayerGang.name == garage.job then
|
||||||
|
zone = CreateZone(index, garage, 'gang')
|
||||||
|
elseif garage.type == 'depot' then
|
||||||
|
zone = CreateZone(index, garage, 'depot')
|
||||||
|
elseif garage.type == 'public' then
|
||||||
|
zone = CreateZone(index, garage, 'public')
|
||||||
|
end
|
||||||
|
|
||||||
|
if zone then
|
||||||
|
garageZones[#garageZones + 1] = zone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local comboZone = ComboZone:Create(garageZones, { name = 'garageCombo', debugPoly = false })
|
||||||
|
|
||||||
|
comboZone:onPlayerInOut(function(isPointInside, _, zone)
|
||||||
|
if isPointInside then
|
||||||
|
listenForKey = true
|
||||||
|
currentZone = zone
|
||||||
|
CreateThread(function()
|
||||||
|
while listenForKey do
|
||||||
|
Wait(0)
|
||||||
|
if IsControlJustReleased(0, 38) then
|
||||||
|
if GetVehiclePedIsUsing(PlayerPedId()) ~= 0 then
|
||||||
|
if zone.data.type == 'depot' then return end
|
||||||
|
local currentVehicle = GetVehiclePedIsUsing(PlayerPedId())
|
||||||
|
if not IsVehicleAllowed(zone.data.category, currentVehicle) then
|
||||||
|
QBCore.Functions.Notify(Lang:t('error.not_correct_type'), 'error', 3500)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
DepositVehicle(currentVehicle, zone.data)
|
||||||
|
else
|
||||||
|
TriggerEvent('ss-garage:client:openGarage')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local displayText = Lang:t('info.car_e')
|
||||||
|
if zone.data.vehicle == 'sea' then
|
||||||
|
displayText = Lang:t('info.sea_e')
|
||||||
|
elseif zone.data.vehicle == 'air' then
|
||||||
|
displayText = Lang:t('info.air_e')
|
||||||
|
elseif zone.data.vehicle == 'rig' then
|
||||||
|
displayText = Lang:t('info.rig_e')
|
||||||
|
elseif zone.data.type == 'depot' then
|
||||||
|
displayText = Lang:t('info.depot_e')
|
||||||
|
end
|
||||||
|
exports['qb-core']:DrawText(displayText, 'top')
|
||||||
|
else
|
||||||
|
listenForKey = false
|
||||||
|
currentZone = nil
|
||||||
|
exports['qb-core']:HideText()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local houseGarageZones = {}
|
||||||
|
local listenForKeyHouse = false
|
||||||
|
local houseComboZones = nil
|
||||||
|
|
||||||
|
function CreateHouseZone(index, garage, zoneType)
|
||||||
|
local houseZone = CircleZone:Create(garage.takeVehicle, 5.0, {
|
||||||
|
name = zoneType .. '_' .. index,
|
||||||
|
debugPoly = false,
|
||||||
|
data = {
|
||||||
|
indexgarage = index,
|
||||||
|
type = zoneType,
|
||||||
|
label = garage.label
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if houseZone then
|
||||||
|
houseGarageZones[#houseGarageZones + 1] = houseZone
|
||||||
|
|
||||||
|
if not houseComboZones then
|
||||||
|
houseComboZones = ComboZone:Create(houseGarageZones, { name = 'houseComboZones', debugPoly = false })
|
||||||
|
else
|
||||||
|
houseComboZones:AddZone(houseZone)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
houseComboZones:onPlayerInOut(function(isPointInside, _, zone)
|
||||||
|
if isPointInside then
|
||||||
|
listenForKeyHouse = true
|
||||||
|
currentZone = zone
|
||||||
|
CreateThread(function()
|
||||||
|
while listenForKeyHouse do
|
||||||
|
Wait(0)
|
||||||
|
if IsControlJustReleased(0, 38) then
|
||||||
|
if GetVehiclePedIsUsing(PlayerPedId()) ~= 0 then
|
||||||
|
local currentVehicle = GetVehiclePedIsUsing(PlayerPedId())
|
||||||
|
DepositVehicle(currentVehicle, zone.data)
|
||||||
|
else
|
||||||
|
TriggerEvent('ss-garage:client:openGarage')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
exports['qb-core']:DrawText(Lang:t('info.house_garage'), 'top')
|
||||||
|
else
|
||||||
|
listenForKeyHouse = false
|
||||||
|
currentZone = nil
|
||||||
|
exports['qb-core']:HideText()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ZoneExists(zoneName)
|
||||||
|
for _, zone in ipairs(houseGarageZones) do
|
||||||
|
if zone.name == zoneName then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function RemoveHouseZone(zoneName)
|
||||||
|
local removedZone = houseComboZones:RemoveZone(zoneName)
|
||||||
|
if removedZone then
|
||||||
|
removedZone:destroy()
|
||||||
|
end
|
||||||
|
for index, zone in ipairs(houseGarageZones) do
|
||||||
|
if zone.name == zoneName then
|
||||||
|
table.remove(houseGarageZones, index)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:client:setHouseGarage', function(house, hasKey) -- event sent periodically from housing
|
||||||
|
if not house then return end
|
||||||
|
local formattedHouseName = string.lower(house)
|
||||||
|
local zoneName = 'house_' .. formattedHouseName
|
||||||
|
if Config.Garages[formattedHouseName] then
|
||||||
|
if hasKey and not ZoneExists(zoneName) then
|
||||||
|
CreateHouseZone(formattedHouseName, Config.Garages[formattedHouseName], 'house')
|
||||||
|
elseif not hasKey and ZoneExists(zoneName) then
|
||||||
|
RemoveHouseZone(zoneName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
TriggerServerEvent('ss-garage:server:setHouseGarages', Config.Garages)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:client:houseGarageConfig', function(houseGarages)
|
||||||
|
for _, garageConfig in pairs(houseGarages) do
|
||||||
|
local formattedHouseName = _
|
||||||
|
if garageConfig.takeVehicle and garageConfig.takeVehicle.x and garageConfig.takeVehicle.y and garageConfig.takeVehicle.z and garageConfig.takeVehicle.w then
|
||||||
|
Config.Garages[formattedHouseName] = {
|
||||||
|
takeVehicle = vector3(garageConfig.takeVehicle.x, garageConfig.takeVehicle.y, garageConfig.takeVehicle.z),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(garageConfig.takeVehicle.x, garageConfig.takeVehicle.y, garageConfig.takeVehicle.z, garageConfig.takeVehicle.w)
|
||||||
|
},
|
||||||
|
label = garageConfig.label,
|
||||||
|
type = 'house',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
TriggerServerEvent('ss-garage:server:setHouseGarages', Config.Garages)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:client:addHouseGarage', function(house, garageInfo) -- event from housing on garage creation
|
||||||
|
local formattedHouseName = string.lower(house)
|
||||||
|
Config.Garages[formattedHouseName] = {
|
||||||
|
takeVehicle = vector3(garageInfo.takeVehicle.x, garageInfo.takeVehicle.y, garageInfo.takeVehicle.z),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(garageInfo.takeVehicle.x, garageInfo.takeVehicle.y, garageInfo.takeVehicle.z, garageInfo.takeVehicle.w)
|
||||||
|
},
|
||||||
|
label = garageInfo.label,
|
||||||
|
type = 'house',
|
||||||
|
}
|
||||||
|
TriggerServerEvent('ss-garage:server:setHouseGarages', Config.Garages)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:client:removeHouseGarage', function(house)
|
||||||
|
Config.Garages[house] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Handlers
|
||||||
|
|
||||||
|
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
|
||||||
|
CreateBlipsZones()
|
||||||
|
end)
|
||||||
|
|
||||||
|
AddEventHandler('onResourceStart', function(res)
|
||||||
|
if res ~= GetCurrentResourceName() then return end
|
||||||
|
CreateBlipsZones()
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('QBCore:Client:OnGangUpdate', function(gang)
|
||||||
|
PlayerGang = gang
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(job)
|
||||||
|
PlayerJob = job
|
||||||
|
end)
|
65
resources/[ss]/ss-garage/client/cl_main.lua
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-garage:client:openGarage', function()
|
||||||
|
QBCore.Functions.TriggerCallback('ss-garage:server:GetVehicles', function(vehicles)
|
||||||
|
if not vehicles then QBCore.Functions.Notify('Du har ingen køretøjer i denne garage.', 'error') return end
|
||||||
|
SendNUIMessage({
|
||||||
|
type = "open",
|
||||||
|
vehicles = vehicles,
|
||||||
|
garages = Config.Garages,
|
||||||
|
garageindex = currentZone.data.indexgarage,
|
||||||
|
})
|
||||||
|
SetNuiFocus(true, true)
|
||||||
|
end, currentZone.data.indexgarage, currentZone.data.type, currentZone.data.category)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('takeOut', function(data, cb)
|
||||||
|
local dataveh = data.vehicle
|
||||||
|
local location = GetSpawnPoint(currentZone.data.indexgarage)
|
||||||
|
if not location then return end
|
||||||
|
|
||||||
|
if dataveh.depotprice ~= 0 then
|
||||||
|
local Player = QBCore.Functions.GetPlayerData()
|
||||||
|
local cash = Player.money["cash"]
|
||||||
|
local bank = Player.money["bank"]
|
||||||
|
|
||||||
|
if cash >= dataveh.depotprice then
|
||||||
|
Player.Functions.RemoveMoney("cash", dataveh.depotprice)
|
||||||
|
QBCore.Functions.Notify('Du betalte gebyret kontant', 'success', 4500)
|
||||||
|
elseif bank >= dataveh.depotprice then
|
||||||
|
Player.Functions.RemoveMoney("bank", dataveh.depotprice)
|
||||||
|
QBCore.Functions.Notify('Gebyret blev betalt gennem banken!', 'success', 4500)
|
||||||
|
else
|
||||||
|
QBCore.Functions.Notify('Du har ikke råd...', 'error', 3500)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
QBCore.Functions.TriggerCallback('ss-garage:server:SpawnVehicle', function(success, netid, properties, plate, fuel, engine, body)
|
||||||
|
while not NetworkDoesNetworkIdExist(netid) do Wait(10) end
|
||||||
|
local veh = NetworkGetEntityFromNetworkId(netid)
|
||||||
|
QBCore.Functions.SetVehicleProperties(veh, properties)
|
||||||
|
exports[Config.FuelSystem]:SetFuel(veh, fuel)
|
||||||
|
doCarDamage(veh, {engine = engine, fuel = fuel, body = body}, properties)
|
||||||
|
TriggerEvent('vehiclekeys:client:SetOwner', plate)
|
||||||
|
end, dataveh.plate, dataveh.spawn, location)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('transfer', function(data, cb)
|
||||||
|
TriggerServerEvent('ss-garage:server:TransferVehicle', data)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('swap', function(data, cb)
|
||||||
|
TriggerServerEvent('ss-garage:server:SwapVehicle', data)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('close', function(data, cb)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
610
resources/[ss]/ss-garage/config.lua
Normal file
@ -0,0 +1,610 @@
|
|||||||
|
Config = {}
|
||||||
|
Config.realisticGarage = true -- If true, people can only take out vehicles the place they parked them.
|
||||||
|
Config.ShouldTeleport = true -- If true, people will be teleported to the vehicle when they take it out.
|
||||||
|
Config.FuelSystem = 'qb-fuel'
|
||||||
|
Config.VehicleClass = {
|
||||||
|
all = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 },
|
||||||
|
car = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 18, 22 },
|
||||||
|
air = { 15, 16 },
|
||||||
|
sea = { 14 },
|
||||||
|
rig = { 10, 11, 17, 19, 20 }
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Garages = {
|
||||||
|
motelgarage = {
|
||||||
|
label = 'Motel Garage',
|
||||||
|
takeVehicle = vector3(274.29, -334.15, 44.92),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(265.96, -332.3, 44.51, 250.68),
|
||||||
|
vector4(282.883, -342.1992, 44.2761, 250.8604),
|
||||||
|
vector4(267.5406, -328.8379, 44.2761, 250.7557),
|
||||||
|
vector4(269.149, -325.8365, 44.2763, 67.0302),
|
||||||
|
vector4(269.6346, -322.39, 44.2762, 249.4603),
|
||||||
|
vector4(271.4303, -319.1182, 44.2765, 244.1053),
|
||||||
|
vector4(283.509, -323.7081, 44.2763, 70.6249),
|
||||||
|
vector4(282.0807, -327.1404, 44.2763, 75.4733),
|
||||||
|
vector4(280.4306, -330.3371, 44.2763, 62.2022),
|
||||||
|
vector4(279.1444, -333.3873, 44.2763, 69.1845),
|
||||||
|
vector4(278.8283, -336.8015, 44.2758, 69.7977),
|
||||||
|
vector4(277.2846, -340.1966, 44.2764, 67.612),
|
||||||
|
vector4(294.4673, -346.4664, 44.2763, 69.6834),
|
||||||
|
vector4(295.1735, -342.9712, 44.2762, 68.7405),
|
||||||
|
vector4(296.5222, -339.7621, 44.276, 70.7631),
|
||||||
|
vector4(297.9995, -336.6969, 44.2759, 70.5789),
|
||||||
|
vector4(299.3056, -333.4106, 44.2764, 70.6955),
|
||||||
|
vector4(300.1339, -330.0648, 44.2764, 70.6679),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public', -- public, gang, job, depot
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
casinogarage = {
|
||||||
|
label = 'Kasino Garage',
|
||||||
|
takeVehicle = vector3(883.96, -4.71, 78.76),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(895.39, -4.75, 78.35, 146.85),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
sapcounsel = {
|
||||||
|
label = 'San Andreas Garage',
|
||||||
|
takeVehicle = vector3(-330.01, -780.33, 33.96),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-341.57, -767.45, 33.56, 92.61),
|
||||||
|
vector4(-357.4557, -775.9738, 33.3235, 270.8601),
|
||||||
|
vector4(-356.9517, -770.8321, 33.3236, 89.8937),
|
||||||
|
vector4(-357.679, -767.6159, 33.3235, 270.2125),
|
||||||
|
vector4(-357.679, -767.6159, 33.3235, 270.2125),
|
||||||
|
vector4(-342.1111, -760.3303, 33.3249, 270.4968),
|
||||||
|
vector4(-337.5381, -751.2196, 33.324, 357.0646),
|
||||||
|
vector4(-357.6219, -753.699, 33.324, 270.6099),
|
||||||
|
vector4(-331.7151, -750.8432, 33.3236, 182.1149),
|
||||||
|
vector4(-323.2357, -752.1731, 33.3236, 333.9358),
|
||||||
|
vector4(-317.3772, -754.2914, 33.3236, 158.9068),
|
||||||
|
vector4(-308.8079, -757.314, 33.3236, 337.8231),
|
||||||
|
vector4(-302.6512, -742.9934, 33.3204, 339.1781),
|
||||||
|
vector4(-302.6133, -759.8962, 33.3238, 342.1106),
|
||||||
|
vector4(-296.9796, -744.9661, 33.3198, 340.7576),
|
||||||
|
vector4(-307.0268, -772.5587, 33.3199, 339.7787),
|
||||||
|
vector4(-314.5116, -770.5553, 33.3195, 180.3153),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
spanishave = {
|
||||||
|
label = 'Spanish Ave Garage',
|
||||||
|
takeVehicle = vector3(-1160.86, -741.41, 19.63),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-1145.2, -745.42, 19.26, 108.22)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
caears24 = {
|
||||||
|
label = 'Caears 24 Garage',
|
||||||
|
takeVehicle = vector3(69.84, 12.6, 68.96),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(60.8, 17.54, 68.82, 339.7),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
caears242 = {
|
||||||
|
label = 'Caears 24 Garage',
|
||||||
|
takeVehicle = vector3(-453.7, -786.78, 30.56),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-472.39, -787.71, 30.14, 180.52),
|
||||||
|
vector4(-467.3271, -794.2883, 29.9037, 271.1952),
|
||||||
|
vector4(-460.5847, -797.3, 29.9009, 270.1559),
|
||||||
|
vector4(-457.2117, -780.4339, 29.917, 272.5331),
|
||||||
|
vector4(-457.2724, -774.8185, 29.9175, 92.8342),
|
||||||
|
vector4(-465.1874, -774.9702, 29.9173, 90.0228),
|
||||||
|
vector4(-465.6922, -780.3431, 29.9172, 270.9347),
|
||||||
|
vector4(-477.4666, -787.4562, 29.9184, 271.7519),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
lagunapi = {
|
||||||
|
label = 'Laguna Garage',
|
||||||
|
takeVehicle = vector3(364.37, 297.83, 103.49),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(375.09, 294.66, 102.86, 164.04)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
airportp = {
|
||||||
|
label = 'Lufthavn Garage',
|
||||||
|
takeVehicle = vector3(-773.12, -2033.04, 8.88),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-779.77, -2040.18, 8.47, 315.34)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
beachp = {
|
||||||
|
label = 'Strand Garage',
|
||||||
|
takeVehicle = vector3(-1185.32, -1500.64, 4.38),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-1188.14, -1487.95, 3.97, 124.06)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
themotorhotel = {
|
||||||
|
label = 'The Motor Hotel Garage',
|
||||||
|
takeVehicle = vector3(1137.77, 2663.54, 37.9),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(1127.7, 2647.84, 37.58, 1.41)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
liqourparking = {
|
||||||
|
label = 'Liqour Garage',
|
||||||
|
takeVehicle = vector3(883.99, 3649.67, 32.87),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(898.38, 3649.41, 32.36, 90.75)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
shoreparking = {
|
||||||
|
label = 'Shore Garage',
|
||||||
|
takeVehicle = vector3(1737.03, 3718.88, 34.05),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(1725.4, 3716.78, 34.15, 20.54)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
haanparking = {
|
||||||
|
label = 'Bell Farms Garage',
|
||||||
|
takeVehicle = vector3(76.88, 6397.3, 31.23),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(62.15, 6403.41, 30.81, 211.38)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
dumbogarage = {
|
||||||
|
label = 'Dumbo Private Garage',
|
||||||
|
takeVehicle = vector3(165.75, -3227.2, 5.89),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(168.34, -3236.1, 5.43, 272.05)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
pillboxgarage = {
|
||||||
|
label = 'Pillbox Garage',
|
||||||
|
takeVehicle = vector3(213.2, -796.05, 30.86),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(208.0369,-795.8985,30.3507,249.2093),
|
||||||
|
vector4(210.226, -791.0077, 30.3061, 248.5806),
|
||||||
|
vector4(211.5416, -786.0048, 30.2899, 248.165),
|
||||||
|
vector4(213.4844, -780.8046, 30.2643, 248.5822),
|
||||||
|
vector4(215.5396, -775.9241, 30.2391, 249.4368),
|
||||||
|
vector4(217.0861, -770.852, 30.2283, 249.9718),
|
||||||
|
vector4(219.1092, -765.7935, 30.2166, 249.7753),
|
||||||
|
vector4(216.5972, -801.837, 30.3747, 69.672),
|
||||||
|
vector4(218.286, -796.6944, 30.3539, 68.0749),
|
||||||
|
vector4(220.107, -791.6907, 30.3425, 69.9591),
|
||||||
|
vector4(222.7271, -786.7191, 30.3557, 69.189),
|
||||||
|
vector4(223.9891, -781.738, 30.1123, 67.8247),
|
||||||
|
vector4(225.7642, -776.7175, 30.1225, 69.919),
|
||||||
|
vector4(227.3384, -771.6263, 30.1372, 68.7111),
|
||||||
|
vector4(220.683, -809.4442, 30.0114, 249.1702),
|
||||||
|
vector4(222.1926, -804.1495, 30.0272, 250.0585),
|
||||||
|
vector4(223.7662, -799.1116, 30.0173, 248.7341),
|
||||||
|
vector4(225.7113, -794.1168, 30.023, 250.1617),
|
||||||
|
vector4(227.6714, -789.1185, 30.0382, 249.4263),
|
||||||
|
vector4(229.8159, -784.0559, 30.0515, 249.9496),
|
||||||
|
vector4(231.3116, -778.8309, 30.0669, 251.3097),
|
||||||
|
vector4(233.2657, -773.8463, 30.0939, 248.8269),
|
||||||
|
vector4(234.9788, -800.2876, 29.8276, 68.0544),
|
||||||
|
vector4(236.8822, -795.0956, 29.8564, 68.6202),
|
||||||
|
vector4(238.6287, -790.1068, 29.8856, 69.3068),
|
||||||
|
vector4(240.3504, -785.0618, 29.9364, 68.9169),
|
||||||
|
vector4(242.1495, -779.8129, 29.9797, 67.5336),
|
||||||
|
vector4(243.9969, -774.7357, 30.0432, 69.2771),
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
grapeseedgarage = {
|
||||||
|
label = 'Grapeseed Garage',
|
||||||
|
takeVehicle = vector3(2552.68, 4671.8, 33.95),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(2550.17, 4681.96, 33.81, 17.05)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Garage',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = true,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
depotLot = {
|
||||||
|
label = 'Depot Lot',
|
||||||
|
takeVehicle = vector3(401.76, -1632.57, 29.29),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(396.55, -1643.93, 28.88, 321.91)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Depot Lot',
|
||||||
|
blipNumber = 68,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'depot',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car']
|
||||||
|
},
|
||||||
|
ballas = {
|
||||||
|
label = 'Ballas',
|
||||||
|
takeVehicle = vector3(87.51, -1969.1, 20.75),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(93.78, -1961.73, 20.34, 319.11)
|
||||||
|
},
|
||||||
|
showBlip = false,
|
||||||
|
blipName = 'Ballas',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'gang',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car'], --car, air, sea, rig
|
||||||
|
job = 'ballas',
|
||||||
|
jobType = 'ballas'
|
||||||
|
},
|
||||||
|
families = {
|
||||||
|
label = 'Families',
|
||||||
|
takeVehicle = vector3(-23.89, -1436.03, 30.65),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-25.47, -1445.76, 30.24, 178.5)
|
||||||
|
},
|
||||||
|
showBlip = false,
|
||||||
|
blipName = 'Families',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'gang',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car'], --car, air, sea, rig
|
||||||
|
job = 'families',
|
||||||
|
jobType = 'families'
|
||||||
|
},
|
||||||
|
lostmc = {
|
||||||
|
label = 'Lost MC',
|
||||||
|
takeVehicle = vector3(985.83, -138.14, 73.09),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(977.65, -133.02, 73.34, 59.39)
|
||||||
|
},
|
||||||
|
showBlip = false,
|
||||||
|
blipName = 'Lost MC',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'gang',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car'], --car, air, sea, rig
|
||||||
|
job = 'lostmc',
|
||||||
|
jobType = 'lostmc'
|
||||||
|
},
|
||||||
|
cartel = {
|
||||||
|
label = 'Cartel',
|
||||||
|
takeVehicle = vector3(1411.67, 1117.8, 114.84),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(1403.01, 1118.25, 114.84, 88.69)
|
||||||
|
},
|
||||||
|
showBlip = false,
|
||||||
|
blipName = 'Cartel',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'gang',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car'],
|
||||||
|
job = 'cartel',
|
||||||
|
jobType = 'cartel'
|
||||||
|
},
|
||||||
|
police = {
|
||||||
|
label = 'Police',
|
||||||
|
takeVehicle = vector3(462.83, -1019.52, 28.1),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(446.16, -1025.79, 28.23, 6.59)
|
||||||
|
},
|
||||||
|
showBlip = false,
|
||||||
|
blipName = 'Police',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'job',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['car'], --car, air, sea, rig
|
||||||
|
job = 'police',
|
||||||
|
jobType = 'leo'
|
||||||
|
},
|
||||||
|
intairport = {
|
||||||
|
label = 'Airport Hangar',
|
||||||
|
takeVehicle = vector3(-979.06, -2995.48, 13.95),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-998.37, -2985.01, 13.95, 61.09)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Hangar',
|
||||||
|
blipNumber = 360,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['air']
|
||||||
|
},
|
||||||
|
higginsheli = {
|
||||||
|
label = 'Higgins Helitours',
|
||||||
|
takeVehicle = vector3(-722.15, -1472.79, 5.0),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-745.22, -1468.72, 5.39, 319.84),
|
||||||
|
vector4(-724.36, -1443.61, 5.39, 135.78)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Hangar',
|
||||||
|
blipNumber = 360,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['air']
|
||||||
|
},
|
||||||
|
airsshores = {
|
||||||
|
label = 'Sandy Shores Hangar',
|
||||||
|
takeVehicle = vector3(1737.89, 3288.13, 41.14),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(1742.83, 3266.83, 41.24, 102.64)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Hangar',
|
||||||
|
blipNumber = 360,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['air']
|
||||||
|
},
|
||||||
|
airzancudo = {
|
||||||
|
label = 'Fort Zancudo Hangar',
|
||||||
|
takeVehicle = vector3(-1828.25, 2975.44, 32.81),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-1828.25, 2975.44, 32.81, 57.24)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Hangar',
|
||||||
|
blipNumber = 360,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['air']
|
||||||
|
},
|
||||||
|
airdepot = {
|
||||||
|
label = 'Air Depot',
|
||||||
|
takeVehicle = vector3(-1270.01, -3377.53, 14.33),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-1270.01, -3377.53, 14.33, 329.25)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Air Depot',
|
||||||
|
blipNumber = 359,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'depot',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['air']
|
||||||
|
},
|
||||||
|
lsymc = {
|
||||||
|
label = 'LSYMC Boathouse',
|
||||||
|
takeVehicle = vector3(-785.95, -1497.84, -0.09),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-796.64, -1502.6, -0.09, 111.49)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Bådhus',
|
||||||
|
blipNumber = 356,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['sea']
|
||||||
|
},
|
||||||
|
paleto = {
|
||||||
|
label = 'Paleto Boathouse',
|
||||||
|
takeVehicle = vector3(-278.21, 6638.13, 7.55),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-289.2, 6637.96, 1.01, 45.5)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Bådhus',
|
||||||
|
blipNumber = 356,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['sea']
|
||||||
|
},
|
||||||
|
millars = {
|
||||||
|
label = 'Millars Boathouse',
|
||||||
|
takeVehicle = vector3(1298.56, 4212.42, 33.25),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(1297.82, 4209.61, 30.12, 253.5)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Bådhus',
|
||||||
|
blipNumber = 356,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['sea']
|
||||||
|
},
|
||||||
|
seadepot = {
|
||||||
|
label = 'LSYMC Depot',
|
||||||
|
takeVehicle = vector3(-742.95, -1407.58, 5.5),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-729.77, -1355.49, 1.19, 142.5)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'LSYMC Depot',
|
||||||
|
blipNumber = 356,
|
||||||
|
blipColor = 3,
|
||||||
|
type = 'depot',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['sea']
|
||||||
|
},
|
||||||
|
rigdepot = {
|
||||||
|
label = 'Big Rig Depot',
|
||||||
|
takeVehicle = vector3(2334.42, 3118.62, 48.2),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(2324.57, 3117.79, 48.21, 4.05)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Depot',
|
||||||
|
blipNumber = 68,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'depot',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
dumborigparking = {
|
||||||
|
label = 'Dumbo Big Rig Parking',
|
||||||
|
takeVehicle = vector3(161.23, -3188.73, 5.97),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(167.0, -3203.89, 5.94, 271.27)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Parking',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
popsrigparking = {
|
||||||
|
label = 'Pop\'s Big Rig Parking',
|
||||||
|
takeVehicle = vector3(137.67, 6632.99, 31.67),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(127.69, 6605.84, 31.93, 223.67)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Parking',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
ronsrigparking = {
|
||||||
|
label = 'Ron\'s Big Rig Parking',
|
||||||
|
takeVehicle = vector3(-2529.37, 2342.67, 33.06),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-2521.61, 2326.45, 33.13, 88.7)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Parking',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
ronsrigparking2 = {
|
||||||
|
label = 'Ron\'s Big Rig Parking',
|
||||||
|
takeVehicle = vector3(2561.67, 476.68, 108.49),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(2561.67, 476.68, 108.49, 177.86)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Parking',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
ronsrigparking3 = {
|
||||||
|
label = 'Ron\'s Big Rig Parking',
|
||||||
|
takeVehicle = vector3(-41.24, -2550.63, 6.01),
|
||||||
|
spawnPoint = {
|
||||||
|
vector4(-39.39, -2527.81, 6.08, 326.18)
|
||||||
|
},
|
||||||
|
showBlip = true,
|
||||||
|
blipName = 'Big Rig Parking',
|
||||||
|
blipNumber = 357,
|
||||||
|
blipColor = 2,
|
||||||
|
type = 'public',
|
||||||
|
canTransfer = false,
|
||||||
|
category = Config.VehicleClass['rig']
|
||||||
|
},
|
||||||
|
}
|
35
resources/[ss]/ss-garage/fxmanifest.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
fx_version 'cerulean'
|
||||||
|
game 'gta5'
|
||||||
|
lua54 'yes'
|
||||||
|
description 'Simplified Studios Garage'
|
||||||
|
version '1.2.0'
|
||||||
|
|
||||||
|
ui_page 'html/index.html'
|
||||||
|
|
||||||
|
shared_scripts {
|
||||||
|
'@qb-core/shared/locale.lua',
|
||||||
|
'locales/en.lua',
|
||||||
|
'locales/*.lua',
|
||||||
|
'config.lua',
|
||||||
|
}
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
'@PolyZone/client.lua',
|
||||||
|
'@PolyZone/CircleZone.lua',
|
||||||
|
'@PolyZone/ComboZone.lua',
|
||||||
|
'client/cl_functions.lua',
|
||||||
|
'client/cl_main.lua',
|
||||||
|
}
|
||||||
|
|
||||||
|
server_scripts {
|
||||||
|
'server/sv_main.lua',
|
||||||
|
'server/sv_functions.lua',
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
'html/img/*.png',
|
||||||
|
'html/img/*.jpg',
|
||||||
|
'html/index.html',
|
||||||
|
'html/style.css',
|
||||||
|
'html/script.js',
|
||||||
|
}
|
BIN
resources/[ss]/ss-garage/html/img/caears24.png
Normal file
After Width: | Height: | Size: 330 KiB |
BIN
resources/[ss]/ss-garage/html/img/default.png
Normal file
After Width: | Height: | Size: 592 KiB |
BIN
resources/[ss]/ss-garage/html/img/motelgarage.png
Normal file
After Width: | Height: | Size: 367 KiB |
BIN
resources/[ss]/ss-garage/html/img/pillboxgarage.png
Normal file
After Width: | Height: | Size: 362 KiB |
BIN
resources/[ss]/ss-garage/html/img/sapcounsel.png
Normal file
After Width: | Height: | Size: 326 KiB |
54
resources/[ss]/ss-garage/html/index.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-...your-integrity-hash-here..." crossorigin="anonymous" />
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||||
|
|
||||||
|
<script src="../config.js" defer></script>
|
||||||
|
<script src="script.js" defer></script>
|
||||||
|
<title>Simplified Studios</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="garage-container" style="display: none;">
|
||||||
|
<div class="mx-auto w-[600px] overflow-hidden rounded-lg h-[51rem] bg-slate-900 mb-10">
|
||||||
|
<img id="garageimage" src="./img/legionsquare.png" class="h-[125px] aspect-video w-full object-cover opacity-50" alt="" />
|
||||||
|
<div class="p-4">
|
||||||
|
<a class="text-xl font-medium text-gray-300">Garage</a>
|
||||||
|
<p class="text-xs font-medium text-gray-500">Viser i øjeblikekt garagen på <span id="garagelabel">Legion Square</span></p>
|
||||||
|
<div class="text-sm text-gray-600 h-[595px] overflow-y-scroll overflow-hidden list-none bg-slate-800 bg-opacity-50 px-4 py-3.5 mt-5 rounded-md">
|
||||||
|
<div class="vehicle-container space-y-2">
|
||||||
|
<!-- Vehicles go here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- popup (swap garage) -->
|
||||||
|
<div class="swap-container mx-auto w-[600px] overflow-hidden rounded-lg px-2 bg-slate-900 mb-10" style="display: none;">
|
||||||
|
<div class="p-4">
|
||||||
|
<a class="text-xl font-medium text-gray-300">Skift Garage</a>
|
||||||
|
<p class="text-xs font-medium text-gray-500">Vælg hvilken garage du vil flytte bilen til</p>
|
||||||
|
<select id="garageSelect" data-te-select-init class="mt-6 h-8 w-full bg-slate-800 text-white border border-slate-700 outline-none rounded-[5px] disabled:cursor-not-allowed disabled:bg-gray-50 option:hover">
|
||||||
|
<!-- Options will be dynamically added here using jQuery -->
|
||||||
|
</select>
|
||||||
|
<button id="confirm-swap" type="button" class="mt-5 ml-[435px] rounded-md border-gray-700 bg-slate-700 px-2.5 py-1.5 text-center text-sm font-medium text-white transition-all hover:bg-green-300 hover:text-green-800 disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300">Bekræft handling</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- popup (transfer vehicle) -->
|
||||||
|
<div class="transfer-container mx-auto w-[600px] overflow-hidden rounded-lg px-2 bg-slate-900 mb-10" style="display: none;">
|
||||||
|
<div class="p-4">
|
||||||
|
<a class="text-xl font-medium text-gray-300">Skift ejerskab</a>
|
||||||
|
<p class="text-xs font-medium text-gray-500">Skriv navnet på spilleren du vil give bilen til</p>
|
||||||
|
<input type="text" id="transfervehicle" placeholder=" Type in the ID of the wanted player" class="mt-6 h-8 w-full bg-slate-800 text-white border border-slate-700 outline-none rounded-[5px] disabled:cursor-not-allowed disabled:bg-gray-50 option:hover"></input>
|
||||||
|
<button id="confirm-transfer" type="button" class="mt-5 ml-[435px] rounded-md border-gray-700 bg-slate-700 px-2.5 py-1.5 text-center text-sm font-medium text-white transition-all hover:bg-green-300 hover:text-green-800 disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300">Bekræft handling</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
144
resources/[ss]/ss-garage/html/script.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
let currentVehicle = null;
|
||||||
|
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (event.data.type == 'open') {
|
||||||
|
$('.garage-container').css('display', 'block')
|
||||||
|
$('.vehicle-container').html('');
|
||||||
|
currentVehicle = null;
|
||||||
|
var vehicles = event.data.vehicles;
|
||||||
|
var garages = event.data.garages;
|
||||||
|
|
||||||
|
var garageImage = $('#garageimage');
|
||||||
|
var garageImageURL = `img/${event.data.garageindex}.png`;
|
||||||
|
garageImage.attr('src', garageImageURL);
|
||||||
|
garageImage.on('error', function() {
|
||||||
|
garageImage.attr('src', 'img/default.png');
|
||||||
|
garageImage.off('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#garagelabel').text(event.data.garages[event.data.garageindex].label);
|
||||||
|
|
||||||
|
vehicles.forEach(function(vehicle, index) {
|
||||||
|
var vehicleHtml = `
|
||||||
|
<details class="group rounded-lg open:bg-slate-800">
|
||||||
|
<summary class="flex cursor-pointer list-none items-center justify-between bg-slate-800 rounded-lg px-3 py-2 text-[15px] font-medium text-white hover:bg-slate-800">
|
||||||
|
<summary class="flex">
|
||||||
|
<a class="mr-2 rounded-md bg-green-300 text-xs font-medium tracking-wide px-[5px] py-[2px] text-green-800">${vehicle.plate}</a>
|
||||||
|
<carname class="text-ellipsis line-clamp-1">${vehicle.fullname}</carname>
|
||||||
|
</summary>
|
||||||
|
<div class="text-secondary-500">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="block h-5 w-5 group-open:hidden">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="hidden h-5 w-5 group-open:block">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<div class="px-6 pb-4 text-xs text-white">
|
||||||
|
${vehicle.state === 0 ?
|
||||||
|
'<br><a class="ml-2 rounded-md bg-rose-400 text-xs font-medium tracking-wide px-[5px] py-[2px] text-stone-800">Ude</a>' :
|
||||||
|
vehicle.state === 1 ?
|
||||||
|
`<br><a class="rounded-md bg-slate-600 text-xs font-medium tracking-wide px-[5px] py-[2px] text-white">${event.data.garages[event.data.garageindex].label}</a>` :
|
||||||
|
vehicle.state === 2 ?
|
||||||
|
`<br><a class="ml-2 rounded-md bg-rose-400 text-xs font-medium tracking-wide px-[5px] py-[2px] text-stone-800">Impounded - Gebyr: ${formatNumber(vehicle.impoundPrice)},-</a>` :
|
||||||
|
''
|
||||||
|
}
|
||||||
|
<p class="mt-5 text-[15px] font-bold">Køretøj Status</p>
|
||||||
|
<div class="space-y-1">
|
||||||
|
<dl class="flex items-center justify-between">
|
||||||
|
<dt class="mt-1 text-sm font-medium text-secondary-700">Brændstof</dt>
|
||||||
|
<dd class="text-sm text-secondary-500">${vehicle.fuel}%</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="relative flex h-2 w-full overflow-hidden rounded-full bg-slate-700">
|
||||||
|
<div role="progressbar" aria-valuenow="${vehicle.fuel}" aria-valuemin="0" aria-valuemax="100" style="width: ${vehicle.fuel}%" class="flex h-full items-center justify-center bg-orange-300 text-white"></div>
|
||||||
|
</div>
|
||||||
|
<dl class="flex items-center justify-between">
|
||||||
|
<dt class="mt-1 text-sm font-medium text-secondary-700">Motor</dt>
|
||||||
|
<dd class="text-sm text-secondary-500">${vehicle.engine / 10}%</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="relative flex h-2 w-full overflow-hidden rounded-full bg-slate-700">
|
||||||
|
<div role="progressbar" aria-valuenow="${vehicle.engine / 10}" aria-valuemin="0" aria-valuemax="100" style="width: ${vehicle.engine / 10}%" class="flex h-full items-center justify-center bg-blue-300 text-white"></div>
|
||||||
|
</div>
|
||||||
|
<dl class="flex items-center justify-between">
|
||||||
|
<dt class="mt-1 text-sm font-medium text-secondary-700">Karrosseri</dt>
|
||||||
|
<dd class="text-sm text-secondary-500">${vehicle.body / 10}%</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="relative flex h-2 w-full overflow-hidden rounded-full bg-slate-700">
|
||||||
|
<div role="progressbar" aria-valuenow="${vehicle.body / 10}" aria-valuemin="0" aria-valuemax="100" style="width: ${vehicle.body / 10}%" class="flex h-full items-center justify-center bg-green-300 text-white"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="drive-${index}" class="mt-5 rounded-md border-gray-700 bg-slate-700 px-2.5 py-1.5 text-center text-sm font-medium text-white transition-all hover:bg-green-300 hover:text-green-800 disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300">Kør</button>
|
||||||
|
<button type="button" id="transfer-${index}" class="ml-2 rounded-md border-gray-700 bg-slate-700 px-2.5 py-1.5 text-center text-sm font-medium text-white transition-all hover:bg-green-300 hover:text-green-800 disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300">Skift ejer</button>
|
||||||
|
`;
|
||||||
|
$('.vehicle-container').append(vehicleHtml);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Denne knap er fjernet, for at undgå at folk kan skifte garage, uden at have køretøjet med sig, eller flytte til en garage de ikke burde kunne flytte den til:
|
||||||
|
|
||||||
|
<button type="button" id="swap-${index}" class="ml-2 rounded-md border-gray-700 bg-slate-700 px-2.5 py-1.5 text-center text-sm font-medium text-white transition-all hover:bg-green-300 hover:text-green-disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300">Swap Garages</button>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(`#drive-${index}`).on('click', function(event) {
|
||||||
|
driveVehicle(vehicle);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(`#swap-${index}`).on('click', function(event) {
|
||||||
|
currentVehicle = vehicle;
|
||||||
|
$('.garage-container').css('display', 'none')
|
||||||
|
$.each(garages, function (index, value) {
|
||||||
|
if (value.label && value.canTransfer) {
|
||||||
|
$("#garageSelect").append('<option value="' + (index) + '">' + value.label + '</option>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.swap-container').css('display', 'block')
|
||||||
|
});
|
||||||
|
|
||||||
|
$(`#transfer-${index}`).on('click', function(event) {
|
||||||
|
$('.garage-container').css('display', 'none')
|
||||||
|
currentVehicle = vehicle;
|
||||||
|
$('.transfer-container').css('display', 'block')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#confirm-transfer").click(function () {
|
||||||
|
let id = $("#transfervehicle").val();
|
||||||
|
$.post(`https://${GetParentResourceName()}/transfer`, JSON.stringify({
|
||||||
|
vehicle: currentVehicle,
|
||||||
|
id: id
|
||||||
|
}));
|
||||||
|
close()
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#confirm-swap").click(function () {
|
||||||
|
let garage = $("#garageSelect").val();
|
||||||
|
$.post(`https://${GetParentResourceName()}/swap`, JSON.stringify({
|
||||||
|
vehicle: currentVehicle,
|
||||||
|
garage: garage
|
||||||
|
}));
|
||||||
|
close()
|
||||||
|
});
|
||||||
|
|
||||||
|
function driveVehicle(vehicle) {
|
||||||
|
$('.garage-container').css('display', 'none')
|
||||||
|
$.post(`https://${GetParentResourceName()}/takeOut`, JSON.stringify({
|
||||||
|
vehicle: vehicle
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
document.onkeyup = function (data) {
|
||||||
|
if (data.which == 27) {
|
||||||
|
close()
|
||||||
|
$.post(`https://${GetParentResourceName()}/close`, JSON.stringify({}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
$('.garage-container').css('display', 'none')
|
||||||
|
$('.swap-container').css('display', 'none')
|
||||||
|
$('.transfer-container').css('display', 'none')
|
||||||
|
$('#garageSelect').empty();
|
||||||
|
}
|
64
resources/[ss]/ss-garage/html/style.css
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
.((((((((((((((((((((((
|
||||||
|
.((((((((((((((((((((((((((((((((*
|
||||||
|
((((((((((((((((((((((((((((((((((((((((
|
||||||
|
.(((((((((((((((((( *((((((((((((((((((
|
||||||
|
(((((((((((((( (((((((((((((((
|
||||||
|
((((((((((( /(((((((((((
|
||||||
|
((((((((((( (((((((((((
|
||||||
|
((((((((((( (((((((((((
|
||||||
|
((((((((((( (((((((((((
|
||||||
|
(((((((((((((/ (((((((((((
|
||||||
|
(((((((((((((((((((((* *((((((
|
||||||
|
(((((((((((((((((((((((((((((,
|
||||||
|
/((((((((((((((((((((((((((((((((((((,
|
||||||
|
,((((((((((((((((((((((((((((((((((((*
|
||||||
|
(((((((((((((((((((((((((((((((
|
||||||
|
(((((. /((((((((((((((((((((((
|
||||||
|
((((((((((( ,((((((((((((((
|
||||||
|
((((((((((( ((, (((((((((((
|
||||||
|
((((((((((( (((((((((( (((((((((((
|
||||||
|
((((((((((( (((((((((( (((((((((((
|
||||||
|
((((((((((( (((((((((( (((((((((((
|
||||||
|
((((((((((( (((((((((( (((((((((((
|
||||||
|
((((((((((( (((( (((((((((((
|
||||||
|
((((((((((( ((((((((((((
|
||||||
|
(((((((((((((( ((((((((((((((
|
||||||
|
((((((((((((((( .((((((((((((((/
|
||||||
|
((((((((((((((( (((((((((((((((
|
||||||
|
.((((((((((((((( (((((((((((((((
|
||||||
|
((((((((((((((( ,(((((((((((((((
|
||||||
|
(((((((((((((((((((((((((((
|
||||||
|
,((((((((((((((((((((((
|
||||||
|
((((((((((((((((((
|
||||||
|
(((((((((((((.
|
||||||
|
*((((((((
|
||||||
|
((((
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Don't touch */
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 2px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-container, .transfer-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
39
resources/[ss]/ss-garage/locales/ar.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'لا يوجد مركبات في هذا المكان!',
|
||||||
|
not_depot = 'مركبتك ليست في المستودع',
|
||||||
|
not_owned = 'لا يمكن تخزين هذه المركبة',
|
||||||
|
not_correct_type = 'لا يمكنك تخزين هذا النوع من المركبات هنا',
|
||||||
|
not_enough = 'لا يوجد مال كافي',
|
||||||
|
no_garage = 'لا شيء',
|
||||||
|
vehicle_occupied = 'لا يمكنك تخزين هذه المركبة لأنها ليست فارغة',
|
||||||
|
vehicle_not_tracked = 'تعذر تعقب المركبة',
|
||||||
|
no_spawn = 'المنطقة مزدحمة جدًا'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'تم تخزين المركبة',
|
||||||
|
vehicle_tracked = 'تم تعقب المركبة',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'خارج',
|
||||||
|
garaged = 'تم التخزين',
|
||||||
|
impound = 'مصادرة من قبل الشرطة',
|
||||||
|
house = 'منزل',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - المرآب',
|
||||||
|
sea_e = 'E - مرفأ القوارب',
|
||||||
|
air_e = 'E - الجناح',
|
||||||
|
rig_e = 'E - موقف الحفر',
|
||||||
|
depot_e = 'E - المستودع',
|
||||||
|
house_garage = 'E - مرآب المنزل',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'ar' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/da.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Der er ingen køretøjer på denne placering!',
|
||||||
|
not_depot = 'Dit køretøj er ikke i depotet',
|
||||||
|
not_owned = 'Dette køretøj kan ikke opbevares',
|
||||||
|
not_correct_type = 'Du kan ikke opbevare denne type køretøj her',
|
||||||
|
not_enough = 'Ikke nok penge',
|
||||||
|
no_garage = 'Ingen',
|
||||||
|
vehicle_occupied = 'Du kan ikke opbevare dette køretøj, da det ikke er tomt',
|
||||||
|
vehicle_not_tracked = 'Kunne ikke spore køretøjet',
|
||||||
|
no_spawn = 'Området er for overfyldt'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Køretøj opbevaret',
|
||||||
|
vehicle_tracked = 'Køretøj sporet',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Ude',
|
||||||
|
garaged = 'I garagen',
|
||||||
|
impound = 'Beslaglagt af politiet',
|
||||||
|
house = 'Hus',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Bådhus',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Rig Parkeringsplads',
|
||||||
|
depot_e = 'E - Depot',
|
||||||
|
house_garage = 'E - Husgarage',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'da' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/de.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Es gibt keine Fahrzeuge an diesem Ort!',
|
||||||
|
not_depot = 'Ihr Fahrzeug befindet sich nicht im Depot',
|
||||||
|
not_owned = 'Dieses Fahrzeug kann nicht eingelagert werden',
|
||||||
|
not_correct_type = 'Sie können diesen Fahrzeugtyp hier nicht abstellen',
|
||||||
|
not_enough = 'Nicht genug Geld',
|
||||||
|
no_garage = 'Keine',
|
||||||
|
vehicle_occupied = 'Sie können dieses Fahrzeug nicht einlagern, da es nicht leer ist',
|
||||||
|
vehicle_not_tracked = 'Fahrzeug konnte nicht verfolgt werden',
|
||||||
|
no_spawn = 'Bereich zu überfüllt'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Fahrzeug eingelagert',
|
||||||
|
vehicle_tracked = 'Fahrzeug verfolgt',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Draußen',
|
||||||
|
garaged = 'In der Garage',
|
||||||
|
impound = 'Von der Polizei beschlagnahmt',
|
||||||
|
house = 'Haus',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Bootshaus',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Rig Parkplatz',
|
||||||
|
depot_e = 'E - Depot',
|
||||||
|
house_garage = 'E - Hausgarage',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'de' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
36
resources/[ss]/ss-garage/locales/en.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'There are no vehicles in this location!',
|
||||||
|
not_depot = 'Your vehicle is not in depot',
|
||||||
|
not_owned = 'This vehicle can\'t be stored',
|
||||||
|
not_correct_type = 'You can\'t store this type of vehicle here',
|
||||||
|
not_enough = 'Not enough money',
|
||||||
|
no_garage = 'None',
|
||||||
|
vehicle_occupied = 'You can\'t store this vehicle as it is not empty',
|
||||||
|
vehicle_not_tracked = 'Could not track vehicle',
|
||||||
|
no_spawn = 'Area too crowded'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Vehicle Stored',
|
||||||
|
vehicle_tracked = 'Vehicle Tracked',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Out',
|
||||||
|
garaged = 'Garaged',
|
||||||
|
impound = 'Impounded By Police',
|
||||||
|
house = 'House',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Boathouse',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Rig Lot',
|
||||||
|
depot_e = 'E - Depot',
|
||||||
|
house_garage = 'E - House Garage',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lang = Lang or Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true
|
||||||
|
})
|
39
resources/[ss]/ss-garage/locales/es.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = '¡No hay vehículos en esta ubicación!',
|
||||||
|
not_depot = 'Tu vehículo no está en el depósito',
|
||||||
|
not_owned = 'Este vehículo no puede ser almacenado',
|
||||||
|
not_correct_type = 'No puedes guardar este tipo de vehículo aquí',
|
||||||
|
not_enough = 'No hay suficiente dinero',
|
||||||
|
no_garage = 'Ninguno',
|
||||||
|
vehicle_occupied = 'No puedes guardar este vehículo ya que no está vacío',
|
||||||
|
vehicle_not_tracked = 'No se pudo rastrear el vehículo',
|
||||||
|
no_spawn = 'Área demasiado concurrida'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Vehículo Almacenado',
|
||||||
|
vehicle_tracked = 'Vehículo Rastreado',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Fuera',
|
||||||
|
garaged = 'En el garaje',
|
||||||
|
impound = 'Embargado por la policía',
|
||||||
|
house = 'Casa',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garaje',
|
||||||
|
sea_e = 'E - Garaje de barcos',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Lote de plataforma',
|
||||||
|
depot_e = 'E - Depósito',
|
||||||
|
house_garage = 'E - Garaje de la casa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'es' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/et.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Selles kohas ei ole sõidukeid!',
|
||||||
|
not_depot = 'Teie sõiduk ei ole depoos',
|
||||||
|
not_owned = 'Seda sõidukit ei saa hoida',
|
||||||
|
not_correct_type = 'Te ei saa seda tüüpi sõidukit siia hoida',
|
||||||
|
not_enough = 'Piisavalt raha pole',
|
||||||
|
no_garage = 'Puudub',
|
||||||
|
vehicle_occupied = 'Te ei saa seda sõidukit hoida, kuna see pole tühi',
|
||||||
|
vehicle_not_tracked = 'Sõidukit ei õnnestunud jälgida',
|
||||||
|
no_spawn = 'Ala on liiga rahvarohke'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Sõiduk on salvestatud',
|
||||||
|
vehicle_tracked = 'Sõiduk on jälgitud',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Väljas',
|
||||||
|
garaged = 'Garaažis',
|
||||||
|
impound = 'Politsei poolt konfiskeeritud',
|
||||||
|
house = 'Maja',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garaaž',
|
||||||
|
sea_e = 'E - Paadimaja',
|
||||||
|
air_e = 'E - Hangaar',
|
||||||
|
rig_e = 'E - Puurplatvormi parkimiskoht',
|
||||||
|
depot_e = 'E - Depoo',
|
||||||
|
house_garage = 'E - Maja garaaž',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'et' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/fa.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'ترددی در این مکان وجود ندارد!',
|
||||||
|
not_depot = 'وسیلهٔ شما در دیپو نیست',
|
||||||
|
not_owned = 'نمیتوانید این وسیله را ذخیره کنید',
|
||||||
|
not_correct_type = 'نمیتوانید این نوع وسیله را در اینجا ذخیره کنید',
|
||||||
|
not_enough = 'موجودی کافی نیست',
|
||||||
|
no_garage = 'ندارد',
|
||||||
|
vehicle_occupied = 'نمیتوانید این وسیله را ذخیره کنید چون پر است',
|
||||||
|
vehicle_not_tracked = 'وسیله را نمیتوان پیگیری کرد',
|
||||||
|
no_spawn = 'محل بسیار شلوغ است'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'وسیله ذخیره شد',
|
||||||
|
vehicle_tracked = 'وسیله پیگیری شد',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'خارج',
|
||||||
|
garaged = 'در گاراژ',
|
||||||
|
impound = 'توسط پلیس ضبط شده',
|
||||||
|
house = 'خانه',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - گاراژ',
|
||||||
|
sea_e = 'E - کشتیگیری',
|
||||||
|
air_e = 'E - هانگار',
|
||||||
|
rig_e = 'E - محل پارک پلتفرم حفاری',
|
||||||
|
depot_e = 'E - دیپو',
|
||||||
|
house_garage = 'E - گاراژ خانه',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'fa' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/fi.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Tässä sijainnissa ei ole ajoneuvoja!',
|
||||||
|
not_depot = 'Ajoneuvosi ei ole varikolla',
|
||||||
|
not_owned = 'Tätä ajoneuvoa ei voi säilyttää',
|
||||||
|
not_correct_type = 'Tätä ajoneuvotyyppiä ei voi säilyttää täällä',
|
||||||
|
not_enough = 'Ei tarpeeksi rahaa',
|
||||||
|
no_garage = 'Ei yhtään',
|
||||||
|
vehicle_occupied = 'Et voi säilyttää tätä ajoneuvoa, koska se ei ole tyhjä',
|
||||||
|
vehicle_not_tracked = 'Ajoneuvoa ei voitu jäljittää',
|
||||||
|
no_spawn = 'Alue on liian täynnä'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Ajoneuvo tallennettu',
|
||||||
|
vehicle_tracked = 'Ajoneuvo jäljitetty',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Ulkona',
|
||||||
|
garaged = 'Tallissa',
|
||||||
|
impound = 'Poliisin takavarikoima',
|
||||||
|
house = 'Talo',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Autotalli',
|
||||||
|
sea_e = 'E - Venevaja',
|
||||||
|
air_e = 'E - Lentokonehalli',
|
||||||
|
rig_e = 'E - Porapaikka',
|
||||||
|
depot_e = 'E - Varikko',
|
||||||
|
house_garage = 'E - Talon autotalli',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'fi' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/fr.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Il n\'y a pas de véhicules à cet endroit !',
|
||||||
|
not_depot = 'Votre véhicule n\'est pas au dépôt',
|
||||||
|
not_owned = 'Ce véhicule ne peut pas être stocké',
|
||||||
|
not_correct_type = 'Vous ne pouvez pas stocker ce type de véhicule ici',
|
||||||
|
not_enough = 'Pas assez d\'argent',
|
||||||
|
no_garage = 'Aucun',
|
||||||
|
vehicle_occupied = 'Vous ne pouvez pas stocker ce véhicule car il n\'est pas vide',
|
||||||
|
vehicle_not_tracked = 'Impossible de suivre le véhicule',
|
||||||
|
no_spawn = 'Zone trop encombrée'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Véhicule stocké',
|
||||||
|
vehicle_tracked = 'Véhicule suivi',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Dehors',
|
||||||
|
garaged = 'Dans le garage',
|
||||||
|
impound = 'Saisi par la police',
|
||||||
|
house = 'Maison',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Hangar à bateaux',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Emplacement de la plateforme de forage',
|
||||||
|
depot_e = 'E - Dépôt',
|
||||||
|
house_garage = 'E - Garage de maison',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'fr' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/ge.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'ამ ადგილზე არ გააქვს წარმოებული ტრანსპორტი!',
|
||||||
|
not_depot = 'თქვენი ტრანსპორტი არ არის დეპოში',
|
||||||
|
not_owned = 'ამ ტრანსპორტს ვერ შეინახავთ',
|
||||||
|
not_correct_type = 'ამ ტიპის ტრანსპორტი აქ არ შეიძლება შეინახოთ',
|
||||||
|
not_enough = 'არ არის საკმარისი თანხა',
|
||||||
|
no_garage = 'არ არის',
|
||||||
|
vehicle_occupied = 'ამ ტრანსპორტს შეუძლებელია შეინახოთ, რადგან ის ცარიელი არ არის',
|
||||||
|
vehicle_not_tracked = 'ტრანსპორტი ვერ იყო თვალის წინ',
|
||||||
|
no_spawn = 'არეული ზონაში ძალა არ არის'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'ტრანსპორტი შენახულია',
|
||||||
|
vehicle_tracked = 'ტრანსპორტი თვალის წინ',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'გარეთ',
|
||||||
|
garaged = 'გარეჯი',
|
||||||
|
impound = 'დაკონფისკირებული პოლიციის მიერ',
|
||||||
|
house = 'სახლი',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - გარეჟი',
|
||||||
|
sea_e = 'E - საზღვაო ბუნები',
|
||||||
|
air_e = 'E - ჰანგარი',
|
||||||
|
rig_e = 'E - ფლევარის პარკინგი',
|
||||||
|
depot_e = 'E - დეპო',
|
||||||
|
house_garage = 'E - სახლის გარეჟი',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'ge' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/it.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Non ci sono veicoli in questa posizione!',
|
||||||
|
not_depot = 'Il tuo veicolo non è in deposito',
|
||||||
|
not_owned = 'Questo veicolo non può essere depositato',
|
||||||
|
not_correct_type = 'Non puoi depositare questo tipo di veicolo qui',
|
||||||
|
not_enough = 'Soldi insufficienti',
|
||||||
|
no_garage = 'Nessuno',
|
||||||
|
vehicle_occupied = 'Non puoi depositare questo veicolo perché non è vuoto',
|
||||||
|
vehicle_not_tracked = 'Impossibile tracciare il veicolo',
|
||||||
|
no_spawn = 'Area troppo affollata'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Veicolo depositato',
|
||||||
|
vehicle_tracked = 'Veicolo tracciato',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Fuori',
|
||||||
|
garaged = 'In garage',
|
||||||
|
impound = 'Sequestrato dalla polizia',
|
||||||
|
house = 'Casa',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Rimessaggio barche',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Piazzale',
|
||||||
|
depot_e = 'E - Deposito',
|
||||||
|
house_garage = 'E - Garage di casa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'it' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/nl.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Er zijn geen voertuigen op deze locatie!',
|
||||||
|
not_depot = 'Uw voertuig bevindt zich niet in het depot',
|
||||||
|
not_owned = 'Dit voertuig kan niet worden opgeslagen',
|
||||||
|
not_correct_type = 'Je kunt dit type voertuig hier niet opslaan',
|
||||||
|
not_enough = 'Niet genoeg geld',
|
||||||
|
no_garage = 'Geen',
|
||||||
|
vehicle_occupied = 'Je kunt dit voertuig niet opslaan omdat het niet leeg is',
|
||||||
|
vehicle_not_tracked = 'Kon voertuig niet volgen',
|
||||||
|
no_spawn = 'Gebied te druk'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Voertuig opgeslagen',
|
||||||
|
vehicle_tracked = 'Voertuig gevolgd',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Uit',
|
||||||
|
garaged = 'In de garage',
|
||||||
|
impound = 'In beslag genomen door de politie',
|
||||||
|
house = 'Huis',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Boothuis',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Rig Lot',
|
||||||
|
depot_e = 'E - Depot',
|
||||||
|
house_garage = 'E - Huis garage',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'nl' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/pt-br.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Não há veículos neste local!',
|
||||||
|
not_depot = 'Seu veículo não está no depósito',
|
||||||
|
not_owned = 'Este veículo não pode ser armazenado',
|
||||||
|
not_correct_type = 'Você não pode armazenar este tipo de veículo aqui',
|
||||||
|
not_enough = 'Dinheiro insuficiente',
|
||||||
|
no_garage = 'Nenhum',
|
||||||
|
vehicle_occupied = 'Você não pode armazenar este veículo, pois ele não está vazio',
|
||||||
|
vehicle_not_tracked = 'Não foi possível rastrear o veículo',
|
||||||
|
no_spawn = 'Área muito lotada'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Veículo armazenado',
|
||||||
|
vehicle_tracked = 'Veículo rastreado',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Fora',
|
||||||
|
garaged = 'Na garagem',
|
||||||
|
impound = 'Apreendido pela polícia',
|
||||||
|
house = 'Casa',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garagem',
|
||||||
|
sea_e = 'E - Hangar de barco',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Local de plataforma de perfuração',
|
||||||
|
depot_e = 'E - Depósito',
|
||||||
|
house_garage = 'E - Garagem de casa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'pt-br' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/pt.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Não existem veículos nesta localização!',
|
||||||
|
not_depot = 'O seu veículo não está no depósito',
|
||||||
|
not_owned = 'Este veículo não pode ser armazenado',
|
||||||
|
not_correct_type = 'Não pode armazenar este tipo de veículo aqui',
|
||||||
|
not_enough = 'Dinheiro insuficiente',
|
||||||
|
no_garage = 'Nenhum',
|
||||||
|
vehicle_occupied = 'Não pode armazenar este veículo, pois não está vazio',
|
||||||
|
vehicle_not_tracked = 'Não foi possível localizar o veículo',
|
||||||
|
no_spawn = 'Área demasiado congestionada'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Veículo armazenado',
|
||||||
|
vehicle_tracked = 'Veículo localizado',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Fora',
|
||||||
|
garaged = 'Na garagem',
|
||||||
|
impound = 'Apreendido pela polícia',
|
||||||
|
house = 'Casa',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garagem',
|
||||||
|
sea_e = 'E - Garagem para barcos',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Local de plataforma',
|
||||||
|
depot_e = 'E - Depósito',
|
||||||
|
house_garage = 'E - Garagem da casa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'pt' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/ro.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Nu există vehicule în această locație!',
|
||||||
|
not_depot = 'Vehiculul dvs. nu este în depozit',
|
||||||
|
not_owned = 'Acest vehicul nu poate fi stocat',
|
||||||
|
not_correct_type = 'Nu puteți stoca acest tip de vehicul aici',
|
||||||
|
not_enough = 'Nu aveți suficientă bani',
|
||||||
|
no_garage = 'Niciunul',
|
||||||
|
vehicle_occupied = 'Nu puteți stoca acest vehicul deoarece nu este gol',
|
||||||
|
vehicle_not_tracked = 'Nu s-a putut urmări vehiculul',
|
||||||
|
no_spawn = 'Zona este prea aglomerată'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Vehiculul a fost depozitat',
|
||||||
|
vehicle_tracked = 'Vehiculul a fost urmărit',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Ieșit',
|
||||||
|
garaged = 'În garaj',
|
||||||
|
impound = 'Confiscat de poliție',
|
||||||
|
house = 'Casa',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garaj',
|
||||||
|
sea_e = 'E - Hangar pentru bărci',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Locul platformei de foraj',
|
||||||
|
depot_e = 'E - Depozit',
|
||||||
|
house_garage = 'E - Garaj de casă',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'ro' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/sk.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'V tomto mieste nie sú žiadne vozidlá!',
|
||||||
|
not_depot = 'Vaše vozidlo nie je v depo',
|
||||||
|
not_owned = 'Toto vozidlo nie je možné uložiť',
|
||||||
|
not_correct_type = 'Tento druh vozidla nemôžete uložiť sem',
|
||||||
|
not_enough = 'Nedostatok peňazí',
|
||||||
|
no_garage = 'Žiadny',
|
||||||
|
vehicle_occupied = 'Toto vozidlo nemôžete uložiť, pretože nie je prázdne',
|
||||||
|
vehicle_not_tracked = 'Vozidlo sa nedá sledovať',
|
||||||
|
no_spawn = 'Príliš preplnené miesto'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Vozidlo uložené',
|
||||||
|
vehicle_tracked = 'Vozidlo sledované',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Vonku',
|
||||||
|
garaged = 'V garáži',
|
||||||
|
impound = 'Zabavené políciou',
|
||||||
|
house = 'Dům',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garáž',
|
||||||
|
sea_e = 'E - Lodný hangár',
|
||||||
|
air_e = 'E - Letecký hangár',
|
||||||
|
rig_e = 'E - Parkovisko pre vrtnú plošinu',
|
||||||
|
depot_e = 'E - Depo',
|
||||||
|
house_garage = 'E - Garáž domu',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'sk' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/sv.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Det finns inga fordon på den här platsen!',
|
||||||
|
not_depot = 'Ditt fordon är inte i depån',
|
||||||
|
not_owned = 'Det går inte att lagra detta fordon',
|
||||||
|
not_correct_type = 'Du kan inte lagra den här typen av fordon här',
|
||||||
|
not_enough = 'Inte tillräckligt med pengar',
|
||||||
|
no_garage = 'Inget',
|
||||||
|
vehicle_occupied = 'Du kan inte lagra detta fordon eftersom det inte är tomt',
|
||||||
|
vehicle_not_tracked = 'Det gick inte att spåra fordonet',
|
||||||
|
no_spawn = 'Området är för trångt'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Fordon lagrat',
|
||||||
|
vehicle_tracked = 'Fordon spårat',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Ute',
|
||||||
|
garaged = 'I garaget',
|
||||||
|
impound = 'Beslagtaget av polisen',
|
||||||
|
house = 'Hus',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garage',
|
||||||
|
sea_e = 'E - Båthus',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Plats för borrigg',
|
||||||
|
depot_e = 'E - Depå',
|
||||||
|
house_garage = 'E - Husgarage',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'sv' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
39
resources/[ss]/ss-garage/locales/tr.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local Translations = {
|
||||||
|
error = {
|
||||||
|
no_vehicles = 'Bu konumda araç yok!',
|
||||||
|
not_depot = 'Araç depoda değil',
|
||||||
|
not_owned = 'Bu araç depolanamaz',
|
||||||
|
not_correct_type = 'Bu tür bir aracı buraya depolayamazsınız',
|
||||||
|
not_enough = 'Yeterli para yok',
|
||||||
|
no_garage = 'Hiç yok',
|
||||||
|
vehicle_occupied = 'Bu aracı boş olmadığı için depolayamazsınız',
|
||||||
|
vehicle_not_tracked = 'Araç izlenemedi',
|
||||||
|
no_spawn = 'Bölge çok kalabalık'
|
||||||
|
},
|
||||||
|
success = {
|
||||||
|
vehicle_parked = 'Araç depolandı',
|
||||||
|
vehicle_tracked = 'Araç izlendi',
|
||||||
|
},
|
||||||
|
status = {
|
||||||
|
out = 'Dışarıda',
|
||||||
|
garaged = 'Garajda',
|
||||||
|
impound = 'Polis tarafından alıkonuldu',
|
||||||
|
house = 'Ev',
|
||||||
|
},
|
||||||
|
info = {
|
||||||
|
car_e = 'E - Garaj',
|
||||||
|
sea_e = 'E - Tekne garajı',
|
||||||
|
air_e = 'E - Hangar',
|
||||||
|
rig_e = 'E - Sondaj platformu yeri',
|
||||||
|
depot_e = 'E - Depo',
|
||||||
|
house_garage = 'E - Ev garajı',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetConvar('qb_locale', 'en') == 'tr' then
|
||||||
|
Lang = Locale:new({
|
||||||
|
phrases = Translations,
|
||||||
|
warnOnMissing = true,
|
||||||
|
fallbackLang = Lang,
|
||||||
|
})
|
||||||
|
end
|
53
resources/[ss]/ss-garage/server/sv_functions.lua
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
|
||||||
|
function FormatVehicles(result)
|
||||||
|
local Vehicles = {}
|
||||||
|
for _, v in pairs(result) do
|
||||||
|
local VehicleData = QBCore.Shared.Vehicles[v.vehicle]
|
||||||
|
|
||||||
|
local VehicleGarage = Lang:t('error.no_garage')
|
||||||
|
if v.garage ~= nil then
|
||||||
|
if Config.Garages[v.garage] ~= nil then
|
||||||
|
VehicleGarage = Config.Garages[v.garage].label
|
||||||
|
else
|
||||||
|
VehicleGarage = Lang:t('info.house')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local stateTranslation
|
||||||
|
if v.state == 0 then
|
||||||
|
stateTranslation = Lang:t('status.out')
|
||||||
|
elseif v.state == 1 then
|
||||||
|
stateTranslation = Lang:t('status.garaged')
|
||||||
|
elseif v.state == 2 then
|
||||||
|
stateTranslation = Lang:t('status.impound')
|
||||||
|
end
|
||||||
|
|
||||||
|
local fullname
|
||||||
|
if VehicleData and VehicleData['brand'] then
|
||||||
|
fullname = VehicleData['brand'] .. ' ' .. VehicleData['name']
|
||||||
|
else
|
||||||
|
fullname = VehicleData and VehicleData['name'] or 'Ukendt køretøj'
|
||||||
|
end
|
||||||
|
|
||||||
|
Vehicles[#Vehicles + 1] = {
|
||||||
|
fullname = fullname,
|
||||||
|
brand = VehicleData and VehicleData['brand'] or '',
|
||||||
|
model = VehicleData and VehicleData['name'] or '',
|
||||||
|
spawn = VehicleData['model'],
|
||||||
|
plate = v.plate,
|
||||||
|
garage = VehicleGarage,
|
||||||
|
garageindex = v.garage,
|
||||||
|
state = stateTranslation,
|
||||||
|
fuel = v.fuel,
|
||||||
|
engine = v.engine,
|
||||||
|
body = v.body,
|
||||||
|
depotprice = v.depotprice,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return Vehicles
|
||||||
|
end
|
||||||
|
|
||||||
|
exports('GetGarages', function()
|
||||||
|
return Config.Garages
|
||||||
|
end)
|
144
resources/[ss]/ss-garage/server/sv_main.lua
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
OutsideVehicles = {}
|
||||||
|
|
||||||
|
QBCore.Functions.CreateCallback('ss-garage:server:SpawnVehicle', function(source, cb, plate, model, coords)
|
||||||
|
local player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local vehicle = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND plate = ? AND vehicle = ?', {player.PlayerData.citizenid, plate, model})
|
||||||
|
|
||||||
|
if not vehicle[1] then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du ejer ikke dette køretøj', 'error')
|
||||||
|
cb(false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if vehicle[1].fakeplate ~= nil and string.len(vehicle[1].fakeplate) > 0 then
|
||||||
|
plate = vehicle[1].fakeplate
|
||||||
|
end
|
||||||
|
if OutsideVehicles[plate] and DoesEntityExist(OutsideVehicles[plate].entity) then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Køretøj er allerede ude', 'error')
|
||||||
|
cb(false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local veh = QBCore.Functions.SpawnVehicle(source, model, coords, Config.ShouldTeleport)
|
||||||
|
SetVehicleNumberPlateText(veh, plate)
|
||||||
|
OutsideVehicles[plate] = { netID = NetworkGetNetworkIdFromEntity(veh), entity = veh }
|
||||||
|
exports['oxmysql']:execute('UPDATE player_vehicles SET state = ?, depotprice = ? WHERE (plate = ? OR fakeplate = ?)', { 0, 0, plate, plate })
|
||||||
|
cb(true, NetworkGetNetworkIdFromEntity(veh), json.decode(vehicle[1].mods), plate, vehicle[1].fuel, vehicle[1].engine, vehicle[1].body)
|
||||||
|
end)
|
||||||
|
|
||||||
|
QBCore.Functions.CreateCallback('qb-garages:server:GetPlayerVehicles', function(source, cb)
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local result = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid})
|
||||||
|
|
||||||
|
if result[1] then
|
||||||
|
local vehs = FormatVehicles(result)
|
||||||
|
cb(vehs)
|
||||||
|
else
|
||||||
|
cb(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-garage:server:setHouseGarages', function(data)
|
||||||
|
Config.Garages = data
|
||||||
|
end)
|
||||||
|
|
||||||
|
QBCore.Functions.CreateCallback('qb-garages:server:canDeposit', function(source, cb, plate, type, garage, state)
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local isOwned = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND (plate = ? OR fakeplate = ?)', {Player.PlayerData.citizenid, plate})
|
||||||
|
if not isOwned[1] then
|
||||||
|
cb(false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if type == 'house' and not exports['ps-housing']:IsOwner(source, garage) then
|
||||||
|
cb(false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if state == 1 then
|
||||||
|
exports['oxmysql']:execute('UPDATE player_vehicles SET state = ?, garage = ? WHERE plate = ?', { state, garage, plate })
|
||||||
|
cb(true)
|
||||||
|
else
|
||||||
|
cb(false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
QBCore.Functions.CreateCallback('ss-garage:server:GetVehicles', function(source, cb, garage, type, category)
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local result
|
||||||
|
|
||||||
|
if type == 'depot' then
|
||||||
|
result = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND depotprice > 0', {Player.PlayerData.citizenid})
|
||||||
|
elseif Config.realisticGarage then
|
||||||
|
result = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND garage = ?', {Player.PlayerData.citizenid, garage})
|
||||||
|
else
|
||||||
|
result = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid})
|
||||||
|
end
|
||||||
|
|
||||||
|
if result[1] then
|
||||||
|
local vehs = FormatVehicles(result)
|
||||||
|
cb(vehs)
|
||||||
|
else
|
||||||
|
cb(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:server:updateVehicleStats', function(plate, fuel, engine, body)
|
||||||
|
exports['oxmysql']:execute('UPDATE player_vehicles SET fuel = ?, engine = ?, body = ? WHERE plate = ?', { fuel, engine, body, plate })
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('qb-garages:server:UpdateOutsideVehicle', function(plate, vehicleNetID)
|
||||||
|
OutsideVehicles[plate] = {
|
||||||
|
netID = vehicleNetID,
|
||||||
|
entity = NetworkGetEntityFromNetworkId(vehicleNetID)
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-garage:server:SwapVehicle', function(data)
|
||||||
|
local source = source
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local vehicle = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND plate = ? AND garage = ?', { Player.PlayerData.citizenid, data.vehicle.plate, data.vehicle.garageindex })
|
||||||
|
|
||||||
|
if not Config.Garages[data.garage] then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Garage eksisterer ikke', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not vehicle[1] then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du ejer ikke dette køretøj', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if OutsideVehicles[vehicle[1].plate] and DoesEntityExist(OutsideVehicles[vehicle[1].plate].entity) then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Køretøj er allerede ude', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du rykkede dit køretøj til '..data.garage, 'success')
|
||||||
|
exports['oxmysql']:execute('UPDATE player_vehicles SET garage = ? WHERE plate = ?', { data.garage, data.vehicle.plate })
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-garage:server:TransferVehicle', function(data)
|
||||||
|
local source = source
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
local vehicle = exports['oxmysql']:fetchSync('SELECT * FROM player_vehicles WHERE citizenid = ? AND plate = ? AND garage = ?', { Player.PlayerData.citizenid, data.vehicle.plate, data.vehicle.garageindex })
|
||||||
|
|
||||||
|
if not vehicle[1] then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du ejer ikke dette køretøj', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if OutsideVehicles[vehicle[1].plate] and DoesEntityExist(OutsideVehicles[vehicle[1].plate].entity) then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Dette køretøj er allerede ude', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local target = QBCore.Functions.GetPlayer(tonumber(data.id))
|
||||||
|
|
||||||
|
if not target then
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Spilleren er ikke online', 'error')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, 'Du gav dit køretøj til '..target.PlayerData.charinfo.firstname..' '..target.PlayerData.charinfo.lastname, 'success')
|
||||||
|
TriggerClientEvent('QBCore:Notify', target.PlayerData.source, 'Du modtog et køretøj fra '..Player.PlayerData.charinfo.firstname..' '..Player.PlayerData.charinfo.lastname, 'success')
|
||||||
|
exports['oxmysql']:execute('UPDATE player_vehicles SET citizenid = ?, license = ? WHERE plate = ?', { target.PlayerData.citizenid, target.PlayerData.license, data.vehicle.plate })
|
||||||
|
end)
|
3
resources/[ss]/ss-jobcenter/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Straight up Drag N drop, and then change the jobs to your needs.
|
||||||
|
|
||||||
|
If you need any help, or you wanna check out our other resources. Then join our discord: https://discord.gg/7YHRdV9San Or see our tebex here: https://simplified-studios.tebex.io/
|
95
resources/[ss]/ss-jobcenter/client/cl_main.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
Config = {}
|
||||||
|
|
||||||
|
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
|
||||||
|
TriggerServerEvent('ss-jobcenter:server:setup')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-jobcenter:client:setup', function(cfg)
|
||||||
|
Config = cfg
|
||||||
|
for k, v in pairs(Config.Locations) do
|
||||||
|
RequestModel(v.model)
|
||||||
|
while not HasModelLoaded(v.model) do
|
||||||
|
Wait(10)
|
||||||
|
end
|
||||||
|
local ped = CreatePed(4, v.model, v.coords.x, v.coords.y, v.coords.z-1, v.coords.w, false, true)
|
||||||
|
PlaceObjectOnGroundProperly(ped)
|
||||||
|
SetEntityHeading(ped, v.coords.w)
|
||||||
|
SetEntityInvincible(ped, true)
|
||||||
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
||||||
|
SetModelAsNoLongerNeeded(v.model)
|
||||||
|
FreezeEntityPosition(ped, true)
|
||||||
|
if Config.useTarget then
|
||||||
|
exports['qb-target']:AddTargetEntity(ped, {
|
||||||
|
options = {
|
||||||
|
{
|
||||||
|
type = 'server',
|
||||||
|
event = 'ss-jobcenter:server:openJobCenter',
|
||||||
|
icon = "fas fa-briefcase",
|
||||||
|
label = "Job Center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
distance = 1.5,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
local zones = {}
|
||||||
|
for k,v in pairs(Config.Locations) do
|
||||||
|
local zone = CircleZone:Create(v.coords, 3.0, {
|
||||||
|
name = 'jobcenter_' .. k,
|
||||||
|
debugPoly = false,
|
||||||
|
})
|
||||||
|
zones[#zones + 1] = zone
|
||||||
|
end
|
||||||
|
|
||||||
|
local combo = ComboZone:Create(zones, {
|
||||||
|
name = 'jobcenter_combo',
|
||||||
|
debugPoly = false,
|
||||||
|
})
|
||||||
|
|
||||||
|
combo:onPlayerInOut(function(isPointInside)
|
||||||
|
if isPointInside then
|
||||||
|
exports['qb-core']:DrawText('Åben Job center', 'top')
|
||||||
|
CreateThread(function()
|
||||||
|
while isPointInside do
|
||||||
|
Wait(0)
|
||||||
|
if IsControlJustPressed(0, 38) then
|
||||||
|
TriggerServerEvent('ss-jobcenter:server:openJobCenter')
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
exports['qb-core']:HideText()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local blip = AddBlipForCoord(v.coords.x, v.coords.y, v.coords.z)
|
||||||
|
SetBlipSprite(blip, 407)
|
||||||
|
SetBlipDisplay(blip, 4)
|
||||||
|
SetBlipScale(blip, 0.5)
|
||||||
|
SetBlipColour(blip, 0)
|
||||||
|
SetBlipAsShortRange(blip, true)
|
||||||
|
BeginTextCommandSetBlipName("STRING")
|
||||||
|
AddTextComponentString("Job Center")
|
||||||
|
EndTextCommandSetBlipName(blip)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-jobcenter:client:openJobCenter', function(config)
|
||||||
|
SendNUIMessage({
|
||||||
|
type = 'open',
|
||||||
|
config = config,
|
||||||
|
})
|
||||||
|
SetNuiFocus(true, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('startJob', function(data, cb)
|
||||||
|
TriggerServerEvent('ss-jobcenter:server:startJob', data.rank, data.name)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('close', function(data, cb)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
139
resources/[ss]/ss-jobcenter/config.lua
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
Config = {}
|
||||||
|
|
||||||
|
Config.Main = {
|
||||||
|
useTarget = true,
|
||||||
|
Locations = {
|
||||||
|
["jobcenter"] = {
|
||||||
|
coords = vector4(-269.19, -956.09, 31.22, 206.34),
|
||||||
|
model = "s_m_m_armoured_01",
|
||||||
|
blip = {
|
||||||
|
sprite = 407,
|
||||||
|
color = 4,
|
||||||
|
scale = 0.7,
|
||||||
|
label = "Job Center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Jobs = {
|
||||||
|
{
|
||||||
|
name = "Skraldemand",
|
||||||
|
image = "garbage.jpg",
|
||||||
|
rank = "garbage",
|
||||||
|
description = "Læs mere om jobbet her.",
|
||||||
|
instructions = "En skraldemand, også kendt som en renovationssarbejder, er ansvarlig for at indsamle og bortskaffe kommunalt affald. Deres opgaver inkluderer at køre skraldebiler langs angivne ruter, samle affaldsbeholdere eller poser op og sikre korrekt affaldsbehandling. Skraldemænd spiller en afgørende rolle i opretholdelsen af folkesundhed og sanitetsstandarder inden for samfundet.",
|
||||||
|
paidActions = {
|
||||||
|
"Affaldsindsamling",
|
||||||
|
"Ruteeffektivitet",
|
||||||
|
"Specialiseret affaldshåndtering",
|
||||||
|
"Overarbejde",
|
||||||
|
"Offentlig interaktion"
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Ensom", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Taxichauffør",
|
||||||
|
image = "taxi.jpg",
|
||||||
|
rank = "taxi",
|
||||||
|
description = "Læs mere om jobbet her.",
|
||||||
|
instructions = "En taxichauffør leverer transporttjenester på efterspørgsel til passagerer inden for et bestemt geografisk område. Ansvarsområder inkluderer at samle passagerer op, navigere effektivt til destinationer og behandle takster. Taxichauffører arbejder ofte selvstændigt eller for taxaselskaber og tjener indkomst gennem en kombination af takster og drikkepenge.",
|
||||||
|
paidActions = {
|
||||||
|
"Transport af passagerer",
|
||||||
|
"Ventetid",
|
||||||
|
"Yderligere services",
|
||||||
|
"Spidslastakster",
|
||||||
|
"Drikkepenge"
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Ensom", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Gartner",
|
||||||
|
image = "garderner.png",
|
||||||
|
rank = "gardener",
|
||||||
|
description = "Læs mere om jobbet her.",
|
||||||
|
instructions = "En gartner får grønne fingre. Ansvarlig for at vedligeholde og pleje grønne områder, herunder græsplæner, haver og parker. Deres opgaver inkluderer græsslåning, beskæring, plantning og fjernelse af ukrudt. Gartnere kan arbejde for private husholdninger, virksomheder eller det offentlige.",
|
||||||
|
paidActions = {
|
||||||
|
"Græsslåning",
|
||||||
|
"Beskæring",
|
||||||
|
"Ukrudtsbekæmpelse",
|
||||||
|
"Plantning",
|
||||||
|
"Vedligeholdelse af grønne områder"
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Kommission" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Lastbilchauffør",
|
||||||
|
image = "trucking.png",
|
||||||
|
rank = "trucker",
|
||||||
|
description = "Læs mere om jobbet her.",
|
||||||
|
instructions = "En lastbilchauffør, også kendt som en lastbilchauffør, betjener kommercielle køretøjer til at transportere varer over lange afstande og sikrer rettidig og sikker levering. Ansvarsområder inkluderer navigation af ruter, overholdelse af trafikregler og vedligeholdelse af køretøjet. Lastbilchauffører spiller en afgørende rolle i logistik- og transportindustrien.",
|
||||||
|
paidActions = {
|
||||||
|
"Fragttransport",
|
||||||
|
"Lastning og losning",
|
||||||
|
"Overholdelse af tidsplan",
|
||||||
|
"Betaling for specialiserede færdigheder",
|
||||||
|
"Overarbejdsbetaling"
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Ensom", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Autohjælp",
|
||||||
|
image = "trucking.png",
|
||||||
|
rank = "tow",
|
||||||
|
description = "Læs mere om jobbet her.",
|
||||||
|
instructions = "Autohjælp hjælper med bugsering af køretøjer, uanset om de er i vejen eller ej.",
|
||||||
|
paidActions = {
|
||||||
|
"Nød-bugsering",
|
||||||
|
"Vejhjælp",
|
||||||
|
"Reparationer på stedet",
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Interaktiv", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Nyhedsvært",
|
||||||
|
image = "trucking.png",
|
||||||
|
rank = "reporter",
|
||||||
|
description = "Læs mere om det gennemsnitligt betalte job her.",
|
||||||
|
instructions = "Nyhedsværten er ansvarlig for at rapportere nyheder og begivenheder til offentligheden gennem forskellige medieplatforme. De kan arbejde for aviser, magasiner, websites, fjernsyn eller radio. De kan også være selvstændige og sælge historier til medieudgivelser.",
|
||||||
|
paidActions = {
|
||||||
|
"Rapportering",
|
||||||
|
"Interviews",
|
||||||
|
"Artikler",
|
||||||
|
"Fotografering",
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Middel løn", "Meget interaktiv", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Buschauffør",
|
||||||
|
image = "trucking.png",
|
||||||
|
rank = "bus",
|
||||||
|
description = "Læs mere om et af de lavest betalte job her.",
|
||||||
|
instructions = "Buschaufføren. Ansvarlig for at transportere passagerer langs fastlagte ruter på en rettidig måde. Deres opgaver inkluderer at indsamle billetter, besvare passagerens spørgsmål og overholde tidsplanen. Buschauffører skal også sikre passagerernes sikkerhed.",
|
||||||
|
paidActions = {
|
||||||
|
"Transport af borgere",
|
||||||
|
"Overholdelse af tidsplan",
|
||||||
|
"Overarbejdsbetaling"
|
||||||
|
},
|
||||||
|
tags = { "Kørsel", "Lav løn", "Interaktiv", }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Pølsemand",
|
||||||
|
image = "trucking.png",
|
||||||
|
rank = "hotdog",
|
||||||
|
description = "Læs mere om et af de mest sociale, men lavest betalte job her.",
|
||||||
|
instructions = "Pølsemand! Ansvarlig for at sælge hotdogs til offentligheden, lave sjov og have rigtig god tid!",
|
||||||
|
paidActions = {
|
||||||
|
"Madservice",
|
||||||
|
"Drikkepenge",
|
||||||
|
"Overarbejdsbetaling"
|
||||||
|
},
|
||||||
|
tags = { "Primært stillesiddende", "Lav løn", "Social", }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.tagColors = {
|
||||||
|
"bg-green-300",
|
||||||
|
"bg-rose-400",
|
||||||
|
"bg-orange-200"
|
||||||
|
}
|
29
resources/[ss]/ss-jobcenter/fxmanifest.lua
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
fx_version 'cerulean'
|
||||||
|
game 'gta5'
|
||||||
|
lua54 'yes'
|
||||||
|
description 'Simplified Studios Jobcenter'
|
||||||
|
version '1.2.0'
|
||||||
|
|
||||||
|
ui_page 'html/index.html'
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
'@PolyZone/client.lua',
|
||||||
|
'@PolyZone/BoxZone.lua',
|
||||||
|
'@PolyZone/EntityZone.lua',
|
||||||
|
'@PolyZone/CircleZone.lua',
|
||||||
|
'@PolyZone/ComboZone.lua',
|
||||||
|
'client/cl_main.lua',
|
||||||
|
}
|
||||||
|
|
||||||
|
server_scripts {
|
||||||
|
'config.lua',
|
||||||
|
'server/sv_main.lua',
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
'html/img/*.png',
|
||||||
|
'html/img/*.jpg',
|
||||||
|
'html/index.html',
|
||||||
|
'html/style.css',
|
||||||
|
'html/script.js',
|
||||||
|
}
|
BIN
resources/[ss]/ss-jobcenter/html/img/garbage.jpg
Normal file
After Width: | Height: | Size: 161 KiB |
BIN
resources/[ss]/ss-jobcenter/html/img/garderner.png
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
resources/[ss]/ss-jobcenter/html/img/taxi.jpg
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
resources/[ss]/ss-jobcenter/html/img/trucking.png
Normal file
After Width: | Height: | Size: 2.2 MiB |
35
resources/[ss]/ss-jobcenter/html/index.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-...your-integrity-hash-here..." crossorigin="anonymous" />
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||||
|
|
||||||
|
<script src="../config.js" defer></script>
|
||||||
|
<script src="script.js" defer></script>
|
||||||
|
<title>Simplified Studios</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="dynamicContentContainer">
|
||||||
|
<!-- Jobs here -->
|
||||||
|
</div>
|
||||||
|
<div class="flex absolute bottom-0 mb-5">
|
||||||
|
<a href="#" id="down" class="flex items-center justify-center px-4 h-10 me-3 text-base font-medium text-gray-500 bg-white rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-slate-900 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
|
||||||
|
<svg class="w-3.5 h-3.5 me-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5H1m0 0 4 4M1 5l4-4"/>
|
||||||
|
</svg>
|
||||||
|
Forrige
|
||||||
|
</a>
|
||||||
|
<a href="#" id="up" class="flex items-center justify-center px-4 h-10 text-base font-medium text-gray-500 bg-white rounded-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-slate-900 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
|
||||||
|
Næste
|
||||||
|
<svg class="w-3.5 h-3.5 ms-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
84
resources/[ss]/ss-jobcenter/html/script.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
let currentJob = 0;
|
||||||
|
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (event.data.type == "open") {
|
||||||
|
$('html, body').css('display', 'flex');
|
||||||
|
config = event.data.config;
|
||||||
|
Object.entries(config.Jobs).forEach(([jobKey, job]) => {
|
||||||
|
var dynamicContent = `
|
||||||
|
<div class="mx-auto max-w-md overflow-hidden rounded-lg h-[51rem] bg-slate-900 mb-10" style="display: none" id="job-${jobKey}">
|
||||||
|
<img src="./img/${job.image}" class="aspect-video w-full object-cover opacity-50" alt="" />
|
||||||
|
<div class="p-4">
|
||||||
|
<a class="text-xl font-medium text-gray-300">${job.name}</a>
|
||||||
|
<p class="text-xs font-medium text-gray-500">${job.description}</p>
|
||||||
|
<div class="mx-auto max-w-lg">
|
||||||
|
<ul class="list-disc text-sm text-gray-600 opacity-85 h-40 overflow-hidden list-none bg-slate-800 px-2 py-1.5 mt-5 rounded-md">
|
||||||
|
<h1 class="font-semibold text-gray-300 mb-1 text-base">Job Beskrivelse</h1>
|
||||||
|
<li class="font-medium">${job.instructions}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="mx-auto max-w-lg">
|
||||||
|
<ul class="list-disc text-sm text-green-900 bg-opacity-85 h-[140px] overflow-hidden list-none bg-emerald-200 px-2 py-1.5 mt-5 rounded-md">
|
||||||
|
<h1 class="font-medium text-green-800 mb-1 text-base">Betalte Handlinger</h1>
|
||||||
|
${job.paidActions.map((action) => `<li class="font-medium">${action}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<p class="overflow-hidden mt-5 text-gray-500 font-semibold text-sm">Hvis dette job lyder som noget for dig, kan du klikke på knappen og begynde at arbejde som ${job.name}.</p>
|
||||||
|
<button type="button" class="mt-2 rounded-md border-gray-700 bg-slate-800 px-4 py-2 text-center text-sm font-medium text-white transition-all hover:bg-slate-700 focus:ring focus:ring-gray-200 disabled:cursor-not-allowed disabled:border-gray-300 disabled:bg-gray-300 start-working-button" onclick="startJob(${jobKey})">Start arbejde</button>
|
||||||
|
<div class="mt-4 flex gap-2">
|
||||||
|
${job.tags.map((tag, index) => `<span class="inline-flex items-center gap-1 rounded-md ${config.tagColors[index]} px-2 py-1 text-xs font-bold text-stone-800">${tag}</span>`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
$("#dynamicContentContainer").append(dynamicContent);
|
||||||
|
});
|
||||||
|
showJob(currentJob);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#up").on("click", function (event) {
|
||||||
|
const nextJob = (currentJob + 1) % config.Jobs.length;
|
||||||
|
showJob(nextJob);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#down").on("click", function (event) {
|
||||||
|
const prevJob = (currentJob - 1 + config.Jobs.length) % config.Jobs.length;
|
||||||
|
showJob(prevJob);
|
||||||
|
});
|
||||||
|
|
||||||
|
const showJob = (jobIndex) => {
|
||||||
|
$(`#job-${currentJob}`).css("display", "none");
|
||||||
|
currentJob = jobIndex;
|
||||||
|
$(`#job-${currentJob}`).css("display", "block");
|
||||||
|
|
||||||
|
$("#down").html(`
|
||||||
|
<svg class="w-3.5 h-3.5 me-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5H1m0 0 4 4M1 5l4-4"/>
|
||||||
|
</svg>
|
||||||
|
${config.Jobs[(currentJob - 1 + config.Jobs.length) % config.Jobs.length].name}
|
||||||
|
`);
|
||||||
|
$("#up").html(`
|
||||||
|
${config.Jobs[(currentJob + 1) % config.Jobs.length].name}
|
||||||
|
<svg class="w-3.5 h-3.5 ms-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9"/>
|
||||||
|
</svg>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const startJob = (jobIndex) => {
|
||||||
|
$('html, body').css('display', 'none');
|
||||||
|
$.post(`https://${GetParentResourceName()}/startJob`, JSON.stringify({
|
||||||
|
rank: config.Jobs[jobIndex].rank,
|
||||||
|
name: config.Jobs[jobIndex].name,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onkeyup = function (data) {
|
||||||
|
if (data.which == 27) {
|
||||||
|
$('html, body').css('display', 'none');
|
||||||
|
currentJob = 0;
|
||||||
|
$("#dynamicContentContainer").empty();
|
||||||
|
$.post(`https://${GetParentResourceName()}/close`, JSON.stringify({}));
|
||||||
|
}
|
||||||
|
};
|
18
resources/[ss]/ss-jobcenter/html/style.css
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* Color choices, change here - not further down */
|
||||||
|
:root {
|
||||||
|
--textcolor: #fff;
|
||||||
|
--textsub: #ffffff57;
|
||||||
|
--texthighlight: #33F9B1;
|
||||||
|
--tabscolor: #08070c69;
|
||||||
|
--textred: #f11c51;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't touch */
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
display: none;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
}
|
35
resources/[ss]/ss-jobcenter/server/sv_main.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-jobcenter:server:openJobCenter', function()
|
||||||
|
local source = source
|
||||||
|
TriggerClientEvent('ss-jobcenter:client:openJobCenter', source, Config)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-jobcenter:server:setup', function()
|
||||||
|
TriggerClientEvent('ss-jobcenter:client:setup', source, Config.Main)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent('ss-jobcenter:server:startJob', function(job, name)
|
||||||
|
local source = source
|
||||||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||||||
|
|
||||||
|
local jobExists = false
|
||||||
|
for k, v in pairs(Config.Jobs) do
|
||||||
|
if v.rank == job then
|
||||||
|
jobExists = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in pairs(Config.Main.Locations) do
|
||||||
|
if #(GetEntityCoords(GetPlayerPed(source)) - vector3(v.coords.x, v.coords.y, v.coords.z)) < 1.5 then
|
||||||
|
if jobExists then
|
||||||
|
Player.Functions.SetJob(job, 0)
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du er nu ' .. job .. '!', 'success')
|
||||||
|
else
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Dette job findes ikke!', 'error')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
TriggerClientEvent('QBCore:Notify', source, 'Du er ikke på job centeret!', 'error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|