const resName = GetParentResourceName(); let hasDoorsCreator = null; // editing this is useless, don't do it /* Utils */ async function placeObjectAndReturnCoords(object) { $("html").hide(); return new Promise((resolve, reject) => { $.post(`https://${resName}/placeObjectAndReturnCoords`, JSON.stringify({object: object}), function(coords) { $("html").show(); resolve(coords); }) }) } async function placeGasPoints() { $("html").hide(); return new Promise((resolve, reject) => { $.post(`https://${resName}/placeGasPoints`, JSON.stringify(), function(gasPoints) { $("html").show(); resolve(gasPoints); }) }) } // Open/Close menu function openMenu(version, fullConfig) { $("#robbery-creator-version").text(version); loadSettings(fullConfig); loadHeists(); loadCargoRobberies(); loadPlannings(); $("#robbery-creator").show() } function closeMenu() { // Resets current active tab $("#robbery-creator").find(".nav-link, .tab-pane").each(function() { if($(this).data("isDefault") == "1") { $(this).addClass(["active", "show"]) } else { $(this).removeClass(["active", "show"]) } }) $("#robbery-creator").hide(); $.post(`https://${resName}/close`, {}) } $("#close-main-btn").click(closeMenu); // Messages received by client window.addEventListener('message', (event) => { let data = event.data; let action = data.action; switch(action) { case "openMenu": { openMenu(data.version, data.fullConfig); break; } case "hasDoorsCreator": { hasDoorsCreator = data.hasDoorsCreator; break; } } }) function loadSettings(fullConfig) { // Generic setTomSelectValue("#settings_locale", fullConfig.locale) $("#settings_acePermission").val(fullConfig.acePermission); $("#settings_can_always_carry").prop("checked", fullConfig.canAlwaysCarryItem); $("#settings_can_receive_multiple_same_item").prop("checked", fullConfig.canReceiveMultipleTimesTheSameItem); $("#settings-global-timeout").val(fullConfig.globalMinutesTimeout); // Targeting setTomSelectValue("#settings-targeting-script", fullConfig.targetingScript) // Help notification setTomSelectValue("#settings-help-notification-script", fullConfig.helpNotification) // NPC Mugging - Shared $("#enable-npc-mugging").prop("checked", fullConfig.isNpcMuggingEnabled).change(); $("#seconds-to-mug").val(fullConfig.secondsToMug); // NPC Mugging - Client $("#can-make-npc-to-follow").prop("checked", fullConfig.clNpcMugging.canMakeFollow); $("#npc-mugging-cooldown-on-mugging").val(fullConfig.clNpcMugging.cooldownOnMugging); // NPC Mugging - Keys $("#npc-mugging-key-to-mug").val(fullConfig.npcMuggingKeys.keyToMug); $("#npc-mugging-key-to-follow").val(fullConfig.npcMuggingKeys.keyToFollow); $("#npc-mugging-key-to-go-away").val(fullConfig.npcMuggingKeys.keyToGoAway); // NPC Mugging - Server setNpcMuggingRobbableObjects(fullConfig.svNpcMugging.robbableObjects) $("#npc-mugging-minimum-police").val(fullConfig.svNpcMugging.minimumPolice) $("#npc-mugging-probability-police-alert").val(fullConfig.svNpcMugging.probabilityPoliceAlert) $("#npc-mugging-minimum-objects-amount").val(fullConfig.svNpcMugging.minimumObjectsAmount) $("#npc-mugging-maximum-objects-amount").val(fullConfig.svNpcMugging.maximumObjectsAmount) $("#minutes-before-automatically-run-away").val(fullConfig.svNpcMugging.minutesAfterAutomaticallyRunAway); $("#npc-mugging-max-npcs-following").val(fullConfig.svNpcMugging.maxNPCsFollowing); // Gas mask $("#gas-mask-item-name").val(fullConfig.gasMask.name); $("#gas-mask-item-duration").val(fullConfig.gasMask.duration); $("#gas-mask-lose-on-use").prop("checked", fullConfig.gasMask.loseOnUse); $("#gas-mask-cloth-id").val(fullConfig.gasMaskClothId); // Drill $("#drill-required-for-cargo-robbery").prop("checked", fullConfig.drill.requiredForCargoRobbery); $("#drill-item-name").val(fullConfig.drill.name); $("#drill-lose-on-use").prop("checked", fullConfig.drill.loseOnUse); // Cargo robbery $("#cargo-robbery-minutes-delete-after-robbed").val(fullConfig.cargoRobbery.minutesBeforeDeleteAfterRobbed); $("#cargo-robbery-minutes-delete-after-arrived").val(fullConfig.cargoRobbery.minutesBeforeDeleteAfterArrived); $("#cargo-robbery-max-minutes-difference-from-defined-date").val(fullConfig.cargoRobbery.maxMinutesDifferenceFromDefinedDate); $("#cargo-robbery-probability-police-alert").val(fullConfig.cargoRobbery.probabilityPoliceAlert); // Discord logs $("#settings_isDiscordLogActive").prop("checked", fullConfig.areDiscordLogsActive); toggleDiscordLogsInSettings(fullConfig.areDiscordLogsActive); $("#settings_discordWebhook").val(fullConfig.mainDiscordWebhook); for(const[logType, webhook] of Object.entries(fullConfig.specificWebhooks)) { $("#settings_specific_webhooks").find(`[data-log-type="${logType}"]`).val(webhook); } } /* Discord logs */ function toggleDiscordLogsInSettings(enable) { $("#settings_discordWebhook").prop("disabled", !enable); $("#settings_discordWebhook").prop("required", enable); $("#settings_specific_webhooks").find(`.form-control`).prop("disabled", !enable); } $("#settings_isDiscordLogActive").change(function() { let enabled = $(this).prop("checked"); toggleDiscordLogsInSettings(enabled); }) function getSeparatedDiscordWebhooks() { let webhooks = {}; $("#settings_specific_webhooks").find(".form-control").each(function(index, element) { let logType = $(element).data("logType"); let webhook = $(element).val(); if(webhook) { webhooks[logType] = webhook; } }); return webhooks; } /* Discord logs END */ $("#settings").submit(async function(event) { if(isThereAnyErrorInForm(event)) return; let clientSettings = { gasMaskClothId: parseInt( $("#gas-mask-cloth-id").val() ), targetingScript:$("#settings-targeting-script").val(), helpNotification: $("#settings-help-notification-script").val(), // NPC Mugging - Keys npcMuggingKeys: { keyToMug: parseInt($("#npc-mugging-key-to-mug").val()), keyToFollow: parseInt($("#npc-mugging-key-to-follow").val()), keyToGoAway: parseInt($("#npc-mugging-key-to-go-away").val()), } } let sharedSettings = { locale: $("#settings_locale").val(), } let serverSettings = { // Generic canAlwaysCarryItem: $("#settings_can_always_carry").prop("checked"), canReceiveMultipleTimesTheSameItem: $("#settings_can_receive_multiple_same_item").prop("checked"), acePermission: $("#settings_acePermission").val(), globalMinutesTimeout: parseInt( $("#settings-global-timeout").val() ), gasMask: { name: $("#gas-mask-item-name").val(), duration: parseInt( $("#gas-mask-item-duration").val() ), loseOnUse: $("#gas-mask-lose-on-use").prop("checked"), }, drill: { requiredForCargoRobbery: $("#drill-required-for-cargo-robbery").prop("checked"), name: $("#drill-item-name").val(), loseOnUse: $("#drill-lose-on-use").prop("checked") }, cargoRobbery: { minutesBeforeDeleteAfterRobbed: parseInt( $("#cargo-robbery-minutes-delete-after-robbed").val() ), minutesBeforeDeleteAfterArrived: parseInt( $("#cargo-robbery-minutes-delete-after-arrived").val() ), maxMinutesDifferenceFromDefinedDate: parseInt( $("#cargo-robbery-max-minutes-difference-from-defined-date").val() ), probabilityPoliceAlert: parseInt( $("#cargo-robbery-probability-police-alert").val() ), }, // Discord logs areDiscordLogsActive: $("#settings_isDiscordLogActive").prop("checked"), mainDiscordWebhook: $("#settings_discordWebhook").val(), specificWebhooks: getSeparatedDiscordWebhooks(), } const response = await $.post(`https://${resName}/saveSettings`, JSON.stringify({ clientSettings: clientSettings, sharedSettings: sharedSettings, serverSettings: serverSettings, })); showServerResponse(response) refreshTranslations(sharedSettings.locale); }); /* ██ ██ ███████ ██ ███████ ████████ ███████ ██ ██ ██ ██ ██ ██ ██ ███████ █████ ██ ███████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ███████ ██ ███████ */ let heistsDatatable = $("#heists-container").DataTable( { "lengthMenu": [10, 15, 20], "createdRow": function ( row, data, index ) { $(row).addClass("clickable"); $(row).click(function() { let id = parseInt( data[0] ); editHeist(id); }) }, }); let heists = {}; function loadHeists() { $.post(`https://${resName}/getAllHeists`, {}, async function(rawHeists) { // Manually create the table to avoid incompatibilities due table indexing heists = {}; for(const[k, heistData] of Object.entries(rawHeists)) { heists[heistData.id] = heistData; } heistsDatatable.clear(); for(const[id, heistData] of Object.entries(heists)) { heistsDatatable.row.add([ id, heistData.label, heistData.stages.length ]); } heistsDatatable.draw(); }) } function setDefaultDataOfHeistModal() { $("#heist-label").val("Default"); $("#heist-minimum-police").val(0); $("#heist-timeout").val(120); $("#heist-reset").val(60); $("#heist-time-limit-minutes").val(0); $("#heist-stages").empty(); } $("#new-heist-btn").click(function() { let heistModal = $("#heist-modal"); // Converts from edit modal to create modal heistModal.data("action", "create"); $("#delete-heist-btn").hide(); $("#save-heist-btn").text( getLocalizedText("menu:create") ); setDefaultDataOfHeistModal(); heistModal.modal("show"); }) function editHeist(id) { let heistData = heists[id]; let heistModal = $("#heist-modal"); heistModal.data("action", "edit"); heistModal.data("heistId", id); $("#delete-heist-btn").show(); $("#save-heist-btn").text( getLocalizedText("menu:save") ); $("#heist-label").val(heistData.label); $("#heist-minimum-police").val(heistData.minimumPolice); $("#heist-timeout").val(heistData.timeoutMinutes); $("#heist-reset").val(heistData.minutesBeforeReset); $("#heist-time-limit-minutes").val(heistData.timeLimitMinutes); $("#heist-stages").empty(); heistData.stages.forEach(stage => { addHeistStage(stage); }) heistModal.modal("show"); } /* ██████ ██████ ██████ ██████ █████ ██████ ██ ███████ ██████ ██████ ██ ███████ ██████ ████████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ██████ ███████ ██████ ██ █████ ██ ██ ██████ ██ █████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██████ ██████ ██ ██ ██████ ███████ ███████ ██████ ██████ █████ ███████ ██████ ██ ███████ */ function getAllRobbableObjectsFromStageDiv(stageDiv) { let robbableObjects = []; const stepMethod = "ROBBABLE_OBJECT" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let robbableObjectDiv = $(this); let robbableObject = { method: stepMethod, type: robbableObjectDiv.find(".object-type").val(), coords: { x: parseFloat( robbableObjectDiv.find(".coords-x").val() ), y: parseFloat( robbableObjectDiv.find(".coords-y").val() ), z: parseFloat( robbableObjectDiv.find(".coords-z").val() ), }, heading: parseFloat( robbableObjectDiv.find(".heading").val() ), blipData : robbableObjectDiv.data("blipData") || getDefaultBlipCustomization(), item: { type: robbableObjectDiv.find(".item-type").val(), name: robbableObjectDiv.find(".item-name").val(), minQuantity: parseInt( robbableObjectDiv.find(".item-min-quantity").val() ), maxQuantity: parseInt( robbableObjectDiv.find(".item-max-quantity").val() ), }, isOptional: robbableObjectDiv.find(".is-optional-checkbox").prop("checked"), isInvisible: robbableObjectDiv.find(".is-invisible-checkbox").prop("checked"), } robbableObjects.push(robbableObject); }); return robbableObjects } async function addRobbableObjectHeist(stageDiv, robbableObject) { let robbableObjectDiv = $(`

