Main/resources/[creator]/farming_creator/html/index.js
2025-06-07 08:51:21 +02:00

2715 lines
92 KiB
JavaScript

const resName = GetParentResourceName();
let hasDoorsCreator = null; // editing this is useless, don't do it
// Open/Close menu
function openMenu(version, fullConfig) {
$("#farming-creator-version").text(version);
loadSeeds();
loadFields();
loadFarms();
loadWorkbenches();
loadFoundries();
loadFormulas();
loadSettings(fullConfig);
$("#farming-creator").show()
}
function closeMenu() {
// Resets current active tab
$("#farming-creator").find(".nav-link, .tab-pane").each(function() {
if($(this).data("isDefault") == "1") {
$(this).addClass(["active", "show"])
} else {
$(this).removeClass(["active", "show"])
}
})
$("#farming-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;
}
}
});
/*
███████ ███████ ████████ ████████ ██ ███ ██ ██████ ███████
██ ██ ██ ██ ██ ████ ██ ██ ██
███████ █████ ██ ██ ██ ██ ██ ██ ██ ███ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
███████ ███████ ██ ██ ██ ██ ████ ██████ ███████
*/
/* Discord logs */
function toggleDiscordLogsInSettings(enable) {
$("#settings-mainDiscordWebhook").prop("disabled", !enable);
$("#settings-mainDiscordWebhook").prop("required", enable);
$("#settings-specific-webooks-div").find(`.form-control`).prop("disabled", !enable);
}
$("#settings-areDiscordLogsActive").change(function() {
let enabled = $(this).prop("checked");
toggleDiscordLogsInSettings(enabled);
})
function getSeparatedDiscordWebhooks() {
let webhooks = {};
$("#settings-specific-webooks-div").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-item-to-burn-plants-choose-item").click(async function() {
const itemName = await itemsDialog();
$("#settings-item-to-burn-plants-item-name").val(itemName);
})
$("#settings-burn-plants-animations-btn").click(async function() {
const oldAnimations = $("#settings-burn-plants-animations-btn").data("animationsData");
const newAnimations = await animationsDialog(oldAnimations || []);
$("#settings-burn-plants-animations-btn").data("animationsData", newAnimations);
})
function loadSettings(fullConfig) {
// Language
setTomSelectValue("#settings-locale", fullConfig.locale)
setTomSelectValue("#settings-targeting-script", fullConfig.targetingScript)
setTomSelectValue("#settings-help-notification-script", fullConfig.helpNotification)
// Generic
$("#settings-ace-permission").val(fullConfig.acePermission);
$("#settings-can-always-carry").prop("checked", fullConfig.canAlwaysCarryItem);
$("#settings-can-receive-multiple-same-item").prop("checked", fullConfig.canReceiveMultipleTimesTheSameItem);
$("#settings-menu-position").val(fullConfig.menuPosition);
$("#settings-targeting-script").val(fullConfig.targetingScript);
setSelectiveTargetingSettings(fullConfig.selectiveTargeting);
// Seeds
$("#settings-time-to-burn-plants").val(fullConfig.timeToBurnPlants);
$("#settings-minimum-distance-between-plants").val(fullConfig.minimumDistanceBetweenPlants);
$("#settings-burn-plants-animations-btn").data("animationsData", fullConfig.burnPlantsAnimations || []);
$("#settings-item-to-burn-plants-is-required").prop("checked", fullConfig.itemToBurnPlants.isRequired);
$("#settings-item-to-burn-plants-item-name").val(fullConfig.itemToBurnPlants.name);
$("#settings-item-to-burn-plants-minimum-quantity").val(fullConfig.itemToBurnPlants.minQuantity);
$("#settings-item-to-burn-plants-lose-on-use").prop("checked", fullConfig.itemToBurnPlants.loseOnUse);
// Farms
$("#settings-allow-afk-farming").prop("checked", fullConfig.allowAfkFarming);
// Foundries
$("#settings-allow-to-save-formulas").prop("checked", fullConfig.allowToSaveFormulas);
$("#settings-allow-afk-foundrying").prop("checked", fullConfig.allowAfkFoundrying);
// Discord logs
$("#settings-areDiscordLogsActive").prop("checked", fullConfig.areDiscordLogsActive);
$("#settings-mainDiscordWebhook").val(fullConfig.mainDiscordWebhook);
toggleDiscordLogsInSettings(fullConfig.areDiscordLogsActive);
for(const[logType, webhook] of Object.entries(fullConfig.specificWebhooks)) {
$("#settings-specific-webooks-div").find(`[data-log-type="${logType}"]`).val(webhook);
}
// Discord logs - END
}
function toggleSelectiveTargeting() {
const enabled = $("#settings-targeting-script").val() != "none";
$("#selective-targeting-container").find(".form-check-input").prop("disabled", !enabled);
}
function getSelectiveTargetingSettings() {
let selectiveTargeting = {};
$("#selective-targeting-container").find(".form-check-input").each(function(index, element) {
element = $(element);
let featureName = element.data("featureName");
let enabled = element.prop("checked");
selectiveTargeting[featureName] = enabled;
});
return selectiveTargeting;
}
function setSelectiveTargetingSettings(selectiveTargeting) {
$("#selective-targeting-container").find(".form-check-input").each(function(index, element) {
element = $(element);
let featureName = element.data("featureName");
let enabled = selectiveTargeting[featureName];
element.prop("checked", enabled);
});
toggleSelectiveTargeting();
}
$("#settings-targeting-script").change(function() {
toggleSelectiveTargeting();
})
$("#settings").submit(async function(event) {
if(isThereAnyErrorInForm(event)) return;
let clientSettings = {
// Generic
menuPosition: $("#settings-menu-position").val(),
targetingScript: $("#settings-targeting-script").val(),
helpNotification: $("#settings-help-notification-script").val(),
// Seeds
minimumDistanceBetweenPlants: parseFloat( $("#settings-minimum-distance-between-plants").val() ),
burnPlantsAnimations: $("#settings-burn-plants-animations-btn").data("animationsData"),
// Farms
allowAfkFarming: $("#settings-allow-afk-farming").prop("checked"),
selectiveTargeting: getSelectiveTargetingSettings()
}
let sharedSettings = {
locale: $("#settings-locale").val(),
timeToBurnPlants: parseInt( $("#settings-time-to-burn-plants").val() ),
allowToSaveFormulas: $("#settings-allow-to-save-formulas").prop("checked"),
allowAfkFoundrying: $("#settings-allow-afk-foundrying").prop("checked"),
}
let serverSettings = {
// Generic
acePermission: $("#settings-ace-permission").val(),
canAlwaysCarryItem: $("#settings-can-always-carry").prop("checked"),
canReceiveMultipleTimesTheSameItem: $("#settings-can-receive-multiple-same-item").prop("checked"),
// Seeds
itemToBurnPlants: {
isRequired: $("#settings-item-to-burn-plants-is-required").prop("checked"),
name: $("#settings-item-to-burn-plants-item-name").val(),
minQuantity: parseInt( $("#settings-item-to-burn-plants-minimum-quantity").val() ),
loseOnUse: $("#settings-item-to-burn-plants-lose-on-use").prop("checked"),
},
// Discord logs
areDiscordLogsActive: $("#settings-areDiscordLogsActive").prop("checked"),
mainDiscordWebhook: $("#settings-mainDiscordWebhook").val(),
specificWebhooks: getSeparatedDiscordWebhooks(),
}
const response = await $.post(`https://${resName}/saveSettings`, JSON.stringify({
clientSettings: clientSettings,
serverSettings: serverSettings,
sharedSettings: sharedSettings
}));
showServerResponse(response);
refreshTranslations(sharedSettings.locale);
});
/*
███████ ███████ ███████ ██████ ███████
██ ██ ██ ██ ██ ██
███████ █████ █████ ██ ██ ███████
██ ██ ██ ██ ██ ██
███████ ███████ ███████ ██████ ███████
*/
let seedsDatatable = $("#seeds-container").DataTable( {
"lengthMenu": [10, 15, 20],
"createdRow": function ( row, data, index ) {
$(row).addClass("clickable");
$(row).click(function() {
let id = parseInt( data[0] );
editSeed(id);
})
},
});
let seeds = {};
function loadSeeds() {
$.post(`https://${resName}/getAllSeeds`, {}, async function(rawSeeds) {
// Manually create the table to avoid incompatibilities due table indexing
seeds = {};
for(const[k, seedData] of Object.entries(rawSeeds)) {
seeds[seedData.id] = seedData;
}
seedsDatatable.clear();
for(const[id, seedData] of Object.entries(seeds)) {
seedsDatatable.row.add([
id,
seedData.label,
seedData.data.stages.length
]);
}
seedsDatatable.draw();
})
}
function setDefaultDataOfSeed() {
$("#seed-label").val("Default");
$("#seed-maximum-steepness").val(55);
$("#seed-minimum-free-space-above").val(3.0);
$("#seed-item-name").val("");
$("#seed-item-minimum-quantity").val(1);
$("#seed-item-lose-on-use-checkbox").prop("checked", true);
$("#seed-minimum-police").val(0);
let seedModal = $("#seed-modal");
seedModal.data("materialsOptions", getDefaultMaterialsOptions());
seedModal.data("plantingAnimations", [defaultPlantingAnimData]);
seedModal.data("markerData", getDefaultMarkerCustomization());
$("#seed-stages").empty();
}
$("#new-seed-btn").click(function() {
let seedModal = $("#seed-modal");
// Converts from edit modal to create modal
seedModal.data("action", "create");
$("#delete-seed-btn").hide();
$("#save-seed-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfSeed();
seedModal.modal("show");
})
$("#materials-options-btn").click(async function() {
let seedModal = $("#seed-modal");
const oldMaterials = seedModal.data("materialsOptions");
const newMaterials = await groundMaterialsDialog(oldMaterials);
seedModal.data("materialsOptions", newMaterials);
})
$("#seed-planting-animation-btn").click(async function() {
let seedModal = $("#seed-modal");
const oldAnimations = seedModal.data("plantingAnimations");
const newAnimations = await animationsDialog(oldAnimations);
seedModal.data("plantingAnimations", newAnimations);
});
$("#seed-customize-marker-btn").click(async function() {
let seedModal = $("#seed-modal");
const oldMarkerData = seedModal.data("markerData");
const newMarkerData = await markerDialog(oldMarkerData);
seedModal.data("markerData", newMarkerData);
});
$("#choose-seed-item-name-btn").click(async function() {
const itemName = await itemsDialog();
$("#seed-item-name").val(itemName);
})
function renameAllStagesByTheirOrder() {
$("#seed-stages").find(".stage-title").each(function(index, element) {
let stageNumber = index + 1;
$(this).prop("innerHTML", `${ getLocalizedText("menu:stage") } ${stageNumber}`)
});
}
async function addRequiredItemToStage(stageDiv, requiredItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 required-item justify-content-center">
<button type="button" class="btn-close delete-required-item-btn me-3" ></button>
<select class="form-select required-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control required-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating">
<input type="number" min=0 class="form-control required-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-check my-auto fs-4 ms-1">
<input class="form-check-input required-item-lose-on-use-checkbox" type="checkbox" value="">
<label class="form-check-label">${getLocalizedText("menu:lose_on_use")}</label>
</div>
</div>
`);
itemDiv.find(".delete-required-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".required-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".required-item-name").val(objectName);
}).tooltip();
if(requiredItem) {
itemDiv.find(".required-item-type").val(requiredItem.type);
itemDiv.find(".required-item-name").val(requiredItem.name);
itemDiv.find(".required-item-min-quantity").val(requiredItem.minQuantity);
itemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", requiredItem.loseOnUse);
}
stageDiv.find(".stage-required-items-list").append(itemDiv);
}
async function addRewardItemToStage(stageDiv, rewardItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 reward-item justify-content-center">
<button type="button" class="btn-close delete-reward-item-btn me-3" ></button>
<select class="form-select reward-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control reward-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-max-quantity" placeholder="${getLocalizedText("menu:max_quantity")}" required>
<label>${getLocalizedText("menu:max_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" class="form-control reward-item-chances" placeholder="${getLocalizedText("menu:probability")}" required>
<label>${getLocalizedText("menu:probability")}</label>
</div>
</div>
`);
itemDiv.find(".delete-reward-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".reward-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".reward-item-name").val(objectName);
}).tooltip();
if(rewardItem) {
itemDiv.find(".reward-item-type").val(rewardItem.type);
itemDiv.find(".reward-item-name").val(rewardItem.name);
itemDiv.find(".reward-item-min-quantity").val(rewardItem.minQuantity);
itemDiv.find(".reward-item-max-quantity").val(rewardItem.maxQuantity);
itemDiv.find(".reward-item-chances").val(rewardItem.chances);
}
stageDiv.find(".stage-reward-items-list").append(itemDiv);
}
function addSeedStage(stageData) {
const stageIndex = $("#seed-stages").children(".stage").length + 1;
let stageDiv = $(`
<div class="stage">
<h3 class="text-center stage-title">${getLocalizedText("menu:stage")} ${stageIndex}</h3>
<div class="d-flex gap-2 align-items-center justify-content-center mt-3">
<div class="form-floating text-body col-3">
<input type="text" class="form-control plant-model" placeholder="Plant model" required>
<label>${getLocalizedText("menu:plant_model")}</label>
</div>
<a class="btn btn-secondary clickable open-models-btn" target="_blank" onclick='window.invokeNative("openUrl", "https://forge.plebmasters.de/objects/")' data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:open_models_list") }"><i class="bi bi-images"></i></a>
<div class="form-floating text-body col-2 ms-3">
<input type="text" class="form-control stage-label" placeholder="Label" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:player_can_see_this") }" required>
<label>${getLocalizedText("menu:label")}</label>
</div>
<div class="form-floating text-body col-2">
<input type="number" class="form-control stage-duration" placeholder="Duration" min="1" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:stage_duration_description") }" required>
<label>${getLocalizedText("menu:duration_minutes")}</label>
</div>
<div class="form-floating text-body col-2">
<input type="number" class="form-control stage-minutes-before-death" placeholder="Duration" min="1" value="60" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:minutes_before_death_description") }" required>
<label>${getLocalizedText("menu:minutes_before_death")}</label>
</div>
<button type="button" class="btn btn-secondary mx-3 seed-stage-end-animation-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:stage_end_animation_description") }">${getLocalizedText("menu:stage_end_animation")}</button>
</div>
<h3 class="text-center mt-5">${getLocalizedText("menu:on_stage_end")}</h3>
<div>
<p class="text-center fs-4">${getLocalizedText("menu:required_items")}</p>
<div class="stage-required-items-list">
</div>
<button type="button" class="btn btn-secondary stage-add-required-item-btn">${getLocalizedText("menu:add_item")}</button>
</div>
<div>
<p class="text-center fs-4">${getLocalizedText("menu:items_to_give")}</p>
<div class="my-4 row g-2 row-cols-auto align-items-center justify-content-center">
<p class="text-center fs-4 my-auto me-3">${ getLocalizedText("menu:amount_of_objects_as_reward") }</p>
<div class="form-floating text-body col-3">
<input type="number" class="form-control min-objects-amount" placeholder="Minimum" required>
<label>${ getLocalizedText("menu:min_quantity") }</label>
</div>
<div class="form-floating text-body col-3">
<input type="number" class="form-control max-objects-amount" placeholder="Maximum" required>
<label>${ getLocalizedText("menu:max_quantity") }</label>
</div>
</div>
<div class="stage-reward-items-list">
</div>
<button type="button" class="btn btn-secondary stage-add-reward-item-btn">${getLocalizedText("menu:add_item")}</button>
</div>
<div class="d-inline-block col-12 mt-1">
<button type="button" class="btn btn-warning btn-sm float-end delete-stage-btn">${getLocalizedText("menu:delete_stage")}</button>
</div>
<hr class="thick-hr">
</div>
`);
stageDiv.find("[data-bs-toggle='tooltip']").tooltip();
stageDiv.find(".delete-stage-btn").click(function() {
stageDiv.remove();
renameAllStagesByTheirOrder();
});
stageDiv.find(".stage-add-required-item-btn").click(function() {
addRequiredItemToStage(stageDiv);
});
stageDiv.find(".stage-add-reward-item-btn").click(function() {
addRewardItemToStage(stageDiv);
});
// Default interaction animation in case there isn't any
stageDiv.data("stageEndAnimations", [defaultPlantInteractionAnimData]);
stageDiv.find(".seed-stage-end-animation-btn").click(async function() {
const oldAnimations = stageDiv.data("stageEndAnimations");
const newAnimations = await animationsDialog(oldAnimations);
stageDiv.data("stageEndAnimations", newAnimations);
});
if(stageData) {
stageDiv.find(".plant-model").val(stageData.plantModel);
stageDiv.find(".stage-label").val(stageData.label);
stageDiv.find(".stage-duration").val(stageData.duration);
stageDiv.find(".stage-minutes-before-death").val(stageData.minutesBeforeDeath);
stageDiv.find(".min-objects-amount").val(stageData.minObjectsAmount);
stageDiv.find(".max-objects-amount").val(stageData.maxObjectsAmount);
stageDiv.data("stageEndAnimations", stageData.stageEndAnimations);
for(let requiredItem of stageData.requiredItems) {
addRequiredItemToStage(stageDiv, requiredItem);
}
for(let rewardItem of stageData.rewardItems) {
addRewardItemToStage(stageDiv, rewardItem);
}
} else {
addRequiredItemToStage(stageDiv);
addRewardItemToStage(stageDiv);
// If it's not the first stage, the model will be copied from the stage before
if(stageIndex > 1) {
const model = $("#seed-stages").children(".stage").last().find(".plant-model").val();
stageDiv.find(".plant-model").val(model);
}
}
$("#seed-stages").append(stageDiv);
}
$("#add-seed-stage-btn").click(function() {
addSeedStage();
})
function editSeed(id) {
let seedModal = $("#seed-modal");
// Converts from create modal to edit modal
seedModal.data("action", "edit");
seedModal.data("seedId", id);
$("#delete-seed-btn").show();
$("#save-seed-btn").text( getLocalizedText("menu:save") );
const seedInfo = seeds[id];
const seedData = seedInfo.data;
$("#seed-label").val(seedInfo.label);
$("#seed-maximum-steepness").val(seedData.maximumSteepness);
$("#seed-minimum-free-space-above").val(seedData.minimumFreeSpaceAbove);
$("#seed-item-name").val(seedData.seedItemName);
$("#seed-item-minimum-quantity").val(seedData.seedItemMinimumQuantity);
$("#seed-item-lose-on-use-checkbox").prop("checked", seedData.seedItemLoseOnUse);
$("#seed-minimum-police").val(seedData.minimumPolice);
seedModal.data("materialsOptions", seedData.materialsOptions);
seedModal.data("plantingAnimations", seedData.plantingAnimations || [defaultPlantingAnimData]);
seedModal.data("markerData", seedData.markerData || getDefaultMarkerCustomization());
$("#seed-stages").empty();
if(seedData.stages) {
for(const[stage, stageData] of Object.entries(seedData.stages)) {
addSeedStage(stageData);
}
}
seedModal.modal("show");
}
function getRequiredItemFromStageDiv(stageDiv) {
let requiredItems = [];
stageDiv.find(".stage-required-items-list").find(".required-item").each(function() {
const itemData = {
type: $(this).find(".required-item-type").val(),
name: $(this).find(".required-item-name").val(),
minQuantity: parseInt( $(this).find(".required-item-min-quantity").val() ),
loseOnUse: $(this).find(".required-item-lose-on-use-checkbox").prop("checked")
}
requiredItems.push(itemData);
});
return requiredItems;
}
function getRewardItemFromStageDiv(stageDiv) {
let rewardItems = [];
stageDiv.find(".stage-reward-items-list").find(".reward-item").each(function() {
const itemData = {
type: $(this).find(".reward-item-type").val(),
name: $(this).find(".reward-item-name").val(),
minQuantity: parseInt( $(this).find(".reward-item-min-quantity").val() ),
maxQuantity: parseInt( $(this).find(".reward-item-max-quantity").val() ),
chances: parseInt( $(this).find(".reward-item-chances").val() ),
}
rewardItems.push(itemData);
});
return rewardItems;
}
function getSeedStages() {
let stages = [];
$("#seed-stages").find(".stage").each(function() {
let stage = {
plantModel: $(this).find(".plant-model").val(),
label: $(this).find(".stage-label").val(),
duration: parseInt( $(this).find(".stage-duration").val() ),
minutesBeforeDeath: parseInt( $(this).find(".stage-minutes-before-death").val() ),
stageEndAnimations: $(this).data("stageEndAnimations"),
requiredItems: getRequiredItemFromStageDiv( $(this) ),
minObjectsAmount: parseInt( $(this).find(".min-objects-amount").val() ),
maxObjectsAmount: parseInt( $(this).find(".max-objects-amount").val() ),
rewardItems: getRewardItemFromStageDiv( $(this) ),
};
stages.push(stage);
});
return stages;
}
$("#seed-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let seedModal = $("#seed-modal");
let action = seedModal.data("action");
let seedData = {
label: $("#seed-label").val(),
data: {
maximumSteepness: parseInt( $("#seed-maximum-steepness").val() ),
minimumFreeSpaceAbove: parseFloat( $("#seed-minimum-free-space-above").val() ),
materialsOptions: seedModal.data("materialsOptions"),
plantingAnimations: seedModal.data("plantingAnimations") || [defaultPlantingAnimData],
markerData: seedModal.data("markerData"),
seedItemName: $("#seed-item-name").val(),
seedItemMinimumQuantity: parseInt( $("#seed-item-minimum-quantity").val() ),
seedItemLoseOnUse: $("#seed-item-lose-on-use-checkbox").prop("checked"),
minimumPolice: parseInt( $("#seed-minimum-police").val() ),
stages: getSeedStages()
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createSeed`, JSON.stringify(seedData), function(isSuccessful) {
if(isSuccessful) {
seedModal.modal("hide");
loadSeeds();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateSeed`, JSON.stringify({seedId: seedModal.data("seedId"), seedData: seedData}), function(isSuccessful) {
if(isSuccessful) {
seedModal.modal("hide");
loadSeeds();
}
});
break;
}
}
})
$("#delete-seed-btn").click(function() {
let seedModal = $("#seed-modal");
let seedId = seedModal.data("seedId");
$.post(`https://${resName}/deleteSeed`, JSON.stringify({seedId: seedId}), function(isSuccessful) {
if(isSuccessful) {
seedModal.modal("hide");
loadSeeds();
}
});
});
/*
███████ ██ ███████ ██ ██████ ███████
██ ██ ██ ██ ██ ██ ██
█████ ██ █████ ██ ██ ██ ███████
██ ██ ██ ██ ██ ██ ██
██ ██ ███████ ███████ ██████ ███████
*/
let fieldsDatatable = $("#fields-container").DataTable( {
"lengthMenu": [10, 15, 20],
"createdRow": function ( row, data, index ) {
$(row).addClass("clickable");
$(row).click(function() {
let id = parseInt( data[0] );
editField(id);
})
},
});
let fields = {};
async function getCountOfObjectsForFieldId(id) {
return new Promise(function(resolve) {
$.post(`https://${resName}/getCountOfObjectsForFieldId`, JSON.stringify({fieldId: parseInt(id)}), function(count) {
resolve(count);
});
});
}
function loadFields() {
$.post(`https://${resName}/getAllFields`, {}, async function(rawFields) {
// Manually create the table to avoid incompatibilities due table indexing
fields = {};
for(const[k, fieldData] of Object.entries(rawFields)) {
fields[fieldData.id] = fieldData;
}
fieldsDatatable.clear();
for(const[id, fieldData] of Object.entries(fields)) {
fieldsDatatable.row.add([
id,
fieldData.label,
fieldData.data.radius,
await getCountOfObjectsForFieldId(id),
]);
}
fieldsDatatable.draw();
})
}
function setDefaultDataOfField() {
$("#field-label").val("Default");
$("#field-object-model").val("");
$("#field-radius").val(30.0);
$("#field-minimum-police").val(0);
$("#field-max-objects").val(30);
$("#field-respawn-timer").val(15);
$("#field-coords-x").val("");
$("#field-coords-y").val("");
$("#field-coords-z").val("");
$("#field-reward-min-objects-amount").val(1);
$("#field-reward-max-objects-amount").val(1);
$("#field-required-items-list").empty();
$("#field-reward-items-list").empty();
$("#field-modal").find("input:radio[name='field-spawn-coords-type'][value='automatic']").prop("checked", true).change();
let fieldModal = $("#field-modal");
fieldModal.data("animations", [defaultPlantInteractionAnimData]);
fieldModal.data("blipData", getDefaultBlipCustomization());
fieldModal.data("allowedJobs", null);
fieldModal.data("availableSpawnPoints", null);
}
$("#new-field-btn").click(function() {
let fieldModal = $("#field-modal");
// Converts from edit modal to create modal
fieldModal.data("action", "create");
$("#delete-field-btn").hide();
$("#save-field-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfField();
fieldModal.modal("show");
})
$("#field-animations-btn").click(async function() {
let fieldModal = $("#field-modal");
let oldAnimations = fieldModal.data("animations");
let newAnimations = await animationsDialog(oldAnimations);
fieldModal.data("animations", newAnimations);
})
$("#field-customize-blip-btn").click(async function() {
let fieldModal = $("#field-modal");
let oldBlipData = fieldModal.data("blipData");
let newBlipData = await blipDialog(oldBlipData);
fieldModal.data("blipData", newBlipData);
})
$("#field-allowed-jobs-btn").click(async function() {
let fieldModal = $("#field-modal");
let oldAllowedJobs = fieldModal.data("allowedJobs");
let newAllowedJobs = await jobsDialog(oldAllowedJobs);
fieldModal.data("allowedJobs", newAllowedJobs);
})
$("#field-current-coords-btn").click(async function() {
const coords = await getCurrentCoords();
$("#field-coords-x").val(coords.x);
$("#field-coords-y").val(coords.y);
$("#field-coords-z").val(coords.z);
})
$("input:radio[name='field-spawn-coords-type']").change(function() {
const spawnType = $(this).val();
$("#field-modal").data("availableSpawnPoints", null);
$("#field-choose-allowed-spawn-coordinates-btn").toggle(spawnType == "manual");
})
$("#field-choose-allowed-spawn-coordinates-btn").click(async function() {
let fieldModal = $("#field-modal");
fieldModal.modal("hide");
$("#farming-creator").hide();
$.post(`https://${resName}/chooseAvailableSpawnpoints`, JSON.stringify({
coords: {
x: parseFloat( $("#field-coords-x").val() ),
y: parseFloat( $("#field-coords-y").val() ),
z: parseFloat( $("#field-coords-z").val() ),
},
radius: parseFloat( $("#field-radius").val() ),
}), async function(availableSpawnPoints) {
if(availableSpawnPoints) {
$("#field-modal").data("availableSpawnPoints", availableSpawnPoints);
}
$("#farming-creator").show();
fieldModal.modal("show");
});
});
async function addRequiredItemToField(requiredItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 required-item justify-content-center">
<button type="button" class="btn-close delete-required-item-btn me-3" ></button>
<select class="form-select required-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control required-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating">
<input type="number" min=0 class="form-control required-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-check my-auto fs-4 ms-1">
<input class="form-check-input required-item-lose-on-use-checkbox" type="checkbox" value="">
<label class="form-check-label">${getLocalizedText("menu:lose_on_use")}</label>
</div>
</div>
`);
itemDiv.find(".delete-required-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".required-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".required-item-name").val(objectName);
}).tooltip();
if(requiredItem) {
itemDiv.find(".required-item-type").val(requiredItem.type);
itemDiv.find(".required-item-name").val(requiredItem.name);
itemDiv.find(".required-item-min-quantity").val(requiredItem.minQuantity);
itemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", requiredItem.loseOnUse);
}
$("#field-required-items-list").append(itemDiv);
}
$("#field-add-required-item-btn").click(function() {
addRequiredItemToField();
});
async function addRewardItemToField(rewardItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 reward-item justify-content-center">
<button type="button" class="btn-close delete-reward-item-btn me-3" ></button>
<select class="form-select reward-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control reward-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-max-quantity" placeholder="${getLocalizedText("menu:max_quantity")}" required>
<label>${getLocalizedText("menu:max_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" class="form-control reward-item-chances" placeholder="${getLocalizedText("menu:probability")}" required>
<label>${getLocalizedText("menu:probability")}</label>
</div>
</div>
`);
itemDiv.find(".delete-reward-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".reward-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".reward-item-name").val(objectName);
}).tooltip();
if(rewardItem) {
itemDiv.find(".reward-item-type").val(rewardItem.type);
itemDiv.find(".reward-item-name").val(rewardItem.name);
itemDiv.find(".reward-item-min-quantity").val(rewardItem.minQuantity);
itemDiv.find(".reward-item-max-quantity").val(rewardItem.maxQuantity);
itemDiv.find(".reward-item-chances").val(rewardItem.chances);
}
$("#field-reward-items-list").append(itemDiv);
}
$("#field-add-reward-item-btn").click(function() {
addRewardItemToField();
})
function editField(id) {
let fieldModal = $("#field-modal");
// Converts from create modal to edit modal
fieldModal.data("action", "edit");
fieldModal.data("fieldId", id);
$("#delete-field-btn").show();
$("#save-field-btn").text( getLocalizedText("menu:save") );
let fieldData = fields[id];
$("#field-label").val(fieldData.label);
$("#field-object-model").val(fieldData.data.objectModel);
$("#field-radius").val(fieldData.data.radius);
$("#field-max-objects").val(fieldData.data.maxObjects);
$("#field-respawn-timer").val(fieldData.data.respawnTimer);
$("#field-minimum-police").val(fieldData.data.minimumPolice);
$("#field-modal").find("input:radio[name='field-spawn-coords-type'][value='" + fieldData.data.spawnType + "']").prop("checked", true).change();
$("#field-coords-x").val(fieldData.data.coords.x);
$("#field-coords-y").val(fieldData.data.coords.y);
$("#field-coords-z").val(fieldData.data.coords.z);
$("#field-reward-min-objects-amount").val(fieldData.data.minObjectsAmount);
$("#field-reward-max-objects-amount").val(fieldData.data.maxObjectsAmount);
$("#field-required-items-list").empty();
if(fieldData.data.requiredItems) {
for(let requiredItem of fieldData.data.requiredItems) {
addRequiredItemToField(requiredItem);
}
}
$("#field-reward-items-list").empty();
if(fieldData.data.rewardItems) {
for(let rewardItem of fieldData.data.rewardItems) {
addRewardItemToField(rewardItem);
}
}
fieldModal.data("animations", fieldData.data.animations);
fieldModal.data("blipData", fieldData.data.blipData);
fieldModal.data("allowedJobs", fieldData.data.allowedJobs || null);
fieldModal.data("availableSpawnPoints", fieldData.data.availableSpawnPoints);
fieldModal.modal("show");
}
function getRewardItemsFromField() {
let rewardItems = [];
$("#field-reward-items-list").find(".reward-item").each(function() {
let rewardItem = {
type: $(this).find(".reward-item-type").val(),
name: $(this).find(".reward-item-name").val(),
minQuantity: parseInt( $(this).find(".reward-item-min-quantity").val() ),
maxQuantity: parseInt( $(this).find(".reward-item-max-quantity").val() ),
chances: parseInt( $(this).find(".reward-item-chances").val() )
}
rewardItems.push(rewardItem);
});
return rewardItems;
}
function getRequiredItemsFromField() {
let requiredItems = [];
$("#field-required-items-list").find(".required-item").each(function() {
let requiredItem = {
type: $(this).find(".required-item-type").val(),
name: $(this).find(".required-item-name").val(),
minQuantity: parseInt( $(this).find(".required-item-min-quantity").val() ),
loseOnUse: $(this).find(".required-item-lose-on-use-checkbox").prop("checked")
}
requiredItems.push(requiredItem);
});
return requiredItems;
}
$("#field-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let fieldModal = $("#field-modal");
let action = fieldModal.data("action");
let fieldData = {
label: $("#field-label").val(),
data: {
objectModel: $("#field-object-model").val(),
radius: parseFloat( $("#field-radius").val() ),
maxObjects: parseInt( $("#field-max-objects").val() ), // Prop objects that can be spawned
respawnTimer: parseInt( $("#field-respawn-timer").val() ),
minimumPolice: parseInt( $("#field-minimum-police").val() ),
animations: fieldModal.data("animations"),
blipData: fieldModal.data("blipData") || [getDefaultBlipCustomization()],
allowedJobs: fieldModal.data("allowedJobs" || null),
coords: {
x: parseFloat( $("#field-coords-x").val() ),
y: parseFloat( $("#field-coords-y").val() ),
z: parseFloat( $("#field-coords-z").val() ),
},
spawnType: $("input:radio[name='field-spawn-coords-type']:checked").val(),
availableSpawnPoints: fieldModal.data("availableSpawnPoints"),
minObjectsAmount: parseInt( $("#field-reward-min-objects-amount").val() ),
maxObjectsAmount: parseInt( $("#field-reward-max-objects-amount").val() ),
rewardItems: getRewardItemsFromField(),
requiredItems: getRequiredItemsFromField(),
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createField`, JSON.stringify(fieldData), function(isSuccessful) {
if(isSuccessful) {
fieldModal.modal("hide");
loadFields();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateField`, JSON.stringify({fieldId: fieldModal.data("fieldId"), fieldData: fieldData}), function(isSuccessful) {
if(isSuccessful) {
fieldModal.modal("hide");
loadFields();
}
});
break;
}
}
})
$("#delete-field-btn").click(function() {
let fieldModal = $("#field-modal");
let fieldId = fieldModal.data("fieldId");
$.post(`https://${resName}/deleteField`, JSON.stringify({fieldId: fieldId}), function(isSuccessful) {
if(isSuccessful) {
fieldModal.modal("hide");
loadFields();
}
});
});
/*
███████ █████ ██████ ███ ███ ███████
██ ██ ██ ██ ██ ████ ████ ██
█████ ███████ ██████ ██ ████ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ███████
*/
let farmsDatatable = $("#farms-container").DataTable( {
"lengthMenu": [10, 15, 20],
"createdRow": function ( row, data, index ) {
$(row).addClass("clickable");
$(row).click(function() {
let id = parseInt( data[0] );
editFarm(id);
})
},
});
let farms = {};
function loadFarms() {
$.post(`https://${resName}/getAllFarms`, {}, async function(rawFarms) {
// Manually create the table to avoid incompatibilities due table indexing
farms = {};
for(const[k, farmData] of Object.entries(rawFarms)) {
farms[farmData.id] = farmData;
}
farmsDatatable.clear();
for(const[id, farmData] of Object.entries(farms)) {
farmsDatatable.row.add([
id,
farmData.label,
]);
}
farmsDatatable.draw();
})
}
function setDefaultDataOfFarm() {
// Generic
$("#farm-label").val("Default");
$("#farm-minimum-police").val(0);
$("#farm-radius").val(5);
// Options
$("#farm-always-active").prop("checked", true).change();
$("#farm-requires-to-be-in-vehicle").prop("checked", false).change();
$("#farm-allowed-vehicles-list").empty();
// Coordinates
$("#farm-coords-x").val("");
$("#farm-coords-y").val("");
$("#farm-coords-z").val("");
// Items
$("#farm-reward-min-objects-amount").val(1);
$("#farm-reward-max-objects-amount").val(1);
$("#farm-required-items-list").empty();
$("#farm-reward-items-list").empty();
// Other
let farmModal = $("#farm-modal");
farmModal.data("animations", [defaultPlantInteractionAnimData]);
farmModal.data("blipData", getDefaultBlipCustomizationForFarms());
farmModal.data("markerData", getDefaultMarkerCustomization());
farmModal.data("objectData", getDefaultObjectCustomization());
farmModal.data("allowedJobs", null);
}
$("#new-farm-btn").click(function() {
let farmModal = $("#farm-modal");
// Converts from edit modal to create modal
farmModal.data("action", "create");
$("#delete-farm-btn").hide();
$("#save-farm-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfFarm();
farmModal.modal("show");
});
$("#farm-animations-btn").click(async function() {
let farmModal = $("#farm-modal");
let oldAnimations = farmModal.data("animations");
let newAnimations = await animationsDialog(oldAnimations);
farmModal.data("animations", newAnimations);
})
$("#farm-customize-blip-btn").click(async function() {
let farmModal = $("#farm-modal");
let oldBlipData = farmModal.data("blipData");
let newBlipData = await blipDialog(oldBlipData);
farmModal.data("blipData", newBlipData);
})
$("#farm-customize-marker-btn").click(async function() {
let farmModal = $("#farm-modal");
let oldMarkerData = farmModal.data("markerData");
let newMarkerData = await markerDialog(oldMarkerData);
farmModal.data("markerData", newMarkerData);
})
$("#farm-customize-object-btn").click(async function() {
let farmModal = $("#farm-modal");
let oldObjectData = farmModal.data("objectData");
let newObjectData = await objectCustomizationDialog(oldObjectData);
farmModal.data("objectData", newObjectData);
});
$("#farm-allowed-jobs-btn").click(async function() {
let farmModal = $("#farm-modal");
let oldAllowedJobs = farmModal.data("allowedJobs");
let newAllowedJobs = await jobsDialog(oldAllowedJobs);
farmModal.data("allowedJobs", newAllowedJobs);
})
$("#farm-current-coords-btn").click(async function() {
const coords = await getCurrentCoords();
$("#farm-coords-x").val(coords.x);
$("#farm-coords-y").val(coords.y);
$("#farm-coords-z").val(coords.z);
})
$("#farm-always-active").change(function() {
let isChecked = $(this).prop("checked");
$("#farm-active-start-time").prop("disabled", isChecked);
$("#farm-active-end-time").prop("disabled", isChecked);
if (isChecked) {
$("#farm-active-start-time").val("00:00");
$("#farm-active-end-time").val("23:59");
}
});
$("#farm-requires-to-be-in-vehicle").change(function() {
const isChecked = $(this).prop("checked");
$("#farm-requires-specific-vehicle").prop("disabled", !isChecked);
if (!isChecked) {
$("#farm-requires-specific-vehicle").prop("checked", false).change();
}
})
$("#farm-requires-specific-vehicle").change(function() {
const isChecked = $(this).prop("checked");
$("#farm-allowed-vehicles-div").toggle(isChecked);
})
async function addRequiredItemToFarm(requiredItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 required-item justify-content-center">
<button type="button" class="btn-close delete-required-item-btn me-3" ></button>
<select class="form-select required-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control required-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating">
<input type="number" min=0 class="form-control required-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-check my-auto fs-4 ms-1">
<input class="form-check-input required-item-lose-on-use-checkbox" type="checkbox" value="">
<label class="form-check-label">${getLocalizedText("menu:lose_on_use")}</label>
</div>
</div>
`);
itemDiv.find(".delete-required-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".required-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".required-item-name").val(objectName);
}).tooltip();
if(requiredItem) {
itemDiv.find(".required-item-type").val(requiredItem.type);
itemDiv.find(".required-item-name").val(requiredItem.name);
itemDiv.find(".required-item-min-quantity").val(requiredItem.minQuantity);
itemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", requiredItem.loseOnUse);
}
$("#farm-required-items-list").append(itemDiv);
}
$("#farm-add-required-item-btn").click(function() {
addRequiredItemToFarm();
});
async function addRewardItemToFarm(rewardItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 reward-item justify-content-center">
<button type="button" class="btn-close delete-reward-item-btn me-3" ></button>
<select class="form-select reward-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control reward-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-max-quantity" placeholder="${getLocalizedText("menu:max_quantity")}" required>
<label>${getLocalizedText("menu:max_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" class="form-control reward-item-chances" placeholder="${getLocalizedText("menu:probability")}" required>
<label>${getLocalizedText("menu:probability")}</label>
</div>
</div>
`);
itemDiv.find(".delete-reward-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".reward-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".reward-item-name").val(objectName);
}).tooltip();
if(rewardItem) {
itemDiv.find(".reward-item-type").val(rewardItem.type);
itemDiv.find(".reward-item-name").val(rewardItem.name);
itemDiv.find(".reward-item-min-quantity").val(rewardItem.minQuantity);
itemDiv.find(".reward-item-max-quantity").val(rewardItem.maxQuantity);
itemDiv.find(".reward-item-chances").val(rewardItem.chances);
}
$("#farm-reward-items-list").append(itemDiv);
}
$("#farm-add-reward-item-btn").click(function() {
addRewardItemToFarm();
});
function addAllowedVehicleToFarm(vehicleName) {
let allowedVehicleDiv = $(`
<ul class="row g-2 row-cols-auto align-items-center justify-content-center allowed-vehicle mb-2">
<button type="button" class="btn-close delete-allowed-vehicle-btn" ></button>
<div class="form-floating">
<input type="text" class="form-control vehicle-spawn-name" placeholder="Vehicle name" required>
<label>${ getLocalizedText("menu:vehicle_name") }</label>
</div>
</ul>
`);
allowedVehicleDiv.find(".delete-allowed-vehicle-btn").click(function() {
allowedVehicleDiv.remove();
});
if(vehicleName) {
allowedVehicleDiv.find(".vehicle-spawn-name").val(vehicleName);
}
$("#farm-allowed-vehicles-list").append(allowedVehicleDiv);
}
$("#farm-add-farm-allowed-vehicle-btn").click(function() {
addAllowedVehicleToFarm();
});
function editFarm(id) {
let farmModal = $("#farm-modal");
// Converts from create modal to edit modal
farmModal.data("action", "edit");
farmModal.data("farmId", id);
$("#delete-farm-btn").show();
$("#save-farm-btn").text( getLocalizedText("menu:save") );
let farmData = farms[id];
// Generic
$("#farm-label").val(farmData.label);
$("#farm-minimum-police").val(farmData.data.minimumPolice);
$("#farm-radius").val(farmData.data.radius);
// Coordinates
$("#farm-coords-x").val(farmData.data.coords.x);
$("#farm-coords-y").val(farmData.data.coords.y);
$("#farm-coords-z").val(farmData.data.coords.z);
// Options
$("#farm-active-start-time").val(farmData.data.activeTimeStart);
$("#farm-active-end-time").val(farmData.data.activeTimeEnd);
$("#farm-requires-to-be-in-vehicle").prop("checked", farmData.data.requiresToBeInVehicle).change();
$("#farm-requires-specific-vehicle").prop("checked", farmData.data.requiresSpecificVehicle).change();
$("#farm-allowed-vehicles-list").empty();
if(farmData.data.allowedVehicles) {
for(const vehicleName of Object.keys(farmData.data.allowedVehicles)) {
addAllowedVehicleToFarm(vehicleName);
}
}
if(farmData.data.activeTimeStart === "00:00" && farmData.data.activeTimeEnd === "23:59") {
$("#farm-always-active").prop("checked", true).change();
} else {
$("#farm-always-active").prop("checked", false).change();
}
// Items
$("#farm-reward-min-objects-amount").val(farmData.data.minObjectsAmount);
$("#farm-reward-max-objects-amount").val(farmData.data.maxObjectsAmount);
$("#farm-required-items-list").empty();
if(farmData.data.requiredItems) {
for(let requiredItem of farmData.data.requiredItems) {
addRequiredItemToFarm(requiredItem);
}
}
$("#farm-reward-items-list").empty();
if(farmData.data.rewardItems) {
for(let rewardItem of farmData.data.rewardItems) {
addRewardItemToFarm(rewardItem);
}
}
farmModal.data("animations", farmData.data.animations);
farmModal.data("blipData", farmData.data.blipData);
farmModal.data("markerData", farmData.data.markerData);
farmModal.data("objectData", farmData.data.objectData);
farmModal.data("allowedJobs", farmData.data.allowedJobs || null);
farmModal.modal("show");
}
function getRewardItemsFromFarm() {
let rewardItems = [];
$("#farm-reward-items-list").find(".reward-item").each(function() {
let rewardItem = {
type: $(this).find(".reward-item-type").val(),
name: $(this).find(".reward-item-name").val(),
minQuantity: parseInt( $(this).find(".reward-item-min-quantity").val() ),
maxQuantity: parseInt( $(this).find(".reward-item-max-quantity").val() ),
chances: parseInt( $(this).find(".reward-item-chances").val() )
}
rewardItems.push(rewardItem);
});
return rewardItems;
}
function getRequiredItemsFromFarm() {
let requiredItems = [];
$("#farm-required-items-list").find(".required-item").each(function() {
let requiredItem = {
type: $(this).find(".required-item-type").val(),
name: $(this).find(".required-item-name").val(),
minQuantity: parseInt( $(this).find(".required-item-min-quantity").val() ),
loseOnUse: $(this).find(".required-item-lose-on-use-checkbox").prop("checked")
}
requiredItems.push(requiredItem);
});
return requiredItems;
}
function getFarmAllowedVehicles() {
let allowedVehicles = {};
$("#farm-allowed-vehicles-list").find(".allowed-vehicle").each(function() {
let vehicleName = $(this).find(".vehicle-spawn-name").val();
allowedVehicles[vehicleName] = true;
});
return allowedVehicles;
}
$("#farm-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let farmModal = $("#farm-modal");
let action = farmModal.data("action");
let farmData = {
label: $("#farm-label").val(),
data: {
minimumPolice: parseInt( $("#farm-minimum-police").val() ),
radius: parseFloat( $("#farm-radius").val() ),
animations: farmModal.data("animations"),
blipData: farmModal.data("blipData") || [getDefaultBlipCustomization()],
markerData: farmModal.data("markerData") || [getDefaultMarkerCustomization()],
objectData: farmModal.data("objectData") || [getDefaultObjectCustomization()],
allowedJobs: farmModal.data("allowedJobs" || null),
coords: {
x: parseFloat( $("#farm-coords-x").val() ),
y: parseFloat( $("#farm-coords-y").val() ),
z: parseFloat( $("#farm-coords-z").val() ),
},
minObjectsAmount: parseInt( $("#farm-reward-min-objects-amount").val() ),
maxObjectsAmount: parseInt( $("#farm-reward-max-objects-amount").val() ),
rewardItems: getRewardItemsFromFarm(),
requiredItems: getRequiredItemsFromFarm(),
activeTimeStart: $("#farm-active-start-time").val(),
activeTimeEnd: $("#farm-active-end-time").val(),
requiresToBeInVehicle: $("#farm-requires-to-be-in-vehicle").prop("checked"),
requiresSpecificVehicle: $("#farm-requires-specific-vehicle").prop("checked"),
allowedVehicles: getFarmAllowedVehicles()
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createFarm`, JSON.stringify(farmData), function(isSuccessful) {
if(isSuccessful) {
farmModal.modal("hide");
loadFarms();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateFarm`, JSON.stringify({farmId: farmModal.data("farmId"), farmData: farmData}), function(isSuccessful) {
if(isSuccessful) {
farmModal.modal("hide");
loadFarms();
}
});
break;
}
}
})
$("#delete-farm-btn").click(function() {
let farmModal = $("#farm-modal");
let farmId = farmModal.data("farmId");
$.post(`https://${resName}/deleteFarm`, JSON.stringify({farmId: farmId}), function(isSuccessful) {
if(isSuccessful) {
farmModal.modal("hide");
loadFarms();
}
});
});
/*
██ ██ ██████ ██████ ██ ██ ██████ ███████ ███ ██ ██████ ██ ██ ███████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██
██ █ ██ ██ ██ ██████ █████ ██████ █████ ██ ██ ██ ██ ███████ █████ ███████
██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
███ ███ ██████ ██ ██ ██ ██ ██████ ███████ ██ ████ ██████ ██ ██ ███████ ███████
*/
let workbenchesDatatable = $("#workbenches-container").DataTable( {
"lengthMenu": [10, 15, 20],
"createdRow": function ( row, data, index ) {
$(row).addClass("clickable");
$(row).click(function() {
let id = parseInt( data[0] );
editWorkbench(id);
})
},
});
let workbenches = {};
function loadWorkbenches() {
$.post(`https://${resName}/getAllWorkbenches`, {}, async function(rawWorkbenches) {
// Manually create the table to avoid incompatibilities due table indexing
workbenches = {};
for(const[k, workbenchData] of Object.entries(rawWorkbenches)) {
workbenches[workbenchData.id] = workbenchData;
}
workbenchesDatatable.clear();
for(const[id, workbenchData] of Object.entries(workbenches)) {
workbenchesDatatable.row.add([
id,
workbenchData.label,
]);
}
workbenchesDatatable.draw();
})
}
function setDefaultDataOfWorkbench() {
// Generic
$("#workbench-label").val("Default");
$("#workbench-minimum-police").val(0);
$("#workbench-radius").val(5);
// Coordinates
$("#workbench-coords-x").val("");
$("#workbench-coords-y").val("");
$("#workbench-coords-z").val("");
// Other
let workbenchModal = $("#workbench-modal");
workbenchModal.data("animations", [defaultWorkbenchAnimData]);
workbenchModal.data("blipData", getDefaultBlipCustomizationForWorkbenches());
workbenchModal.data("markerData", getDefaultMarkerCustomization());
workbenchModal.data("allowedJobs", null);
workbenchModal.data("objectData", getDefaultObjectCustomizationForWorkbenches());
// Empty craftings
$("#workbench-craftings-list").empty();
}
$("#new-workbench-btn").click(function() {
let workbenchModal = $("#workbench-modal");
// Converts from edit modal to create modal
workbenchModal.data("action", "create");
$("#delete-workbench-btn").hide();
$("#save-workbench-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfWorkbench();
workbenchModal.modal("show");
})
$("#workbench-animations-btn").click(async function() {
let workbenchModal = $("#workbench-modal");
let oldAnimations = workbenchModal.data("animations");
let newAnimations = await animationsDialog(oldAnimations);
workbenchModal.data("animations", newAnimations);
})
$("#workbench-customize-blip-btn").click(async function() {
let workbenchModal = $("#workbench-modal");
let oldBlipData = workbenchModal.data("blipData");
let newBlipData = await blipDialog(oldBlipData);
workbenchModal.data("blipData", newBlipData);
})
$("#workbench-customize-marker-btn").click(async function() {
let workbenchModal = $("#workbench-modal");
let oldMarkerData = workbenchModal.data("markerData");
let newMarkerData = await markerDialog(oldMarkerData);
workbenchModal.data("markerData", newMarkerData);
})
$("#workbench-allowed-jobs-btn").click(async function() {
let workbenchModal = $("#workbench-modal");
let oldAllowedJobs = workbenchModal.data("allowedJobs");
let newAllowedJobs = await jobsDialog(oldAllowedJobs);
workbenchModal.data("allowedJobs", newAllowedJobs);
})
$("#workbench-current-coords-btn").click(async function() {
const coords = await getCurrentCoords();
$("#workbench-coords-x").val(coords.x);
$("#workbench-coords-y").val(coords.y);
$("#workbench-coords-z").val(coords.z);
})
$("#workbench-customize-object-btn").click(async function() {
let workbenchModal = $("#workbench-modal");
let oldObjectData = workbenchModal.data("objectData");
let newObjectData = await objectCustomizationDialog(oldObjectData);
workbenchModal.data("objectData", newObjectData);
});
async function addRequiredItemToCrafting(craftingDiv, requiredItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 required-item justify-content-center">
<button type="button" class="btn-close delete-required-item-btn me-3" ></button>
<select class="form-select required-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control required-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating">
<input type="number" min=0 class="form-control required-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-check my-auto fs-4 ms-1">
<input class="form-check-input required-item-lose-on-use-checkbox" type="checkbox" value="">
<label class="form-check-label">${getLocalizedText("menu:lose_on_use")}</label>
</div>
</div>
`);
itemDiv.find(".delete-required-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".required-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".required-item-name").val(objectName);
}).tooltip();
if(requiredItem) {
itemDiv.find(".required-item-type").val(requiredItem.type);
itemDiv.find(".required-item-name").val(requiredItem.name);
itemDiv.find(".required-item-min-quantity").val(requiredItem.minQuantity);
itemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", requiredItem.loseOnUse);
}
craftingDiv.find(".required-items-list").append(itemDiv);
}
async function addRewardItemToCrafting(craftingDiv, rewardItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 reward-item justify-content-center">
<button type="button" class="btn-close delete-reward-item-btn me-3" ></button>
<select class="form-select reward-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control reward-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating col-2">
<input type="number" min="1" class="form-control reward-item-quantity" placeholder="${getLocalizedText("menu:quantity")}" required>
<label>${getLocalizedText("menu:quantity")}</label>
</div>
</div>
`);
itemDiv.find(".delete-reward-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".reward-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".reward-item-name").val(objectName);
}).tooltip();
if(rewardItem) {
itemDiv.find(".reward-item-type").val(rewardItem.type);
itemDiv.find(".reward-item-name").val(rewardItem.name);
itemDiv.find(".reward-item-quantity").val(rewardItem.quantity);
}
craftingDiv.find(".reward-items-list").append(itemDiv);
}
function addCraftingToWorkbench(craftingData) {
let craftingDiv = $(`
<div class="mb-4 crafting">
<div class="col-12 d-inline-block">
<button type="button" class="btn btn-danger float-end col-auto delete-crafting-btn"><i class="bi bi-trash-fill"></i></button>
</div>
<div class="form-floating crafting-label-div col-3 mx-auto my-3" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:crafting_label_description") }">
<input type="text" class="form-control crafting-label" placeholder="Label">
<label>${ getLocalizedText("menu:crafting_label") }</label>
</div>
<p class="text-center fs-4">${getLocalizedText("menu:required_items_list")}</p>
<div class="required-items-list">
</div>
<button class="btn btn-secondary add-required-item-btn" type="button">${getLocalizedText("menu:add_required_item")}</button>
<p class="text-center fs-4">${getLocalizedText("menu:reward_items_list")}</p>
<div class="reward-items-list">
</div>
<button class="btn btn-secondary add-reward-item-btn" type="button">${getLocalizedText("menu:add_reward_item")}</button>
<hr>
</div>
`);
craftingDiv.find(".crafting-label-div").tooltip();
craftingDiv.find(".add-required-item-btn").click(function() {
addRequiredItemToCrafting(craftingDiv);
});
craftingDiv.find(".add-reward-item-btn").click(function() {
addRewardItemToCrafting(craftingDiv);
});
craftingDiv.find(".delete-crafting-btn").click(function() {
craftingDiv.remove();
});
if(craftingData) {
for(let requiredItem of craftingData.requiredItems) {
addRequiredItemToCrafting(craftingDiv, requiredItem);
}
for(let rewardItem of craftingData.rewardItems) {
addRewardItemToCrafting(craftingDiv, rewardItem);
}
craftingDiv.find(".crafting-label").val(craftingData.label);
} else {
addRequiredItemToCrafting(craftingDiv);
addRewardItemToCrafting(craftingDiv);
}
$("#workbench-craftings-list").append(craftingDiv);
}
$("#workbench-add-crafting-btn").click(async function() {
addCraftingToWorkbench();
});
function getAllCraftingsFromWorkbench() {
let craftings = [];
$("#workbench-craftings-list").find(".crafting").each(function() {
let crafting = {
label: $(this).find(".crafting-label").val(),
requiredItems: [],
rewardItems: []
};
$(this).find(".required-item").each(function() {
let requiredItem = {
type: $(this).find(".required-item-type").val(),
name: $(this).find(".required-item-name").val(),
minQuantity: parseInt( $(this).find(".required-item-min-quantity").val() ),
loseOnUse: $(this).find(".required-item-lose-on-use-checkbox").prop("checked")
};
crafting.requiredItems.push(requiredItem);
});
$(this).find(".reward-item").each(function() {
let rewardItem = {
type: $(this).find(".reward-item-type").val(),
name: $(this).find(".reward-item-name").val(),
quantity: parseInt( $(this).find(".reward-item-quantity").val() )
};
crafting.rewardItems.push(rewardItem);
});
craftings.push(crafting);
});
return craftings;
}
function editWorkbench(id) {
let workbenchModal = $("#workbench-modal");
// Converts from create modal to edit modal
workbenchModal.data("action", "edit");
workbenchModal.data("workbenchId", id);
$("#delete-workbench-btn").show();
$("#save-workbench-btn").text( getLocalizedText("menu:save") );
let workbenchData = workbenches[id];
// Generic
$("#workbench-label").val(workbenchData.label);
$("#workbench-minimum-police").val(workbenchData.data.minimumPolice);
$("#workbench-radius").val(workbenchData.data.radius);
// Coordinates
$("#workbench-coords-x").val(workbenchData.data.coords.x);
$("#workbench-coords-y").val(workbenchData.data.coords.y);
$("#workbench-coords-z").val(workbenchData.data.coords.z);
// Craftings
$("#workbench-craftings-list").empty();
for(let craftingData of workbenchData.data.craftings) {
addCraftingToWorkbench(craftingData);
}
workbenchModal.data("animations", workbenchData.data.animations);
workbenchModal.data("blipData", workbenchData.data.blipData);
workbenchModal.data("markerData", workbenchData.data.markerData);
workbenchModal.data("allowedJobs", workbenchData.data.allowedJobs || null);
workbenchModal.data("objectData", workbenchData.data.objectData);
workbenchModal.modal("show");
}
$("#workbench-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let workbenchModal = $("#workbench-modal");
let action = workbenchModal.data("action");
let workbenchData = {
label: $("#workbench-label").val(),
data: {
minimumPolice: parseInt( $("#workbench-minimum-police").val() ),
radius: parseFloat( $("#workbench-radius").val() ),
animations: workbenchModal.data("animations"),
blipData: workbenchModal.data("blipData") || [getDefaultBlipCustomization()],
markerData: workbenchModal.data("markerData") || [getDefaultMarkerCustomization()],
objectData: workbenchModal.data("objectData") || [getDefaultObjectCustomization()],
allowedJobs: workbenchModal.data("allowedJobs" || null),
coords: {
x: parseFloat( $("#workbench-coords-x").val() ),
y: parseFloat( $("#workbench-coords-y").val() ),
z: parseFloat( $("#workbench-coords-z").val() ),
},
craftings: getAllCraftingsFromWorkbench()
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createWorkbench`, JSON.stringify(workbenchData), function(isSuccessful) {
if(isSuccessful) {
workbenchModal.modal("hide");
loadWorkbenches();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateWorkbench`, JSON.stringify({workbenchId: workbenchModal.data("workbenchId"), workbenchData: workbenchData}), function(isSuccessful) {
if(isSuccessful) {
workbenchModal.modal("hide");
loadWorkbenches();
}
});
break;
}
}
})
$("#delete-workbench-btn").click(function() {
let workbenchModal = $("#workbench-modal");
let workbenchId = workbenchModal.data("workbenchId");
$.post(`https://${resName}/deleteWorkbench`, JSON.stringify({workbenchId: workbenchId}), function(isSuccessful) {
if(isSuccessful) {
workbenchModal.modal("hide");
loadWorkbenches();
}
});
});
/*
███████ ██████ ██ ██ ███ ██ ██████ ██████ ██ ███████ ███████
██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██
█████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ █████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██████ ██████ ██ ████ ██████ ██ ██ ██ ███████ ███████
*/
let foundriesDatatable = $("#foundries-container").DataTable( {
"lengthMenu": [10, 15, 20],
"createdRow": function ( row, data, index ) {
$(row).addClass("clickable");
$(row).click(function() {
let id = parseInt( data[0] );
editFoundry(id);
})
},
});
let foundries = {};
function loadFoundries() {
$.post(`https://${resName}/getAllFoundries`, {}, async function(rawFoundries) {
// Manually create the table to avoid incompatibilities due table indexing
foundries = {};
for(const[k, foundryData] of Object.entries(rawFoundries)) {
foundries[foundryData.id] = foundryData;
}
foundriesDatatable.clear();
for(const[id, foundryData] of Object.entries(foundries)) {
foundriesDatatable.row.add([
id,
foundryData.label,
]);
}
foundriesDatatable.draw();
})
}
function setDefaultDataOfFoundry() {
// Generic
$("#foundry-label").val("Default");
$("#foundry-minimum-police").val(0);
$("#foundry-radius").val(5);
$("#foundry-explode-on-failure-checkbox").prop("checked", false).change();
$("#foundry-alert-police-on-failure-checkbox").prop("checked", false).change();
// Coordinates
$("#foundry-coords-x").val("");
$("#foundry-coords-y").val("");
$("#foundry-coords-z").val("");
// Other
let foundryModal = $("#foundry-modal");
foundryModal.data("blipData", getDefaultBlipCustomizationForFoundries());
foundryModal.data("markerData", getDefaultMarkerCustomization());
foundryModal.data("allowedJobs", null);
foundryModal.data("objectData", getDefaultObjectCustomization());
}
$("#new-foundry-btn").click(function() {
let foundryModal = $("#foundry-modal");
// Converts from edit modal to create modal
foundryModal.data("action", "create");
$("#delete-foundry-btn").hide();
$("#save-foundry-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfFoundry();
foundryModal.modal("show");
});
$("#foundry-customize-blip-btn").click(async function() {
let foundryModal = $("#foundry-modal");
let oldBlipData = foundryModal.data("blipData");
let newBlipData = await blipDialog(oldBlipData);
foundryModal.data("blipData", newBlipData);
});
$("#foundry-customize-marker-btn").click(async function() {
let foundryModal = $("#foundry-modal");
let oldMarkerData = foundryModal.data("markerData");
let newMarkerData = await markerDialog(oldMarkerData);
foundryModal.data("markerData", newMarkerData);
});
$("#foundry-customize-object-btn").click(async function() {
let foundryModal = $("#foundry-modal");
let oldObjectData = foundryModal.data("objectData");
let newObjectData = await objectCustomizationDialog(oldObjectData);
foundryModal.data("objectData", newObjectData);
});
$("#foundry-allowed-jobs-btn").click(async function() {
let foundryModal = $("#foundry-modal");
let oldAllowedJobs = foundryModal.data("allowedJobs");
let newAllowedJobs = await jobsDialog(oldAllowedJobs);
foundryModal.data("allowedJobs", newAllowedJobs);
});
$("#foundry-current-coords-btn").click(async function() {
const coords = await getCurrentCoords();
$("#foundry-coords-x").val(coords.x);
$("#foundry-coords-y").val(coords.y);
$("#foundry-coords-z").val(coords.z);
});
async function chooseAllowedFormulas() {
let foundryModal = $("#foundry-modal");
let oldAllowedFormulas = foundryModal.data("allowedFormulas");
let newAllowedFormulas = await formulasDialog(oldAllowedFormulas);
foundryModal.data("allowedFormulas", newAllowedFormulas);
}
$("#foundry-allowed-formulas-btn").click(async function() {
chooseAllowedFormulas()
});
$("#foundry-explode-on-failure-checkbox").change(function() {
const isEnabled = $(this).prop("checked");
$("#foundry-seconds-before-explosion-div").toggle(isEnabled);
$("#foundry-seconds-before-explosion").prop("required", isEnabled);
if(!isEnabled) {
$("#foundry-seconds-before-explosion").val(0);
}
})
$("#foundry-alert-police-on-failure-checkbox").change(function() {
const isEnabled = $(this).prop("checked");
$("#foundry-alert-police-probability-div").toggle(isEnabled);
$("#foundry-alert-police-probability").prop("required", isEnabled);
if(!isEnabled) {
$("#foundry-alert-police-probability").val(0);
}
})
function editFoundry(id) {
let foundryModal = $("#foundry-modal");
// Converts from create modal to edit modal
foundryModal.data("action", "edit");
foundryModal.data("foundryId", id);
$("#delete-foundry-btn").show();
$("#save-foundry-btn").text( getLocalizedText("menu:save") );
let foundryData = foundries[id];
// Generic
$("#foundry-label").val(foundryData.label);
$("#foundry-minimum-police").val(foundryData.data.minimumPolice);
$("#foundry-radius").val(foundryData.data.radius);
$("#foundry-explode-on-failure-checkbox").prop("checked", foundryData.data.explodeOnFailure).change();
$("#foundry-seconds-before-explosion").val(foundryData.data.secondsBeforeExplosion);
$("#foundry-alert-police-on-failure-checkbox").prop("checked", foundryData.data.alertPoliceOnFailure).change();
$("#foundry-alert-police-probability").val(foundryData.data.alertPoliceProbability);
// Coordinates
$("#foundry-coords-x").val(foundryData.data.coords.x);
$("#foundry-coords-y").val(foundryData.data.coords.y);
$("#foundry-coords-z").val(foundryData.data.coords.z);
foundryModal.data("blipData", foundryData.data.blipData);
foundryModal.data("markerData", foundryData.data.markerData);
foundryModal.data("allowedJobs", foundryData.data.allowedJobs || null);
foundryModal.data("allowedFormulas", foundryData.data.allowedFormulas);
foundryModal.data("objectData", foundryData.data.objectData);
foundryModal.modal("show");
}
$("#foundry-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let foundryModal = $("#foundry-modal");
let action = foundryModal.data("action");
let foundryData = {
label: $("#foundry-label").val(),
data: {
minimumPolice: parseInt( $("#foundry-minimum-police").val() ),
radius: parseFloat( $("#foundry-radius").val() ),
explodeOnFailure: $("#foundry-explode-on-failure-checkbox").prop("checked"),
secondsBeforeExplosion: parseInt( $("#foundry-seconds-before-explosion").val() ),
alertPoliceOnFailure: $("#foundry-alert-police-on-failure-checkbox").prop("checked"),
alertPoliceProbability: parseInt( $("#foundry-alert-police-probability").val() ),
blipData: foundryModal.data("blipData") || [getDefaultBlipCustomization()],
markerData: foundryModal.data("markerData") || [getDefaultMarkerCustomization()],
objectData: foundryModal.data("objectData") || [getDefaultObjectCustomization()],
allowedJobs: foundryModal.data("allowedJobs" || null),
allowedFormulas: foundryModal.data("allowedFormulas"),
coords: {
x: parseFloat( $("#foundry-coords-x").val() ),
y: parseFloat( $("#foundry-coords-y").val() ),
z: parseFloat( $("#foundry-coords-z").val() ),
},
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createFoundry`, JSON.stringify(foundryData), function(isSuccessful) {
if(isSuccessful) {
foundryModal.modal("hide");
loadFoundries();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateFoundry`, JSON.stringify({foundryId: foundryModal.data("foundryId"), foundryData: foundryData}), function(isSuccessful) {
if(isSuccessful) {
foundryModal.modal("hide");
loadFoundries();
}
});
break;
}
}
})
$("#delete-foundry-btn").click(function() {
let foundryModal = $("#foundry-modal");
let foundryId = foundryModal.data("foundryId");
$.post(`https://${resName}/deleteFoundry`, JSON.stringify({foundryId: foundryId}), function(isSuccessful) {
if(isSuccessful) {
foundryModal.modal("hide");
loadFoundries();
}
});
});
/*
███████ ██████ ██████ ███ ███ ██ ██ ██ █████ ███████
██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██
█████ ██ ██ ██████ ██ ████ ██ ██ ██ ██ ███████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██████ ██ ██ ██ ██ ██████ ███████ ██ ██ ███████
*/
let formulas = {};
async function loadFormulas() {
$.post(`https://${resName}/getAllFormulas`, {}, async function(rawFormulas) {
// Manually create the table to avoid incompatibilities due table indexing
formulas = {};
for(const[k, formulaData] of Object.entries(rawFormulas)) {
formulas[formulaData.id] = formulaData;
}
})
}
$("#formula-produces-smoke-checkbox").change(function() {
const isEnabled = $(this).prop("checked");
$("#formula-smoke-color").toggle(isEnabled);
});
function setDefaultDataOfFormula() {
// Generic
$("#formula-label").val("Default");
$("#formula-probability-of-failure").val(0);
$("#formula-produces-smoke-checkbox").prop("checked", false).change();
$("#formula-smoke-color").val("#FF0000");
// Required items
$("#formula-required-items-list").empty();
// Reward items
$("#formula-reward-items-list").empty();
$("#formula-reward-min-objects-amount").val(1);
$("#formula-reward-max-objects-amount").val(1);
// Other
let formulaModal = $("#formula-modal");
formulaModal.data("animations", [defaultFormulaAnimData]);
}
$("#formula-animations-btn").click(async function() {
let formulaModal = $("#formula-modal");
const oldAnimations = formulaModal.data("animations");
const newAnimations = await animationsDialog(oldAnimations);
formulaModal.data("animations", newAnimations);
});
async function addRequiredItemToFormula(requiredItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 required-item justify-content-center">
<button type="button" class="btn-close delete-required-item-btn me-3" ></button>
<select class="form-select required-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control required-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating">
<input type="number" min=0 class="form-control required-item-quantity" placeholder="${getLocalizedText("menu:quantity")}" required>
<label>${getLocalizedText("menu:quantity")}</label>
</div>
<div class="form-check my-auto fs-4 ms-1">
<input class="form-check-input required-item-lose-on-use-checkbox" type="checkbox" value="">
<label class="form-check-label">${getLocalizedText("menu:lose_on_use")}</label>
</div>
</div>
`);
itemDiv.find(".delete-required-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".required-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".required-item-name").val(objectName);
}).tooltip();
if(requiredItem) {
itemDiv.find(".required-item-type").val(requiredItem.type);
itemDiv.find(".required-item-name").val(requiredItem.name);
itemDiv.find(".required-item-quantity").val(requiredItem.quantity);
itemDiv.find(".required-item-lose-on-use-checkbox").prop("checked", requiredItem.loseOnUse);
}
$("#formula-required-items-list").append(itemDiv);
}
$("#formula-add-required-item-btn").click(function() {
addRequiredItemToFormula();
});
async function addRewardItemToFormula(rewardItem) {
let itemDiv = $(`
<div class="row g-2 row-cols-auto align-items-center text-body my-2 reward-item justify-content-center">
<button type="button" class="btn-close delete-reward-item-btn me-3" ></button>
<select class="form-select reward-item-type" style="width: auto;">
<option selected value="item">${getLocalizedText("menu:item")}</option>
<option value="account">${getLocalizedText("menu:account")}</option>
${await getFramework() == "ESX" ? `<option value="weapon">${getLocalizedText("menu:weapon")}</option>` : ""}
</select>
<div class="form-floating">
<input type="text" class="form-control reward-item-name" placeholder="Name" required>
<label>${ getLocalizedText("menu:object_name") }</label>
</div>
<button type="button" class="btn btn-secondary col-auto choose-item-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${ getLocalizedText("menu:choose") }"><i class="bi bi-list-ul"></i></button>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-min-quantity" placeholder="${getLocalizedText("menu:min_quantity")}" required>
<label>${getLocalizedText("menu:min_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" min=0 class="form-control reward-item-max-quantity" placeholder="${getLocalizedText("menu:max_quantity")}" required>
<label>${getLocalizedText("menu:max_quantity")}</label>
</div>
<div class="form-floating col-2">
<input type="number" class="form-control reward-item-chances" placeholder="${getLocalizedText("menu:probability")}" required>
<label>${getLocalizedText("menu:probability")}</label>
</div>
</div>
`);
itemDiv.find(".delete-reward-item-btn").click(function() {
itemDiv.remove();
});
itemDiv.find(".choose-item-btn").click(async function() {
let objectType = itemDiv.find(".reward-item-type").val();
let objectName = await objectDialog(objectType);
itemDiv.find(".reward-item-name").val(objectName);
}).tooltip();
if(rewardItem) {
itemDiv.find(".reward-item-type").val(rewardItem.type);
itemDiv.find(".reward-item-name").val(rewardItem.name);
itemDiv.find(".reward-item-min-quantity").val(rewardItem.minQuantity);
itemDiv.find(".reward-item-max-quantity").val(rewardItem.maxQuantity);
itemDiv.find(".reward-item-chances").val(rewardItem.chances);
}
$("#formula-reward-items-list").append(itemDiv);
}
$("#formula-add-reward-item-btn").click(function() {
addRewardItemToFormula();
});
function getRewardItemsFromformula() {
let rewardItems = [];
$("#formula-reward-items-list").find(".reward-item").each(function() {
let rewardItem = {
type: $(this).find(".reward-item-type").val(),
name: $(this).find(".reward-item-name").val(),
minQuantity: parseInt( $(this).find(".reward-item-min-quantity").val() ),
maxQuantity: parseInt( $(this).find(".reward-item-max-quantity").val() ),
chances: parseInt( $(this).find(".reward-item-chances").val() )
}
rewardItems.push(rewardItem);
});
return rewardItems;
}
function getRequiredItemsFromformula() {
let requiredItems = [];
$("#formula-required-items-list").find(".required-item").each(function() {
let requiredItem = {
type: $(this).find(".required-item-type").val(),
name: $(this).find(".required-item-name").val(),
quantity: parseInt( $(this).find(".required-item-quantity").val() ),
loseOnUse: $(this).find(".required-item-lose-on-use-checkbox").prop("checked")
}
requiredItems.push(requiredItem);
});
return requiredItems;
}
$("#new-formula-btn").click(function() {
let formulaModal = $("#formula-modal");
// Converts from edit modal to create modal
formulaModal.data("action", "create");
$("#delete-formula-btn").hide();
$("#save-formula-btn").text( getLocalizedText("menu:create") );
setDefaultDataOfFormula();
formulaModal.modal("show");
});
function editFormula(id) {
let formulaModal = $("#formula-modal");
// Converts from create modal to edit modal
formulaModal.data("action", "edit");
formulaModal.data("formulaId", id);
$("#delete-formula-btn").show();
$("#save-formula-btn").text( getLocalizedText("menu:save") );
let formulaData = formulas[id];
// Generic
$("#formula-label").val(formulaData.label);
$("#formula-probability-of-failure").val(formulaData.data.probabilityOfFailure);
$("#formula-produces-smoke-checkbox").prop("checked", formulaData.data.producesSmoke);
$("#formula-smoke-color").val( rgbToHex(formulaData.data.smokeColor.r, formulaData.data.smokeColor.g, formulaData.data.smokeColor.b) );
$("#formula-reward-min-objects-amount").val(formulaData.data.minObjectsAmount);
$("#formula-reward-max-objects-amount").val(formulaData.data.maxObjectsAmount);
// Required items
$("#formula-required-items-list").empty();
if(formulaData.data.requiredItems) {
for(let requiredItem of formulaData.data.requiredItems) {
addRequiredItemToFormula(requiredItem);
}
}
// Reward items
$("#formula-reward-items-list").empty();
if(formulaData.data.rewardItems) {
for(let rewardItem of formulaData.data.rewardItems) {
addRewardItemToFormula(rewardItem);
}
}
// Anims
formulaModal.data("animations", formulaData.data.animations);
formulaModal.modal("show");
}
$("#formula-form").submit(function(event) {
if(isThereAnyErrorInForm(event)) return;
let formulaModal = $("#formula-modal");
let action = formulaModal.data("action");
let formulaData = {
label: $("#formula-label").val(),
data: {
animations: formulaModal.data("animations"),
probabilityOfFailure: parseInt( $("#formula-probability-of-failure").val() ),
producesSmoke: $("#formula-produces-smoke-checkbox").prop("checked"),
smokeColor: hexToRgb( $("#formula-smoke-color").val() ),
requiredItems: getRequiredItemsFromformula(),
rewardItems: getRewardItemsFromformula(),
minObjectsAmount: parseInt( $("#formula-reward-min-objects-amount").val() ),
maxObjectsAmount: parseInt( $("#formula-reward-max-objects-amount").val() ),
}
}
switch(action) {
case "create": {
$.post(`https://${resName}/createFormula`, JSON.stringify(formulaData), function(isSuccessful) {
if(isSuccessful) {
formulaModal.modal("hide");
loadFormulas();
chooseAllowedFormulas();
}
});
break;
}
case "edit": {
$.post(`https://${resName}/updateFormula`, JSON.stringify({formulaId: formulaModal.data("formulaId"), formulaData: formulaData}), function(isSuccessful) {
if(isSuccessful) {
formulaModal.modal("hide");
loadFormulas();
chooseAllowedFormulas();
}
});
break;
}
}
})
$("#delete-formula-btn").click(function() {
let formulaModal = $("#formula-modal");
let formulaId = formulaModal.data("formulaId");
$.post(`https://${resName}/deleteFormula`, JSON.stringify({formulaId: formulaId}), function(isSuccessful) {
if(isSuccessful) {
formulaModal.modal("hide");
loadFormulas();
chooseAllowedFormulas();
}
});
});