This commit is contained in:
Hawk 2024-12-29 21:01:18 +01:00
parent 05467895cf
commit e377c91601
No known key found for this signature in database
GPG Key ID: 2890D5366F8BAC14
70 changed files with 90403 additions and 0 deletions

View 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.`
});
}
});

View File

@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-alpr

View 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"}

File diff suppressed because one or more lines are too long

View 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"
});
}
});

View File

@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-call911

View 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"}

File diff suppressed because one or more lines are too long

View 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);
});

View 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"}

File diff suppressed because it is too large Load Diff

View 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 });
});

View File

@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://docs.snailycad.org/docs/fivem-integrations/scripts/sna-sync

View 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"}

View 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};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View 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)
```

View 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)

View 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)

View 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']
},
}

View 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',
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

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

View 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();
}

View 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%);
}

View 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

View 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

View 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

View 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
})

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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)

View 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/

View 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)

View 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"
}

View 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',
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

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

View 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 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({}));
}
};

View 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;
}

View 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)