${getLocalizedText("menu:robbable_object")}


`); robbableObjectDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = robbableObjectDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { robbableObjectDiv.find(".coords-x").val(data.coords.x); robbableObjectDiv.find(".coords-y").val(data.coords.y); robbableObjectDiv.find(".coords-z").val(data.coords.z); robbableObjectDiv.find(".heading").val(data.heading); } }).tooltip(); robbableObjectDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = robbableObjectDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) robbableObjectDiv.data("blipData", blipData); }) robbableObjectDiv.find(".delete-step-btn").click(function() { robbableObjectDiv.remove(); }) robbableObjectDiv.find(".choose-robbable-item-btn").click(async function() { let objectType = robbableObjectDiv.find(".robbable-item").find(".item-type").val(); let objectName = await objectDialog(objectType); robbableObjectDiv.find(".item-name").val(objectName); }).tooltip(); // Sets value if the object is not new if(robbableObject) { robbableObjectDiv.find(".object-type").val(robbableObject.type); robbableObjectDiv.find(".coords-x").val(robbableObject.coords.x); robbableObjectDiv.find(".coords-y").val(robbableObject.coords.y); robbableObjectDiv.find(".coords-z").val(robbableObject.coords.z); robbableObjectDiv.find(".heading").val(robbableObject.heading); robbableObjectDiv.data("blipData", robbableObject.blipData); robbableObjectDiv.find(".item-type").val(robbableObject.item.type); robbableObjectDiv.find(".item-name").val(robbableObject.item.name); robbableObjectDiv.find(".item-min-quantity").val(robbableObject.item.minQuantity); robbableObjectDiv.find(".item-max-quantity").val(robbableObject.item.maxQuantity); robbableObjectDiv.find(".is-optional-checkbox").prop("checked", robbableObject.isOptional); robbableObjectDiv.find(".is-invisible-checkbox").prop("checked", robbableObject.isInvisible); } stageDiv.find(".steps-list").append(robbableObjectDiv); } /* ██████ █████ ██ ███ ██ ████████ ██ ███ ██ ██████ ███████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ████ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ████ ██████ ███████ */ function getAllPaintingsFromStageDiv(stageDiv) { let paintings = []; const stepMethod = "PAINTING" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let paintingDiv = $(this); let painting = { method: stepMethod, type: paintingDiv.find(".object-type").val(), coords: { x: parseFloat( paintingDiv.find(".coords-x").val() ), y: parseFloat( paintingDiv.find(".coords-y").val() ), z: parseFloat( paintingDiv.find(".coords-z").val() ), }, heading: parseFloat( paintingDiv.find(".heading").val() ), blipData : paintingDiv.data("blipData") || getDefaultBlipCustomization(), item: { type: paintingDiv.find(".item-type").val(), name: paintingDiv.find(".item-name").val(), minQuantity: parseInt( paintingDiv.find(".item-min-quantity").val() ), maxQuantity: parseInt( paintingDiv.find(".item-max-quantity").val() ), }, isOptional: paintingDiv.find(".is-optional-checkbox").prop("checked"), isInvisible: paintingDiv.find(".is-invisible-checkbox").prop("checked"), } paintings.push(painting); }); return paintings } async function addPaintingHeist(stageDiv, painting) { let paintingDiv = $(`

${getLocalizedText("menu:painting")}


`); paintingDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = paintingDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { paintingDiv.find(".coords-x").val(data.coords.x); paintingDiv.find(".coords-y").val(data.coords.y); paintingDiv.find(".coords-z").val(data.coords.z); paintingDiv.find(".heading").val(data.heading); } }).tooltip(); paintingDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = paintingDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) paintingDiv.data("blipData", blipData); }) paintingDiv.find(".delete-robbable-object-btn").click(function() { paintingDiv.remove(); }) paintingDiv.find(".choose-robbable-item-btn").click(async function() { let objectType = paintingDiv.find(".robbable-item").find(".item-type").val(); let objectName = await objectDialog(objectType); paintingDiv.find(".item-name").val(objectName); }).tooltip(); // Sets value if the object is not new if(painting) { paintingDiv.find(".object-type").val(painting.type); paintingDiv.find(".coords-x").val(painting.coords.x); paintingDiv.find(".coords-y").val(painting.coords.y); paintingDiv.find(".coords-z").val(painting.coords.z); paintingDiv.find(".heading").val(painting.heading); paintingDiv.data("blipData", painting.blipData); paintingDiv.find(".item-type").val(painting.item.type); paintingDiv.find(".item-name").val(painting.item.name); paintingDiv.find(".item-min-quantity").val(painting.item.minQuantity); paintingDiv.find(".item-max-quantity").val(painting.item.maxQuantity); paintingDiv.find(".is-optional-checkbox").prop("checked", painting.isOptional); paintingDiv.find(".is-invisible-checkbox").prop("checked", painting.isInvisible); } stageDiv.find(".steps-list").append(paintingDiv); } /* ██████ ██ █████ ███████ ███████ ██████ ██ ███████ ██████ ██ █████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ███████ ███████ ███████ ██ ██ ██ ███████ ██████ ██ ███████ ████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ███████ ██ ██ ███████ ███████ ██████ ██ ███████ ██ ███████ ██ ██ ██ ███████ */ function getAllGlassDisplaysFromStageDiv(stageDiv) { let glassDisplays = []; const stepMethod = "GLASS_DISPLAY" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let glassDisplayDiv = $(this); let glassDisplay = { method: stepMethod, type: glassDisplayDiv.find(".object-type").val(), coords: { x: parseFloat( glassDisplayDiv.find(".coords-x").val() ), y: parseFloat( glassDisplayDiv.find(".coords-y").val() ), z: parseFloat( glassDisplayDiv.find(".coords-z").val() ), }, heading: parseFloat( glassDisplayDiv.find(".heading").val() ), blipData : glassDisplayDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: glassDisplayDiv.find(".is-optional-checkbox").prop("checked"), requiredItem: getRequiredItemFromDiv(glassDisplayDiv), item: { type: glassDisplayDiv.find(".item-type").val(), name: glassDisplayDiv.find(".item-name").val(), minQuantity: parseInt( glassDisplayDiv.find(".item-min-quantity").val() ), maxQuantity: parseInt( glassDisplayDiv.find(".item-max-quantity").val() ), }, } glassDisplays.push(glassDisplay); }); return glassDisplays } async function addGlassDisplayHeist(stageDiv, glassDisplay) { let stepDiv = $(`

${getLocalizedText("menu:glass_display")}


`); stepDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = stepDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { stepDiv.find(".coords-x").val(data.coords.x); stepDiv.find(".coords-y").val(data.coords.y); stepDiv.find(".coords-z").val(data.coords.z); stepDiv.find(".heading").val(data.heading); } }).tooltip(); stepDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = stepDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) stepDiv.data("blipData", blipData); }) stepDiv.find(".delete-step-btn").click(function() { stepDiv.remove(); }) stepDiv.find(".choose-robbable-item-btn").click(async function() { let objectType = stepDiv.find(".robbable-item").find(".item-type").val(); let objectName = await objectDialog(objectType); stepDiv.find(".item-name").val(objectName); }).tooltip(); stepDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); stepDiv.find(".required-item-name").val(itemName); }) stepDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(stepDiv.find(".required-item-div")); }); // Sets value if the object is not new if(glassDisplay) { stepDiv.find(".object-type").val(glassDisplay.type); stepDiv.find(".coords-x").val(glassDisplay.coords.x); stepDiv.find(".coords-y").val(glassDisplay.coords.y); stepDiv.find(".coords-z").val(glassDisplay.coords.z); stepDiv.find(".heading").val(glassDisplay.heading); stepDiv.data("blipData", glassDisplay.blipData); stepDiv.find(".is-optional-checkbox").prop("checked", glassDisplay.isOptional); if(glassDisplay.requiredItem) { stepDiv.find(".required-item-name").val(glassDisplay.requiredItem.name); stepDiv.find(".required-item-quantity").val(glassDisplay.requiredItem.quantity); stepDiv.find(".required-item-lose-on-use-checkbox").prop("checked", glassDisplay.requiredItem.loseOnUse); } stepDiv.find(".item-type").val(glassDisplay.item.type); stepDiv.find(".item-name").val(glassDisplay.item.name); stepDiv.find(".item-min-quantity").val(glassDisplay.item.minQuantity); stepDiv.find(".item-max-quantity").val(glassDisplay.item.maxQuantity); } stepDiv.find(".requires-an-item-checkbox").prop("checked", glassDisplay?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(stepDiv); } /* ██ █████ ███████ ███████ ██████ ██████ ██████ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ███████ █████ ██████ ██ ██ ██████ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ███████ ███████ ██ ██ ██████ ██ ██ ██ ███████ ███████ ███████ */ function getAllLaserDrillsFromStageDiv(stageDiv) { let laserDrills = []; const stepMethod = "LASER_DRILL" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let laserDrillDiv = $(this); let stepData = { type: "laser_drill", // for the object model method: stepMethod, coords: { x: parseFloat( laserDrillDiv.find(".coords-x").val() ), y: parseFloat( laserDrillDiv.find(".coords-y").val() ), z: parseFloat( laserDrillDiv.find(".coords-z").val() ), }, blipData : laserDrillDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: laserDrillDiv.find(".is-optional-checkbox").prop("checked"), duration: parseInt( laserDrillDiv.find(".duration").val() ), requiredItem: getRequiredItemFromDiv( laserDrillDiv ), minObjectsAmount: parseInt( laserDrillDiv.find(".min-objects-amount").val() ), maxObjectsAmount: parseInt( laserDrillDiv.find(".max-objects-amount").val() ), items: getAllItemsFromDiv(laserDrillDiv), } laserDrills.push(stepData); }); return laserDrills } async function addLaserDrillHeist(stageDiv, laserDrill) { let stepDiv = $(`

${getLocalizedText("menu:laser_drill")}

${ getLocalizedText("menu:amount_of_objects") }


`); stepDiv.find(".delete-step-btn").click(function() { stepDiv.remove(); }) stepDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = stepDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { stepDiv.find(".coords-x").val(data.coords.x); stepDiv.find(".coords-y").val(data.coords.y); stepDiv.find(".coords-z").val(data.coords.z); stepDiv.find(".heading").val(data.heading); } }).tooltip(); stepDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = stepDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) stepDiv.data("blipData", blipData); }) stepDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(stepDiv.find(".required-item-div")); }); stepDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); stepDiv.find(".required-item-name").val(itemName); }) stepDiv.find(".add-item-btn").click(function() { addItemInStep(stepDiv); }) // Sets value if the object is not new if(laserDrill) { stepDiv.find(".coords-x").val(laserDrill.coords.x); stepDiv.find(".coords-y").val(laserDrill.coords.y); stepDiv.find(".coords-z").val(laserDrill.coords.z); stepDiv.data("blipData", laserDrill.blipData); stepDiv.find(".is-optional-checkbox").prop("checked", laserDrill.isOptional); stepDiv.find(".duration").val(laserDrill.duration); if(laserDrill.requiredItem) { stepDiv.find(".required-item-name").val(laserDrill.requiredItem.name); stepDiv.find(".required-item-quantity").val(laserDrill.requiredItem.quantity); stepDiv.find(".required-item-lose-on-use-checkbox").prop("checked", laserDrill.requiredItem.loseOnUse); } stepDiv.find(".min-objects-amount").val(laserDrill.minObjectsAmount); stepDiv.find(".max-objects-amount").val(laserDrill.maxObjectsAmount); if(laserDrill.items) { laserDrill.items.forEach(item => { addItemInStep(stepDiv, item); }); } } else { stepDiv.find(".min-objects-amount").val(1); stepDiv.find(".max-objects-amount").val(1); addItemInStep(stepDiv); } stepDiv.find(".requires-an-item-checkbox").prop("checked", laserDrill?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(stepDiv); } /* ██████ ██ ██ █████ ██████ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ███████ ██████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██████ ██ ██ ██ ██ ██████ ███████ */ function getGuardsFromGuardsDiv(guardsDiv) { let guards = []; guardsDiv.find(".guard").each(function() { let guardDiv = $(this); let guard = { model: guardDiv.find(".guard-model").val(), weapon: guardDiv.find(".guard-weapon").val(), coords: { x: parseFloat( guardDiv.find(".coords-x").val() ), y: parseFloat( guardDiv.find(".coords-y").val() ), z: parseFloat( guardDiv.find(".coords-z").val() ), }, heading: parseFloat( guardDiv.find(".heading").val() ), } guards.push(guard); }); return guards; } function getAllGuardsFromStageDiv(stageDiv) { let guards = []; const stepMethod = "GUARDS" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let guardsDiv = $(this); let currentGuards = { method: stepMethod, difficulty: parseInt( guardsDiv.find(".difficulty").val() ), headshotOneshot: guardsDiv.find(".headshot-oneshot-checkbox").prop("checked"), hideBlip: guardsDiv.find(".hide-blip-checkbox").prop("checked"), guardsList: getGuardsFromGuardsDiv(guardsDiv), } guards.push(currentGuards); }); return guards } function addGuardToGuardsDiv(guardsDiv, guard) { let guardDiv = $(`
`); guardDiv.find(".delete-guard-btn").click(function() { guardDiv.remove(); }); guardDiv.find(".choose-coords-and-heading-btn").click(async function() { let data = await placeObjectAndReturnCoords(); if(data) { guardDiv.find(".coords-x").val(data.coords.x); guardDiv.find(".coords-y").val(data.coords.y); guardDiv.find(".coords-z").val(data.coords.z); guardDiv.find(".heading").val(data.heading); } }).tooltip(); if(guard) { guardDiv.find(".guard-model").val(guard.model); guardDiv.find(".guard-weapon").val(guard.weapon); guardDiv.find(".coords-x").val(guard.coords.x); guardDiv.find(".coords-y").val(guard.coords.y); guardDiv.find(".coords-z").val(guard.coords.z); guardDiv.find(".heading").val(guard.heading); } guardsDiv.find(".guards-list").append(guardDiv); } async function addGuardsHeist(stageDiv, guards) { let guardsDiv = $(`

${getLocalizedText("menu:guards")}

${ getLocalizedText("menu:guards_list") }


`); guardsDiv.find(".difficulty").tooltip(); guardsDiv.find(".delete-step-btn").click(function() { guardsDiv.remove(); }); guardsDiv.find(".add-guard-btn").click(function() { addGuardToGuardsDiv(guardsDiv); }); if(guards) { guardsDiv.find(".difficulty").val(guards.difficulty); guardsDiv.find(".headshot-oneshot-checkbox").prop("checked", guards.headshotOneshot); guardsDiv.find(".hide-blip-checkbox").prop("checked", guards.hideBlip); if(guards.guardsList) { guards.guardsList.forEach(guard => { addGuardToGuardsDiv(guardsDiv, guard); }); } } stageDiv.find(".steps-list").append(guardsDiv); } /* ███████ █████ ███████ ███████ ███████ ██ ██ ██ ██ ██ ██ ███████ ███████ █████ █████ ███████ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ███████ ███████ */ function getAllSafesFromStageDiv(stageDiv) { let safes = []; const stepMethod = "SAFE" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let safeDiv = $(this); let safe = { method: stepMethod, type: safeDiv.find(".object-type").val(), coords: { x: parseFloat( safeDiv.find(".coords-x").val() ), y: parseFloat( safeDiv.find(".coords-y").val() ), z: parseFloat( safeDiv.find(".coords-z").val() ), }, heading: parseFloat( safeDiv.find(".heading").val() ), blipData : safeDiv.data("blipData") || getDefaultBlipCustomization(), items: getAllItemsFromDiv(safeDiv), difficulty: parseInt( safeDiv.find(".difficulty").val() ), minObjectsAmount: parseInt( safeDiv.find(".min-objects-amount").val() ), maxObjectsAmount: parseInt( safeDiv.find(".max-objects-amount").val() ), isOptional: safeDiv.find(".is-optional-checkbox").prop("checked"), isInvisible: safeDiv.find(".is-invisible-checkbox").prop("checked"), requiredItem: getRequiredItemFromDiv( safeDiv ), alarms: safeDiv.data("alarms") } safes.push(safe); }); return safes } function addSafeHeist(stageDiv, safe) { let safeDiv = $(`

${getLocalizedText("menu:safe")}

${ getLocalizedText("menu:amount_of_objects_from_the_safe") }


`); safeDiv.find(".setup-alarm-btn").click(async function() { let currentAlarms = safeDiv.data("alarms"); let alarms = await alarmsDialog(currentAlarms); safeDiv.data("alarms", alarms); }).tooltip(); safeDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(safeDiv.find(".required-item-div")); }); safeDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); safeDiv.find(".required-item-name").val(itemName); }) safeDiv.find(".add-item-btn").click(function() { addItemInStep(safeDiv); }) safeDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = safeDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { safeDiv.find(".coords-x").val(data.coords.x); safeDiv.find(".coords-y").val(data.coords.y); safeDiv.find(".coords-z").val(data.coords.z); safeDiv.find(".heading").val(data.heading); } }).tooltip(); safeDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = safeDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) safeDiv.data("blipData", blipData); }) safeDiv.find(".delete-step-btn").click(function() { safeDiv.remove(); }) // Sets value if the object is not new if(safe) { safeDiv.find(".object-type").val(safe.type); safeDiv.find(".coords-x").val(safe.coords.x); safeDiv.find(".coords-y").val(safe.coords.y); safeDiv.find(".coords-z").val(safe.coords.z); safeDiv.find(".heading").val(safe.heading); safeDiv.find(".difficulty").val(safe.difficulty); safeDiv.find(".min-objects-amount").val(safe.minObjectsAmount); safeDiv.find(".max-objects-amount").val(safe.maxObjectsAmount); safeDiv.find(".is-optional-checkbox").prop("checked", safe.isOptional); safeDiv.find(".is-invisible-checkbox").prop("checked", safe.isInvisible); safeDiv.data("blipData", safe.blipData); safeDiv.data("alarms", safe.alarms); safe.items.forEach(item => { addItemInStep(safeDiv, item); }) if(safe.requiredItem) { safeDiv.find(".required-item-name").val(safe.requiredItem.name); safeDiv.find(".required-item-quantity").val(safe.requiredItem.quantity); safeDiv.find(".required-item-lose-on-use-checkbox").prop("checked", safe.requiredItem.loseOnUse); } } else { // If safe didn't exist, it will also add 1 empty item to it addItemInStep(safeDiv); } safeDiv.find(".requires-an-item-checkbox").prop("checked", safe?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(safeDiv); } /* ██ ██ █████ ██████ ██ ██ █████ ██████ ██ ███████ ██████ █████ ███ ██ ███████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ███████ ███████ ██ █████ ███████ ██████ ██ █████ ██████ ███████ ██ ██ ██ █████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██████ ███████ ███████ ██ ██ ██ ██ ████ ███████ ███████ ███████ */ function getAllHackablePanelsFromStageDiv(stageDiv) { let hackablePanels = []; const stepMethod = "HACKABLE_PANEL" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let hackablePanelDiv = $(this); let hackablePanel = { type: "hackable_panel", // for the object model method: stepMethod, coords: { x: parseFloat( hackablePanelDiv.find(".coords-x").val() ), y: parseFloat( hackablePanelDiv.find(".coords-y").val() ), z: parseFloat( hackablePanelDiv.find(".coords-z").val() ), }, heading: parseFloat( hackablePanelDiv.find(".heading").val() ), blipData : hackablePanelDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: hackablePanelDiv.find(".is-optional-checkbox").prop("checked"), difficulty: parseInt( hackablePanelDiv.find(".difficulty").val() ), isInvisible: hackablePanelDiv.find(".is-invisible-checkbox").prop("checked"), doorsToOpen: hackablePanelDiv.data("doorsToOpen"), alarms: hackablePanelDiv.data("alarms"), requiredItem: getRequiredItemFromDiv( hackablePanelDiv ), minigameToUse: hackablePanelDiv.find(".minigame-to-use").val() } hackablePanels.push(hackablePanel); }); return hackablePanels } function addHackablePanelHeist(stageDiv, hackablePanel) { let hackablePanelDiv = $(`

${getLocalizedText("menu:hackable_panel")}


`); hackablePanelDiv.find(".delete-step-btn").click(function() { hackablePanelDiv.remove(); }) hackablePanelDiv.find(".difficulty").tooltip(); hackablePanelDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(hackablePanelDiv.find(".required-item-div")); }); hackablePanelDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); hackablePanelDiv.find(".required-item-name").val(itemName); }) hackablePanelDiv.find(".choose-coords-and-heading-btn").click(async function() { let data = await placeObjectAndReturnCoords("hackable_panel"); if(data) { hackablePanelDiv.find(".coords-x").val(data.coords.x); hackablePanelDiv.find(".coords-y").val(data.coords.y); hackablePanelDiv.find(".coords-z").val(data.coords.z); hackablePanelDiv.find(".heading").val(data.heading); } }).tooltip(); hackablePanelDiv.find(".setup-alarm-btn").click(async function() { let currentAlarms = hackablePanelDiv.data("alarms"); let alarms = await alarmsDialog(currentAlarms); hackablePanelDiv.data("alarms", alarms); }).tooltip(); hackablePanelDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = hackablePanelDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) hackablePanelDiv.data("blipData", blipData); }) hackablePanelDiv.find(".choose-doors-btn").click(async function() { let doors = await doorsDialog( hackablePanelDiv.data("doorsToOpen") ); hackablePanelDiv.data("doorsToOpen", doors); }) // Sets value if the object is not new if(hackablePanel) { hackablePanelDiv.find(".coords-x").val(hackablePanel.coords.x); hackablePanelDiv.find(".coords-y").val(hackablePanel.coords.y); hackablePanelDiv.find(".coords-z").val(hackablePanel.coords.z); hackablePanelDiv.find(".heading").val(hackablePanel.heading); hackablePanelDiv.find(".difficulty").val(hackablePanel.difficulty); hackablePanelDiv.find(".is-optional-checkbox").prop("checked", hackablePanel.isOptional); hackablePanelDiv.find(".is-invisible-checkbox").prop("checked", hackablePanel.isInvisible); hackablePanelDiv.data("blipData", hackablePanel.blipData); hackablePanelDiv.data("doorsToOpen", hackablePanel.doorsToOpen); hackablePanelDiv.data("alarms", hackablePanel.alarms); hackablePanelDiv.find(".minigame-to-use").val(hackablePanel.minigameToUse || "bruteforce"); if(hackablePanel.requiredItem) { hackablePanelDiv.find(".required-item-name").val(hackablePanel.requiredItem.name); hackablePanelDiv.find(".required-item-quantity").val(hackablePanel.requiredItem.quantity); hackablePanelDiv.find(".required-item-lose-on-use-checkbox").prop("checked", hackablePanel.requiredItem.loseOnUse); } } hackablePanelDiv.find(".requires-an-item-checkbox").prop("checked", hackablePanel?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(hackablePanelDiv); } /* ████████ ██ ██ ███████ ██████ ███ ███ █████ ██ ██████ ██ ██ █████ ██████ ██████ ███████ ███████ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ █████ ██████ ██ ████ ██ ███████ ██ ██ ███████ ███████ ██████ ██ ███ █████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ███████ ██████ ██ ██ ██ ██ ██ ██ ██████ ███████ ███████ */ function getAllThermalChargesFromStageDiv(stageDiv) { let thermalCharges = []; const stepMethod = "THERMAL_CHARGE" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let thermalChargeDiv = $(this); let thermalCharge = { type: "thermal_charge", // for the object model method: stepMethod, coords: { x: parseFloat( thermalChargeDiv.find(".coords-x").val() ), y: parseFloat( thermalChargeDiv.find(".coords-y").val() ), z: parseFloat( thermalChargeDiv.find(".coords-z").val() ), }, heading: parseFloat( thermalChargeDiv.find(".heading").val() ), blipData : thermalChargeDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: thermalChargeDiv.find(".is-optional-checkbox").prop("checked"), doorsToOpen: thermalChargeDiv.data("doorsToOpen"), duration: parseInt( thermalChargeDiv.find(".duration").val() ), requiredItem: getRequiredItemFromDiv(thermalChargeDiv), alarms: thermalChargeDiv.data("alarms"), } thermalCharges.push(thermalCharge); }); return thermalCharges } function addThermalChargeHeist(stageDiv, thermalCharge) { let thermalChargeHeistDiv = $(`

${getLocalizedText("menu:thermal_charge")}


`); thermalChargeHeistDiv.find(".setup-alarm-btn").click(async function() { let currentAlarms = thermalChargeHeistDiv.data("alarms"); let alarms = await alarmsDialog(currentAlarms); thermalChargeHeistDiv.data("alarms", alarms); }).tooltip(); thermalChargeHeistDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(thermalChargeHeistDiv.find(".required-item-div")); }); thermalChargeHeistDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); thermalChargeHeistDiv.find(".required-item-name").val(itemName); }) thermalChargeHeistDiv.find(".choose-coords-and-heading-btn").click(async function() { let data = await placeObjectAndReturnCoords("thermal_charge"); if(data) { thermalChargeHeistDiv.find(".coords-x").val(data.coords.x); thermalChargeHeistDiv.find(".coords-y").val(data.coords.y); thermalChargeHeistDiv.find(".coords-z").val(data.coords.z); thermalChargeHeistDiv.find(".heading").val(data.heading); } }).tooltip(); thermalChargeHeistDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = thermalChargeHeistDiv.data("blipData"); let blipData = await blipDialog(oldBlipData); thermalChargeHeistDiv.data("blipData", blipData); }); thermalChargeHeistDiv.find(".choose-doors-btn").click(async function() { let doors = await doorsDialog( thermalChargeHeistDiv.data("doorsToOpen") ); thermalChargeHeistDiv.data("doorsToOpen", doors); }); thermalChargeHeistDiv.find(".delete-step-btn").click(function() { thermalChargeHeistDiv.remove(); }); if(thermalCharge) { thermalChargeHeistDiv.find(".coords-x").val(thermalCharge.coords.x); thermalChargeHeistDiv.find(".coords-y").val(thermalCharge.coords.y); thermalChargeHeistDiv.find(".coords-z").val(thermalCharge.coords.z); thermalChargeHeistDiv.find(".heading").val(thermalCharge.heading); thermalChargeHeistDiv.find(".is-optional-checkbox").prop("checked", thermalCharge.isOptional); thermalChargeHeistDiv.find(".duration").val(thermalCharge.duration); thermalChargeHeistDiv.data("blipData", thermalCharge.blipData); thermalChargeHeistDiv.data("doorsToOpen", thermalCharge.doorsToOpen); thermalChargeHeistDiv.data("alarms", thermalCharge.alarms); if(thermalCharge.requiredItem) { thermalChargeHeistDiv.find(".required-item-name").val(thermalCharge.requiredItem.name); thermalChargeHeistDiv.find(".required-item-quantity").val(thermalCharge.requiredItem.quantity); thermalChargeHeistDiv.find(".required-item-lose-on-use-checkbox").prop("checked", thermalCharge.requiredItem.loseOnUse); } } thermalChargeHeistDiv.find(".requires-an-item-checkbox").prop("checked", thermalCharge?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(thermalChargeHeistDiv); } /* ██ ██████ ██████ ██ ██ ██████ ██ ██████ ██ ██ █████ ██████ ██ ███████ ██████ ██████ ██████ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █████ ██████ ██ ██ █████ ███████ ██████ ██ █████ ██ ██ ██ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██████ ██████ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██████ ███████ ███████ ██████ ██████ ██████ ██ ██ ███████ */ function getAllLockpickableDoorsFromStageDiv(stageDiv) { let lockpickableDoors = []; const stepMethod = "LOCKPICKABLE_DOOR" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let lockpickableDoorDiv = $(this); let lockpickableDoor = { type: "lockpickable_door", // for the object model method: stepMethod, coords: { x: parseFloat( lockpickableDoorDiv.find(".coords-x").val() ), y: parseFloat( lockpickableDoorDiv.find(".coords-y").val() ), z: parseFloat( lockpickableDoorDiv.find(".coords-z").val() ), }, blipData : lockpickableDoorDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: lockpickableDoorDiv.find(".is-optional-checkbox").prop("checked"), doorsToOpen: lockpickableDoorDiv.data("doorsToOpen"), difficulty: parseInt( lockpickableDoorDiv.find(".difficulty").val() ), requiredItem: getRequiredItemFromDiv(lockpickableDoorDiv), alarms: lockpickableDoorDiv.data("alarms"), } lockpickableDoors.push(lockpickableDoor); }); return lockpickableDoors } function addLockpickableDoorHeist(stageDiv, lockpickableDoor) { let lockpickableDoorHeistDiv = $(`

${getLocalizedText("menu:lockpickable_door")}


`); lockpickableDoorHeistDiv.find(".setup-alarm-btn").click(async function() { let currentAlarms = lockpickableDoorHeistDiv.data("alarms"); let alarms = await alarmsDialog(currentAlarms); lockpickableDoorHeistDiv.data("alarms", alarms); }).tooltip(); lockpickableDoorHeistDiv.find(".requires-an-item-checkbox").change(function() { toggleRequiredItem(lockpickableDoorHeistDiv.find(".required-item-div")); }); lockpickableDoorHeistDiv.find(".choose-item-btn").click(async function() { let itemName = await itemsDialog(); lockpickableDoorHeistDiv.find(".required-item-name").val(itemName); }) lockpickableDoorHeistDiv.find(".choose-coords-and-heading-btn").click(async function() { let data = await placeObjectAndReturnCoords(); if(data) { lockpickableDoorHeistDiv.find(".coords-x").val(data.coords.x); lockpickableDoorHeistDiv.find(".coords-y").val(data.coords.y); lockpickableDoorHeistDiv.find(".coords-z").val(data.coords.z); } }).tooltip(); lockpickableDoorHeistDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = lockpickableDoorHeistDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) lockpickableDoorHeistDiv.data("blipData", blipData); }); lockpickableDoorHeistDiv.find(".choose-doors-btn").click(async function() { let doors = await doorsDialog( lockpickableDoorHeistDiv.data("doorsToOpen") ); lockpickableDoorHeistDiv.data("doorsToOpen", doors); }); lockpickableDoorHeistDiv.find(".delete-step-btn").click(function() { lockpickableDoorHeistDiv.remove(); }); if(lockpickableDoor) { lockpickableDoorHeistDiv.find(".coords-x").val(lockpickableDoor.coords.x); lockpickableDoorHeistDiv.find(".coords-y").val(lockpickableDoor.coords.y); lockpickableDoorHeistDiv.find(".coords-z").val(lockpickableDoor.coords.z); lockpickableDoorHeistDiv.find(".is-optional-checkbox").prop("checked", lockpickableDoor.isOptional); lockpickableDoorHeistDiv.find(".difficulty").val(lockpickableDoor.difficulty); lockpickableDoorHeistDiv.data("blipData", lockpickableDoor.blipData); lockpickableDoorHeistDiv.data("doorsToOpen", lockpickableDoor.doorsToOpen); lockpickableDoorHeistDiv.data("alarms", lockpickableDoor.alarms); if(lockpickableDoor.requiredItem) { lockpickableDoorHeistDiv.find(".required-item-name").val(lockpickableDoor.requiredItem.name); lockpickableDoorHeistDiv.find(".required-item-quantity").val(lockpickableDoor.requiredItem.quantity); lockpickableDoorHeistDiv.find(".required-item-lose-on-use-checkbox").prop("checked", lockpickableDoor.requiredItem.loseOnUse); } } lockpickableDoorHeistDiv.find(".requires-an-item-checkbox").prop("checked", lockpickableDoor?.requiredItem ? true : false).change(); stageDiv.find(".steps-list").append(lockpickableDoorHeistDiv); } /* ██ ███████ ████████ ██ ██ █████ ██ ██████ █████ ███████ ███████ ███████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █████ ██ ███████ ███████ ██ ██ ███ ███████ ███████ ███████ █████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ███████ ██ ██ ██ ██ ██ ███████ ██████ ██ ██ ███████ ███████ ███████ ███████ */ function getAllLethalGassesFromStageDiv(stageDiv) { let lethalGases = []; const stepMethod = "LETHAL_GAS" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let lethalGasDiv = $(this); let lethalGas = { type: "lethal_gas", // for the object model method: stepMethod, gasPoints: lethalGasDiv.data("gasPoints"), duration: parseInt( lethalGasDiv.find(".duration").val() ), damage: parseInt( lethalGasDiv.find(".damage").val() ), secondsBeforeStart: parseInt( lethalGasDiv.find(".seconds-before-start").val() ), color: hexToRgb( lethalGasDiv.find(".gas-color").val() ), } lethalGases.push(lethalGas); }); return lethalGases } function addLethalGasHeist(stageDiv, lethalGas) { let lethalGasHeistDiv = $(`

${getLocalizedText("menu:lethal_gas")}


`); lethalGasHeistDiv.find(".seconds-before-start").tooltip() lethalGasHeistDiv.find(".gas-color").tooltip() lethalGasHeistDiv.find(".choose-gas-points").click(async function() { let gasPoints = await placeGasPoints(); lethalGasHeistDiv.data("gasPoints", gasPoints); }).tooltip(); lethalGasHeistDiv.find(".delete-step-btn").click(function() { lethalGasHeistDiv.remove(); }); if(lethalGas) { lethalGasHeistDiv.find(".duration").val(lethalGas.duration); lethalGasHeistDiv.data("gasPoints", lethalGas.gasPoints); lethalGasHeistDiv.find(".damage").val(lethalGas.damage); lethalGasHeistDiv.find(".seconds-before-start").val(lethalGas.secondsBeforeStart); lethalGasHeistDiv.find(".gas-color").val( rgbToHex(lethalGas.color.r, lethalGas.color.g, lethalGas.color.b) ); } stageDiv.find(".steps-list").append(lethalGasHeistDiv); } /* ███████ ███████ █████ ██████ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ █████ ███████ ██████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ███████ ██ ██ ██ ██ ██████ ██ ██ */ function getPossiblePointsFromSearchPointsDiv(searchPointsDiv) { let possiblePoints = []; searchPointsDiv.find(".point").each(function() { let pointDiv = $(this); let possiblePoint = { coords: { x: parseFloat( pointDiv.find(".coords-x").val() ), y: parseFloat( pointDiv.find(".coords-y").val() ), z: parseFloat( pointDiv.find(".coords-z").val() ), }, } possiblePoints.push(possiblePoint); }); return possiblePoints; } function getAllSearchPointsFromStageDiv(stageDiv) { let searchPoints = []; const stepMethod = "SEARCH_POINTS" stageDiv.find(`.steps-list > [data-step-method='${stepMethod}']`).each(function() { let searchPointslDiv = $(this); let stepData = { type: "search_points", // for the object model method: stepMethod, possiblePoints: getPossiblePointsFromSearchPointsDiv(searchPointslDiv), blipData : searchPointslDiv.data("blipData") || getDefaultBlipCustomization(), isOptional: searchPointslDiv.find(".is-optional-checkbox").prop("checked"), minObjectsAmount: parseInt( searchPointslDiv.find(".min-objects-amount").val() ), maxObjectsAmount: parseInt( searchPointslDiv.find(".max-objects-amount").val() ), items: getAllItemsFromDiv(searchPointslDiv), } searchPoints.push(stepData); }); return searchPoints } function addPossiblePointToSearchPointsDiv(searchPointsDiv, possiblePoint) { let possiblePointDiv = $(`
`); possiblePointDiv.find(".delete-point-btn").click(function() { possiblePointDiv.remove(); }); possiblePointDiv.find(".choose-coords-and-heading-btn").click(async function() { let coords = await chooseCoords(); if(coords) { possiblePointDiv.find(".coords-x").val(coords.x); possiblePointDiv.find(".coords-y").val(coords.y); possiblePointDiv.find(".coords-z").val(coords.z); } }).tooltip(); if(possiblePoint) { possiblePointDiv.find(".coords-x").val(possiblePoint.coords.x); possiblePointDiv.find(".coords-y").val(possiblePoint.coords.y); possiblePointDiv.find(".coords-z").val(possiblePoint.coords.z); } searchPointsDiv.find(".possible-points-list").append(possiblePointDiv); } async function addSearchPointsHeist(stageDiv, searchPoints) { let stepDiv = $(`

${getLocalizedText("menu:search_points")}

${ getLocalizedText("menu:amount_of_objects") }

${getLocalizedText("menu:possible_points")}


`); stepDiv.find(".delete-step-btn").click(function() { stepDiv.remove(); }) stepDiv.find(".choose-coords-and-heading-btn").click(async function() { let objectType = stepDiv.find(".object-type").val(); let data = await placeObjectAndReturnCoords(objectType); if(data) { stepDiv.find(".coords-x").val(data.coords.x); stepDiv.find(".coords-y").val(data.coords.y); stepDiv.find(".coords-z").val(data.coords.z); } }).tooltip(); stepDiv.find(".customize-blip-btn").click(async function() { let oldBlipData = stepDiv.data("blipData"); let blipData = await blipDialog(oldBlipData) stepDiv.data("blipData", blipData); }) stepDiv.find(".add-item-btn").click(function() { addItemInStep(stepDiv); }) stepDiv.find(".add-point-btn").click(function() { addPossiblePointToSearchPointsDiv(stepDiv); }) // Sets value if the object is not new if(searchPoints) { stepDiv.data("blipData", searchPoints.blipData); stepDiv.find(".is-optional-checkbox").prop("checked", searchPoints.isOptional); stepDiv.find(".min-objects-amount").val(searchPoints.minObjectsAmount); stepDiv.find(".max-objects-amount").val(searchPoints.maxObjectsAmount); if(searchPoints.items) { searchPoints.items.forEach(item => { addItemInStep(stepDiv, item); }); } if(searchPoints.possiblePoints) { searchPoints.possiblePoints.forEach(possiblePoint => { addPossiblePointToSearchPointsDiv(stepDiv, possiblePoint); }); } } else { stepDiv.find(".min-objects-amount").val(1); stepDiv.find(".max-objects-amount").val(1); addItemInStep(stepDiv); addPossiblePointToSearchPointsDiv(stepDiv); } stageDiv.find(".steps-list").append(stepDiv); } /* ██ ██ ███████ ██ ███████ ████████ ███████ ███ ███ ██ ███████ ██████ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ███████ █████ ██ ███████ ██ ███████ ██ ████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ███████ ██ ███████ ██ ██ ██ ███████ ██████ */ function getAllItemsFromDiv(stepDiv) { let items = []; stepDiv.find(".item").each(function() { let itemDiv = $(this); let item = { type: itemDiv.find(".item-type").val(), name: itemDiv.find(".item-name").val(), minQuantity: parseInt( itemDiv.find(".item-min-quantity").val() ), maxQuantity: parseInt( itemDiv.find(".item-max-quantity").val() ), chances: parseInt( itemDiv.find(".item-chances").val() ), } items.push(item); }); return items } function getRequiredItemFromDiv(stepDiv) { const requiredItemDiv = stepDiv.find(".required-item-div"); let requiresItem = requiredItemDiv.find(".requires-an-item-checkbox").prop("checked"); if(requiresItem) { return { name: requiredItemDiv.find(".required-item-name").val(), quantity: parseInt( requiredItemDiv.find(".required-item-quantity").val() ), loseOnUse: requiredItemDiv.find(".required-item-lose-on-use-checkbox").prop("checked"), } } else { return null; } } function getHeistStages() { let stages = []; $("#heist-stages").find(".stage").each(function(index) { let stageDiv = $(this); let stage = { steps: [ ...getAllRobbableObjectsFromStageDiv(stageDiv), ...getAllSafesFromStageDiv(stageDiv), ...getAllPaintingsFromStageDiv(stageDiv), ...getAllGlassDisplaysFromStageDiv(stageDiv), ...getAllLaserDrillsFromStageDiv(stageDiv), ...getAllGuardsFromStageDiv(stageDiv), ...getAllHackablePanelsFromStageDiv(stageDiv), ...getAllThermalChargesFromStageDiv(stageDiv), ...getAllLockpickableDoorsFromStageDiv(stageDiv), ...getAllLethalGassesFromStageDiv(stageDiv), ...getAllSearchPointsFromStageDiv(stageDiv), ], } stages.push(stage); }) return stages } $("#heist-form").submit(async function(event) { if(isThereAnyErrorInForm(event)) return; let heistModal = $("#heist-modal"); let action = heistModal.data("action"); let heistData = { label: $("#heist-label").val(), minimumPolice: parseInt( $("#heist-minimum-police").val() ), timeoutMinutes: parseInt( $("#heist-timeout").val() ), minutesBeforeReset: parseInt( $("#heist-reset").val() ), timeLimitMinutes: parseInt( $("#heist-time-limit-minutes").val() ), stages: getHeistStages() } switch(action) { case "create": { const response = await $.post(`https://${resName}/createHeist`, JSON.stringify(heistData)); showServerResponse(response) if(response === true) { heistModal.modal("hide"); loadHeists(); } break; } case "edit": { const response = await $.post(`https://${resName}/updateHeist`, JSON.stringify({heistId: heistModal.data("heistId"), heistData: heistData})); showServerResponse(response) if(response === true) { heistModal.modal("hide"); loadHeists(); } break; } } }); $("#delete-heist-btn").click(async function() { if(!await confirmDeletion()) return; let heistModal = $("#heist-modal"); let heistId = heistModal.data("heistId"); const response = await $.post(`https://${resName}/deleteHeist`, JSON.stringify({heistId: heistId})); showServerResponse(response); if(response === true) { heistModal.modal("hide"); loadHeists(); } }) async function addItemInStep(stepDiv, item) { let itemDiv = $(`
`); itemDiv.find(".delete-item-btn").click(function() { itemDiv.remove(); }) itemDiv.find(".choose-item-btn").click(async function() { let objectType = itemDiv.find(".item-type").val(); let objectName = await objectDialog(objectType); itemDiv.find(".item-name").val(objectName); }).tooltip(); if(item) { itemDiv.find(".item-type").val(item.type); itemDiv.find(".item-name").val(item.name); itemDiv.find(".item-min-quantity").val(item.minQuantity); itemDiv.find(".item-max-quantity").val(item.maxQuantity); itemDiv.find(".item-chances").val(item.chances); } stepDiv.find(".items-list").append(itemDiv); } function toggleRequiredItem(requiredItemDiv) { let enabled = requiredItemDiv.find(".requires-an-item-checkbox").prop("checked"); requiredItemDiv.find(".required-item-name").prop("disabled", !enabled).prop("required", enabled); requiredItemDiv.find(".required-item-quantity").prop("disabled", !enabled).prop("required", enabled); requiredItemDiv.find(".choose-item-btn").prop("disabled", !enabled); requiredItemDiv.find(".required-item-lose-on-use-checkbox").prop("disabled", !enabled); if(!enabled) { requiredItemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", false); } } function renameAllStagesByTheirOrder() { $("#heist-stages").find(".stage-title").each(function(index) { let stageNumber = index + 1; $(this).prop("innerHTML", `${ getLocalizedText("menu:stage") } ${stageNumber}`) }) $("#heist-stages").find(".delete-stage-btn").each(function(index) { let stageNumber = index + 1; $(this).prop("innerHTML", `${ getLocalizedText("menu:delete_stage") } - ${stageNumber}`) }) } function setDoorsCreatorStatusOnStageDiv(stageDiv) { if(hasDoorsCreator) return; let stepsRequiringDoorsCreator = { "HACKABLE_PANEL": true, "THERMAL_CHARGE": true, "LOCKPICKABLE_DOOR": true, } stageDiv.find("[data-step-method]").each(function() { let stepMethod = $(this).data("stepMethod"); if(stepsRequiringDoorsCreator[stepMethod]) { $(this) .addClass("disabled") .parent() .data("bs-toggle", "tooltip") .data("bs-placement", "top") .prop("title", getLocalizedText("menu:requires_doors_creator")) .tooltip(); } }); } // If it's the first stage, the steps guards and lethal gas won't be usable function setAvailableStepsForEachStage() { $("#heist-stages").find(".stage").each(function() { let stageNumber = $(this).index() + 1; const isFirstStage = stageNumber == 1; const guardDiv = $(this).find(".steps-methods-list").find("[data-step-method='GUARDS']"); const lethalGasDiv = $(this).find(".steps-methods-list").find("[data-step-method='LETHAL_GAS']"); guardDiv.toggleClass("disabled", isFirstStage); lethalGasDiv.toggleClass("disabled", isFirstStage); // Enable tooltip only if it's first stage if(isFirstStage) { $(this).find(".not-first-stage-list-element").tooltip("enable"); } else { $(this).find(".not-first-stage-list-element").tooltip("disable"); } }) } function addStepDiv(stepMethod, stageDiv, stepData) { switch(stepMethod) { case "ROBBABLE_OBJECT": addRobbableObjectHeist(stageDiv, stepData); break; case "SAFE": addSafeHeist(stageDiv, stepData); break; case "PAINTING": addPaintingHeist(stageDiv, stepData); break; case "GLASS_DISPLAY": addGlassDisplayHeist(stageDiv, stepData); break; case "LASER_DRILL": addLaserDrillHeist(stageDiv, stepData); break; case "GUARDS": addGuardsHeist(stageDiv, stepData); break; case "HACKABLE_PANEL": addHackablePanelHeist(stageDiv, stepData); break; case "THERMAL_CHARGE": addThermalChargeHeist(stageDiv, stepData); break; case "LOCKPICKABLE_DOOR": addLockpickableDoorHeist(stageDiv, stepData); break; case "LETHAL_GAS": addLethalGasHeist(stageDiv, stepData); break; case "SEARCH_POINTS": { addSearchPointsHeist(stageDiv, stepData); break; } default: console.log("Unknown step method: " + stepMethod); break; } } function addHeistStage(stage) { let stageDiv = $(`

${ getLocalizedText("menu:stage") } ${$("#heist-stages").children(".stage").length + 1}


`) stageDiv.find(".delete-stage-btn").click(function() { stageDiv.remove(); renameAllStagesByTheirOrder(); setAvailableStepsForEachStage(); }) stageDiv.find(".steps-methods-list a").click(function() { let stepMethod = $(this).data("stepMethod"); addStepDiv(stepMethod, stageDiv); }) if(stage) { stage.steps.forEach(stepData => { addStepDiv(stepData.method, stageDiv, stepData); }); } setDoorsCreatorStatusOnStageDiv(stageDiv); $("#heist-stages").append(stageDiv); setAvailableStepsForEachStage(); } $("#heist-add-stage-btn").click(function() { addHeistStage() }) $("#heist-import-stages-from-heist-btn").click(async function() { let heistId = await heistsDialog() if(heistId) { heists[heistId].stages.forEach(stage => { addHeistStage(stage); }) } }) /* ██████ █████ ██████ ██████ ██████ ██████ ██████ ██████ ██████ ███████ ██████ ██ ███████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██████ ██ ███ ██ ██ ██████ ██ ██ ██████ ██████ █████ ██████ ██ █████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██████ ██████ ██ ██ ██████ ██████ ██████ ███████ ██ ██ ██ ███████ ███████ */ let cargoRobberiesDatatable = $("#cargo-robberies-container").DataTable( { "lengthMenu": [10, 15, 20], "createdRow": function ( row, data, index ) { $(row).addClass("clickable"); $(row).click(function() { let id = parseInt( data[0] ); editCargoRobbery(id); }) }, }); let cargoRobberies = {}; function loadCargoRobberies() { $.post(`https://${resName}/getAllCargoRobberies`, {}, async function(rawCargoRobberies) { // Manually create the table to avoid incompatibilities due table indexing cargoRobberies = {}; for(const[k, heistData] of Object.entries(rawCargoRobberies)) { cargoRobberies[heistData.id] = heistData; } cargoRobberiesDatatable.clear(); for(const[id, heistData] of Object.entries(cargoRobberies)) { cargoRobberiesDatatable.row.add([ id, heistData.label, ]); } cargoRobberiesDatatable.draw(); }) } function getDefaultBlipCargoRobbery() { return { isEnabled: true, sprite: 67, label: getLocalizedText("menu:armored_truck"), scale: 0.8, color: 1, display: 2, } } function setDefaultDataOfCargoRobberyModal() { $("#cargo-robbery-label").val("Default"); $("#cargo-robbery-vehicle-model").val("stockade"); $("#cargo-robbery-driver-model").val("mp_m_securoguard_01"); $("#cargo-robbery-max-speed").val(50.0); $("#cargo-robbery-seconds-to-drill").val(20); $(`input[name=cargo-drive-type][value='stops']`).prop("checked", true).change(); $("#cargo-robbery-random-drive-coords-x").val(""); $("#cargo-robbery-random-drive-coords-y").val(""); $("#cargo-robbery-random-drive-coords-z").val(""); $("#cargo-robbery-random-drive-heading").val(""); $("#cargo-robbery-random-drive-minutes-before-despawn").val(30); $("#cargo-robbery-min-objects-quantity").val(1); $("#cargo-robbery-max-objects-quantity").val(2); $("#cargo-items-list").empty(); $("#cargo-robbery-stops").empty(); $("#cargo-robbery-modal").data("blipData", getDefaultBlipCargoRobbery()); } function renameAllStopsByTheirOrder() { $("#cargo-robbery-stops").find(".stop-title").each(function(index) { let stopNumber = index + 1; $(this).prop("innerHTML", `${ getLocalizedText("menu:stop") } ${stopNumber}`) }) $("#cargo-robbery-stops").find(".delete-stop-btn").each(function(index) { let stopNumber = index + 1; $(this).prop("innerHTML", `${ getLocalizedText("menu:delete_stop") } - ${stopNumber}`) }) } $("#new-cargo-robbery-btn").click(function() { let cargoRobberyModal = $("#cargo-robbery-modal"); // Converts from edit modal to create modal cargoRobberyModal.data("action", "create"); $("#delete-cargo-robbery-btn").hide(); $("#save-cargo-robbery-btn").text( getLocalizedText("menu:create") ); setDefaultDataOfCargoRobberyModal(); cargoRobberyModal.modal("show"); }) function editCargoRobbery(id) { let cargoRobberyData = cargoRobberies[id]; let cargoRobberyModal = $("#cargo-robbery-modal"); cargoRobberyModal.data("action", "edit"); cargoRobberyModal.data("cargoRobberyId", id); cargoRobberyModal.data("blipData", cargoRobberyData.blipData); $("#delete-cargo-robbery-btn").show(); $("#save-cargo-robbery-btn").text( getLocalizedText("menu:save") ); $("#cargo-robbery-label").val(cargoRobberyData.label); $("#cargo-robbery-vehicle-model").val(cargoRobberyData.data.vehicleModel); $("#cargo-robbery-driver-model").val(cargoRobberyData.data.driverModel); $("#cargo-robbery-bulletproof-wheels-checkbox").prop("checked", cargoRobberyData.data.hasBulletproofTires); $("#cargo-robbery-max-speed").val(cargoRobberyData.data.maxSpeed); $("#cargo-robbery-seconds-to-drill").val(cargoRobberyData.data.secondsToDrill) $(`input[name=cargo-drive-type][value='${cargoRobberyData.data.driveType}']`).prop("checked", true).change(); $("#cargo-robbery-random-drive-coords-x").val(cargoRobberyData.data.startCoords?.x); $("#cargo-robbery-random-drive-coords-y").val(cargoRobberyData.data.startCoords?.y); $("#cargo-robbery-random-drive-coords-z").val(cargoRobberyData.data.startCoords?.z); $("#cargo-robbery-random-drive-heading").val(cargoRobberyData.data.startCoords?.heading); $("#cargo-robbery-random-drive-minutes-before-despawn").val(cargoRobberyData.data.minutesBeforeDespawn); $("#cargo-robbery-min-objects-quantity").val(cargoRobberyData.data.minObjectsAmount); $("#cargo-robbery-max-objects-quantity").val(cargoRobberyData.data.maxObjectsAmount); $("#cargo-items-list").empty(); if(cargoRobberyData.data.rewardObjects) { cargoRobberyData.data.rewardObjects.forEach(rewardObject => { addObjectInCargoRobbery(rewardObject); }) } $("#cargo-robbery-stops").empty(); if(cargoRobberyData.data.stops) { cargoRobberyData.data.stops.forEach(stop => { addCargoRobberyStop(stop); }) } cargoRobberyModal.modal("show"); } function addCargoRobberyStop(stopData) { let stopIndex = $("#cargo-robbery-stops").children(".stop").length + 1; let stopDiv = $(`

${ getLocalizedText("menu:stop") } ${stopIndex}

${ getLocalizedText("menu:destination") }


`) stopDiv.find(".current-coords-btn").click(async function() { let data = await getCurrentCoordsAndHeading(); stopDiv.find(".coords-x").val(data.coords.x); stopDiv.find(".coords-y").val(data.coords.y); stopDiv.find(".coords-z").val(data.coords.z); stopDiv.find(".heading").val(data.heading); }).tooltip(); stopDiv.find(".delete-stop-btn").click(function() { stopDiv.remove(); renameAllStopsByTheirOrder(); }); if(stopData) { stopDiv.find(".coords-x").val(stopData.coords.x); stopDiv.find(".coords-y").val(stopData.coords.y); stopDiv.find(".coords-z").val(stopData.coords.z); stopDiv.find(".heading").val(stopData.heading); stopDiv.find(".minutes-to-wait").val(stopData.minutesToWait); } $("#cargo-robbery-stops").append(stopDiv); } $("#cargo-robbery-add-stop-btn").click(function() { addCargoRobberyStop() }) $('input[name=cargo-drive-type]').change(function() { let type = $(this).val(); switch(type) { case "stops": { $("#cargo-robbery-stops-container").show().find(".form-control").prop("required", true); $("#cargo-robbery-random-drive-container").hide().find(".form-control").prop("required", false); break; } case "random": { $("#cargo-robbery-stops-container").hide().find(".form-control").prop("required", false); $("#cargo-robbery-random-drive-container").show().find(".form-control").prop("required", true); break; } } }); $("#cargo-robbery-random-drive-current-coords-btn").click(async function() { let data = await getCurrentCoordsAndHeading(); $("#cargo-robbery-random-drive-coords-x").val(data.coords.x); $("#cargo-robbery-random-drive-coords-y").val(data.coords.y); $("#cargo-robbery-random-drive-coords-z").val(data.coords.z); $("#cargo-robbery-random-drive-heading").val(data.heading); }) function getCargoRobberyStops() { let stops = []; $("#cargo-robbery-stops").find(".stop").each(function() { let stop = { coords: { x: parseFloat( $(this).find(".coords-x").val() ), y: parseFloat( $(this).find(".coords-y").val() ), z: parseFloat( $(this).find(".coords-z").val() ), }, heading: parseFloat( $(this).find(".heading").val() ), minutesToWait: parseInt( $(this).find(".minutes-to-wait").val() ), }; stops.push(stop); }); return stops; } function getCargoRobberyRewards() { let rewards = []; $("#cargo-items-list").find(".cargo-robbery-item").each(function() { let currentObject = $(this); let reward = { type: currentObject.find(".object-type").val(), name: currentObject.find(".object-name").val(), minQuantity: parseInt(currentObject.find(".min-quantity").val()), maxQuantity: parseInt(currentObject.find(".max-quantity").val()), chances: parseInt(currentObject.find(".chances").val()) } rewards.push(reward); }) return rewards; } $("#cargo-robbery-form").submit(async function(event) { if(isThereAnyErrorInForm(event)) return; let cargoRobberyModal = $("#cargo-robbery-modal"); let action = cargoRobberyModal.data("action"); let cargoRobberyData = { label: $("#cargo-robbery-label").val(), blipData: cargoRobberyModal.data("blipData"), data: { vehicleModel: $("#cargo-robbery-vehicle-model").val(), driverModel: $("#cargo-robbery-driver-model").val(), hasBulletproofTires: $("#cargo-robbery-bulletproof-wheels-checkbox").prop("checked"), maxSpeed: parseFloat( $("#cargo-robbery-max-speed").val() ), secondsToDrill: parseInt( $("#cargo-robbery-seconds-to-drill").val() ), minObjectsAmount: parseInt( $("#cargo-robbery-min-objects-quantity").val() ), maxObjectsAmount: parseInt( $("#cargo-robbery-max-objects-quantity").val() ), rewardObjects: getCargoRobberyRewards(), stops: getCargoRobberyStops(), driveType: $('input[name=cargo-drive-type]:checked').val(), startCoords: { x: parseFloat( $("#cargo-robbery-random-drive-coords-x").val() ), y: parseFloat( $("#cargo-robbery-random-drive-coords-y").val() ), z: parseFloat( $("#cargo-robbery-random-drive-coords-z").val() ), heading: parseFloat( $("#cargo-robbery-random-drive-heading").val() ), }, minutesBeforeDespawn: parseInt( $("#cargo-robbery-random-drive-minutes-before-despawn").val() ) } } switch(action) { case "create": { const response = await $.post(`https://${resName}/createCargoRobbery`, JSON.stringify(cargoRobberyData)); showServerResponse(response); if(response === true) { cargoRobberyModal.modal("hide"); loadCargoRobberies(); } break; } case "edit": { const response = await $.post(`https://${resName}/updateCargoRobbery`, JSON.stringify({cargoRobberyId: cargoRobberyModal.data("cargoRobberyId"), cargoRobberyData: cargoRobberyData})); showServerResponse(response); if(response === true) { cargoRobberyModal.modal("hide"); loadCargoRobberies(); } break; } } }); $("#delete-cargo-robbery-btn").click(async function() { if(!await confirmDeletion()) return; let cargoRobberyModal = $("#cargo-robbery-modal"); let cargoRobberyId = cargoRobberyModal.data("cargoRobberyId"); const response = await $.post(`https://${resName}/deleteCargoRobbery`, JSON.stringify({cargoRobberyId: cargoRobberyId})); showServerResponse(response); if(response === true) { cargoRobberyModal.modal("hide"); loadCargoRobberies(); } }) $("#cargo-robbery-customize-blip-btn").click(async function() { oldBlipData = $("#cargo-robbery-modal").data("blipData"); let blipData = await blipDialog(oldBlipData) $("#cargo-robbery-modal").data("blipData", blipData); }); async function addObjectInCargoRobbery(objectData) { let objectDiv = $(`
`); objectDiv.find(".delete-cargo-robbery-item-btn").click(function() { objectDiv.remove(); }) objectDiv.find(".choose-item-btn").click(async function() { let objectType = objectDiv.find(".object-type").val(); let objectName = await objectDialog(objectType); objectDiv.find(".object-name").val(objectName); }).tooltip(); if(objectData) { objectDiv.find(".object-type").val(objectData.type); objectDiv.find(".object-name").val(objectData.name); objectDiv.find(".min-quantity").val(objectData.minQuantity); objectDiv.find(".max-quantity").val(objectData.maxQuantity); objectDiv.find(".chances").val(objectData.chances); } $("#cargo-items-list").append(objectDiv); } $("#cargo-robbery-add-item-btn").click(function() { addObjectInCargoRobbery(); }); /* ██████ ██ █████ ███ ██ ███ ██ ██ ███ ██ ██████ ██ ██ ██ ██ ██ ████ ██ ████ ██ ██ ████ ██ ██ ██████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ████ ██ ████ ██ ██ ████ ██████ */ let planningsDatatable = $("#plannings-container").DataTable( { "lengthMenu": [10, 15, 20], "createdRow": function ( row, data, index ) { $(row).addClass("clickable"); $(row).click(function() { let id = parseInt( data[0] ); editPlanning(id); }) }, }); let plannings = {}; function getRemainingTimeForPlannings() { return new Promise((resolve, reject) => { $.post(`https://${resName}/getRemainingTimeForPlannings`, function(remainingTimes) { resolve(remainingTimes) }); }) } async function loadPlannings() { let remainingTimes = await getRemainingTimeForPlannings(); $.post(`https://${resName}/getAllPlannings`, {}, async function(rawPlannings) { // Manually create the table to avoid incompatibilities due table indexing plannings = {}; for(const[k, planningData] of Object.entries(rawPlannings)) { plannings[planningData.id] = planningData; } planningsDatatable.clear(); for(const[id, planningData] of Object.entries(plannings)) { planningsDatatable.row.add([ id, planningData.label, cargoRobberies[planningData.cargoRobberyId]?.label || "None", remainingTimes[id] || "?", ]); } planningsDatatable.draw(); }) } function planningSetTargetRobbery(robberyId = null) { let planningModal = $("#planning-modal"); planningModal.data("cargoRobberyId", robberyId); if(robberyId) { let robberyLabel = cargoRobberies[robberyId].label; $("#planning-target-robbery").val( robberyLabel ); } else { $("#planning-target-robbery").val( getLocalizedText("menu:none") ); } } function setDefaultDataOfPlanningModal() { $("#planning-label").val("Default"); $("#planning-min-police").val(0); planningSetTargetRobbery(null); $("#planning-date-type").val("now").change(); } $("#new-planning-btn").click(function() { let planningModal = $("#planning-modal"); // Converts from edit modal to create modal planningModal.data("action", "create"); $("#delete-planning-btn").hide(); $("#save-planning-btn").text( getLocalizedText("menu:create") ); setDefaultDataOfPlanningModal(); planningModal.modal("show"); }) $("#planning-choose-robbery-btn").click(async function() { let robberyId = await cargoRobberiesDialog(); planningSetTargetRobbery(robberyId); }); function togglePlanningDateType() { let val = $("#planning-date-type").val(); if(val == "date") { $("#planning-date").show().prop("required", true); } else { $("#planning-date").hide().prop("required", false); } if(val == "interval") { $("#planning-interval-div").show(); $("#planning-interval").prop("required", true); } else { $("#planning-interval-div").hide(); $("#planning-interval").prop("required", false); } } $("#planning-date-type").change(togglePlanningDateType); function getUnixFromDate(date) { return Math.floor(new Date(date).getTime() / 1000 ) } function getDateFromUnix(unix) { const padL = (nr, len = 2, chr = `0`) => `${nr}`.padStart(2, chr); let date = new Date(unix * 1000) let formatted = `${ date.getFullYear()}-${ padL(date.getMonth()+1)}-${ padL(date.getDate())}T${ padL(date.getHours())}:${ padL(date.getMinutes())}` return formatted; } $("#planning-form").submit(async function(event) { if(isThereAnyErrorInForm(event)) return; let planningModal = $("#planning-modal"); let action = planningModal.data("action"); let planningData = { label: $("#planning-label").val(), minimumPolice: parseInt($("#planning-min-police").val()), cargoRobberyId: parseInt(planningModal.data("cargoRobberyId")), data: { dateType: $("#planning-date-type").val(), date: getUnixFromDate( $("#planning-date").val() ), interval: parseInt( $("#planning-interval").val() ), } } switch(action) { case "create": { const response = await $.post(`https://${resName}/createPlanning`, JSON.stringify(planningData)); showServerResponse(response); if(response === true) { planningModal.modal("hide"); loadPlannings(); } break; } case "edit": { const response = await $.post(`https://${resName}/updatePlanning`, JSON.stringify({planningId: planningModal.data("planningId"), planningData: planningData})); showServerResponse(response); if(response === true) { planningModal.modal("hide"); loadPlannings(); } break; } } }) function editPlanning(id) { let planningData = plannings[id]; let planningsModal = $("#planning-modal"); planningsModal.data("action", "edit"); planningsModal.data("planningId", id); $("#delete-planning-btn").show(); $("#save-planning-btn").text( getLocalizedText("menu:save") ); $("#planning-label").val(planningData.label); $("#planning-min-police").val(planningData.minimumPolice); planningSetTargetRobbery(planningData.cargoRobberyId); $("#planning-date-type").val(planningData.data.dateType).change(); $("#planning-date").val( getDateFromUnix(planningData.data.date) ); $("#planning-interval").val(planningData.data.interval); planningsModal.modal("show"); } $("#delete-planning-btn").click(async function() { if(!await confirmDeletion()) return; let planningModal = $("#planning-modal"); let planningId = planningModal.data("planningId"); const response = await $.post(`https://${resName}/deletePlanning`, JSON.stringify({planningId: planningId})); showServerResponse(response); if(response === true) { planningModal.modal("hide"); loadPlannings(); } }) /* ███ ██ ██████ ██████ ███ ███ ██ ██ ██████ ██████ ██ ███ ██ ██████ ████ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ██ ████ ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██████ ██ ██ ██████ ██████ ██████ ██ ██ ████ ██████ */ function toggleNpcMugging() { let enableNpcMuggingDiv = $("#enable-npc-mugging") let enable = enableNpcMuggingDiv.prop("checked"); $("#npc-mugging-options").find("input, button").not(enableNpcMuggingDiv).prop("disabled", !enable); } $("#enable-npc-mugging").change(toggleNpcMugging); async function addRobbableObjectNpcMugging(object) { let robbableObjectDiv = $(`
`) robbableObjectDiv.find(".choose-btn").click(async function() { let objectType = robbableObjectDiv.find(".object-type").val(); let objectName = await objectDialog(objectType); robbableObjectDiv.find(".object-name").val(objectName); }).tooltip(); robbableObjectDiv.find(".remove-btn").click(function() { robbableObjectDiv.remove(); }) // Sets the object property if exist if(object) { robbableObjectDiv.find(".object-type").val(object.type); robbableObjectDiv.find(".object-name").val(object.name); robbableObjectDiv.find(".min-quantity").val(object.minQuantity); robbableObjectDiv.find(".max-quantity").val(object.maxQuantity); robbableObjectDiv.find(".chances").val(object.chances); } $("#npc-mugging-robbable-items").append(robbableObjectDiv); } $("#npc-mugging-add-object").click(function() { addRobbableObjectNpcMugging(); }); function getNpcMuggingRobbableObjects() { let robbableObjects = []; $("#npc-mugging-robbable-items").find(".robbable-object").each(function() { let currentObject = $(this); let object = { type: currentObject.find(".object-type").val(), name: currentObject.find(".object-name").val(), minQuantity: parseInt(currentObject.find(".min-quantity").val()), maxQuantity: parseInt(currentObject.find(".max-quantity").val()), chances: parseInt(currentObject.find(".chances").val()) } robbableObjects.push(object); }) return robbableObjects; } function setNpcMuggingRobbableObjects(objects) { $("#npc-mugging-robbable-items").empty(); objects.forEach(object => { addRobbableObjectNpcMugging(object); }); } $("#npc-mugging").submit(async function(event) { if(isThereAnyErrorInForm(event)) return; let clientSettings = { clNpcMugging: { canMakeFollow: $("#can-make-npc-to-follow").prop("checked"), cooldownOnMugging: parseInt( $("#npc-mugging-cooldown-on-mugging").val() ) } } let sharedSettings = { isNpcMuggingEnabled: $("#enable-npc-mugging").prop("checked"), secondsToMug: parseInt( $("#seconds-to-mug").val() ) } let serverSettings = { svNpcMugging: { robbableObjects: getNpcMuggingRobbableObjects(), minimumPolice: parseInt( $("#npc-mugging-minimum-police").val() ), probabilityPoliceAlert: parseInt( $("#npc-mugging-probability-police-alert").val() ), minimumObjectsAmount: parseInt( $("#npc-mugging-minimum-objects-amount").val() ), maximumObjectsAmount: parseInt( $("#npc-mugging-maximum-objects-amount").val() ), minutesAfterAutomaticallyRunAway: parseInt( $("#minutes-before-automatically-run-away").val() ), maxNPCsFollowing: parseInt( $("#npc-mugging-max-npcs-following").val() ) } } const response = await $.post(`https://${resName}/saveSettings`, JSON.stringify({ clientSettings: clientSettings, sharedSettings: sharedSettings, serverSettings: serverSettings, })); showServerResponse(response); });